<|start_filename|>GitDiffMargin.Shared/Commands/GitDiffMarginCommandHandler`1.cs<|end_filename|>
﻿#if !LEGACY_COMMANDS

namespace GitDiffMargin.Commands
{
    using System;
    using Microsoft.VisualStudio.OLE.Interop;
    using Microsoft.VisualStudio.Text.Editor.Commanding;

    internal abstract class GitDiffMarginCommandHandler<T> : ShimCommandHandler<T>
        where T : EditorCommandArgs
    {
        protected GitDiffMarginCommandHandler(GitDiffMarginCommand commandId)
            : base(new Guid(GitDiffMarginCommandHandler.GitDiffMarginCommandSet), (uint)commandId)
        {
        }

        protected override IOleCommandTarget GetCommandTarget(T args)
            => args.TextView.Properties.GetProperty<GitDiffMarginCommandHandler>(typeof(GitDiffMarginCommandHandler));
    }
}

#endif


<|start_filename|>GitDiffMargin.Shim/TypeForwarders.cs<|end_filename|>
﻿using System.Runtime.CompilerServices;

[assembly: TypeForwardedTo(typeof(GitDiffMargin.GitDiffMarginPackage))]


<|start_filename|>GitDiffMargin/Properties/AssemblyInfo.cs<|end_filename|>
using System;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell;

[assembly: CLSCompliant(false)]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

[assembly: ProvideCodeBase(CodeBase = "$PackageFolder$\\GalaSoft.MvvmLight.dll")]
[assembly: ProvideCodeBase(CodeBase = "$PackageFolder$\\GalaSoft.MvvmLight.Extras.dll")]
[assembly: ProvideCodeBase(CodeBase = "$PackageFolder$\\GalaSoft.MvvmLight.Platform.dll")]
[assembly: ProvideCodeBase(CodeBase = "$PackageFolder$\\LibGit2Sharp.dll")]
[assembly: ProvideCodeBase(CodeBase = "$PackageFolder$\\CommonServiceLocator.dll")]
[assembly: ProvideCodeBase(CodeBase = "$PackageFolder$\\System.Windows.Interactivity.dll")]


<|start_filename|>GitDiffMargin.Extension/Properties/AssemblyInfo.cs<|end_filename|>
using Microsoft.VisualStudio.Shell;
using System.Runtime.InteropServices;

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("e4701f35-8030-418e-8e8c-6ae72e229138")]

[assembly: ProvideCodeBase(CodeBase = "$PackageFolder$\\GalaSoft.MvvmLight.dll")]
[assembly: ProvideCodeBase(CodeBase = "$PackageFolder$\\GalaSoft.MvvmLight.Extras.dll")]
[assembly: ProvideCodeBase(CodeBase = "$PackageFolder$\\GalaSoft.MvvmLight.Platform.dll")]
[assembly: ProvideCodeBase(CodeBase = "$PackageFolder$\\GitDiffMargin.Shim.dll")]
[assembly: ProvideCodeBase(CodeBase = "$PackageFolder$\\LibGit2Sharp.dll")]
[assembly: ProvideCodeBase(CodeBase = "$PackageFolder$\\CommonServiceLocator.dll")]
[assembly: ProvideCodeBase(CodeBase = "$PackageFolder$\\System.Windows.Interactivity.dll")]


<|start_filename|>GitDiffMargin.Shared/Git/HunkRangeInfo.cs<|end_filename|>
#region using

using System.Collections.Generic;
using System.Linq;

#endregion

namespace GitDiffMargin.Git
{
    public class HunkRangeInfo
    {
        private List<string> DiffLines { get; set; }

        public HunkRangeInfo(HunkRange originaleHunkRange, HunkRange newHunkRange, IEnumerable<string> diffLines)
            : this(originaleHunkRange, newHunkRange, diffLines, false)
        {
        }

        public HunkRangeInfo(HunkRange originaleHunkRange, HunkRange newHunkRange, IEnumerable<string> diffLines, bool suppressRollback)
        {
            OriginalHunkRange = originaleHunkRange;
            NewHunkRange = newHunkRange;
            DiffLines = diffLines.ToList();
            SuppressRollback = suppressRollback;

            IsAddition = DiffLines.All(s => s.StartsWith("+") || s.StartsWith("\\") || string.IsNullOrWhiteSpace(s));
            IsDeletion = DiffLines.All(s => s.StartsWith("-") || s.StartsWith("\\") || string.IsNullOrWhiteSpace(s));
            IsModification = !IsAddition && !IsDeletion;

            if (IsDeletion || IsModification)
            {
                OriginalText = DiffLines.Where(s => s.StartsWith("-")).Select(s => s.Remove(0, 1).TrimEnd('\n').TrimEnd('\r')).ToList();
            }
        }

        public HunkRange OriginalHunkRange { get; private set; }
        public HunkRange NewHunkRange { get; private set; }
        public List<string> OriginalText { get; private set; }
        public bool SuppressRollback { get; private set; }

        public bool IsAddition { get; private set; }
        public bool IsModification { get; private set; }
        public bool IsDeletion { get; private set; }
    }
}

<|start_filename|>GitDiffMargin.Shared/LegacyCommands/LegacyCommandHandlerTextViewCreationListener.cs<|end_filename|>
﻿#if LEGACY_COMMANDS

namespace GitDiffMargin.LegacyCommands
{
    using System.ComponentModel.Composition;
    using Microsoft.VisualStudio.Editor;
    using Microsoft.VisualStudio.Shell;
    using Microsoft.VisualStudio.Text.Editor;
    using Microsoft.VisualStudio.TextManager.Interop;
    using Microsoft.VisualStudio.Utilities;

    [Export(typeof(IVsTextViewCreationListener))]
    [ContentType("text")]
    [TextViewRole(PredefinedTextViewRoles.Editable)]
    internal class LegacyCommandHandlerTextViewCreationListener : IVsTextViewCreationListener
    {
        private readonly SVsServiceProvider _serviceProvider;
        private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService;

        [ImportingConstructor]
        public LegacyCommandHandlerTextViewCreationListener(SVsServiceProvider serviceProvider, IVsEditorAdaptersFactoryService editorAdaptersFactoryService)
        {
            _serviceProvider = serviceProvider;
            _editorAdaptersFactoryService = editorAdaptersFactoryService;
        }

        public void VsTextViewCreated(IVsTextView textViewAdapter)
        {
            ITextView textView = _editorAdaptersFactoryService.GetWpfTextView(textViewAdapter);
            if (textView == null)
                return;

            GitDiffMarginCommandHandler filter = new GitDiffMarginCommandHandler(textViewAdapter, _editorAdaptersFactoryService, textView);
            filter.Enabled = true;
            textView.Properties.AddProperty(typeof(GitDiffMarginCommandHandler), filter);
        }
    }
}

#endif


<|start_filename|>GitDiffMargin.Shared/Commands/GitDiffMarginCommandBinding.cs<|end_filename|>
﻿#if !LEGACY_COMMANDS

namespace GitDiffMargin.Commands
{
    using System.ComponentModel.Composition;
    using Microsoft.VisualStudio.Editor.Commanding;

    internal class GitDiffMarginCommandBinding
    {
#pragma warning disable CS0649 // Field 'fieldName' is never assigned to, and will always have its default value null

        [Export]
        [CommandBinding(GitDiffMarginCommandHandler.GitDiffMarginCommandSet, (uint)GitDiffMarginCommand.PreviousChange, typeof(PreviousChangeCommandArgs))]
        internal CommandBindingDefinition PreviousChangeCommandBinding;

        [Export]
        [CommandBinding(GitDiffMarginCommandHandler.GitDiffMarginCommandSet, (uint)GitDiffMarginCommand.NextChange, typeof(NextChangeCommandArgs))]
        internal CommandBindingDefinition NextChangeCommandBinding;

        [Export]
        [CommandBinding(GitDiffMarginCommandHandler.GitDiffMarginCommandSet, (uint)GitDiffMarginCommand.RollbackChange, typeof(RollbackChangeCommandArgs))]
        internal CommandBindingDefinition RollbackChangeCommandBinding;

        [Export]
        [CommandBinding(GitDiffMarginCommandHandler.GitDiffMarginCommandSet, (uint)GitDiffMarginCommand.CopyOldText, typeof(CopyOldTextCommandArgs))]
        internal CommandBindingDefinition CopyOldTextCommandBinding;

        [Export]
        [CommandBinding(GitDiffMarginCommandHandler.GitDiffMarginCommandSet, (uint)GitDiffMarginCommand.ShowPopup, typeof(ShowPopupCommandArgs))]
        internal CommandBindingDefinition ShowPopupCommandBinding;

#pragma warning restore CS0649 // Field 'fieldName' is never assigned to, and will always have its default value null
    }
}

#endif


<|start_filename|>GitDiffMargin.Shared/Commands/ShowPopupCommandHandler.cs<|end_filename|>
﻿#if !LEGACY_COMMANDS

namespace GitDiffMargin.Commands
{
    using System.ComponentModel.Composition;
    using Microsoft.VisualStudio.Commanding;
    using Microsoft.VisualStudio.Utilities;

    [Export(typeof(ICommandHandler))]
    [ContentType("text")]
    [Name(nameof(ShowPopupCommandHandler))]
    internal class ShowPopupCommandHandler : GitDiffMarginCommandHandler<ShowPopupCommandArgs>
    {
        public ShowPopupCommandHandler()
            : base(GitDiffMarginCommand.ShowPopup)
        {
        }

        public override string DisplayName => "Show Popup";
    }
}

#endif


<|start_filename|>GitDiffMargin.Shared/Commands/ShimCommandHandler.cs<|end_filename|>
﻿#if !LEGACY_COMMANDS

namespace GitDiffMargin.Commands
{
    using System;
    using Microsoft.VisualStudio;
    using Microsoft.VisualStudio.Commanding;
    using Microsoft.VisualStudio.Shell;
    using IOleCommandTarget = Microsoft.VisualStudio.OLE.Interop.IOleCommandTarget;
    using OLECMD = Microsoft.VisualStudio.OLE.Interop.OLECMD;
    using OLECMDEXECOPT = Microsoft.VisualStudio.OLE.Interop.OLECMDEXECOPT;
    using OLECMDF = Microsoft.VisualStudio.OLE.Interop.OLECMDF;

    internal abstract class ShimCommandHandler<T> : ICommandHandler<T>
        where T : CommandArgs
    {
        private readonly Guid _commandSet;
        private readonly uint _commandId;

        protected ShimCommandHandler(Guid commandSet, uint commandId)
        {
            _commandSet = commandSet;
            _commandId = commandId;
        }

        public abstract string DisplayName
        {
            get;
        }

        public virtual CommandState GetCommandState(T args)
        {
            ThreadHelper.ThrowIfNotOnUIThread();

            OLECMD[] command = { new OLECMD { cmdID = _commandId } };
            ErrorHandler.ThrowOnFailure(GetCommandTarget(args).QueryStatus(_commandSet, 1, command, IntPtr.Zero));
            if ((command[0].cmdf & (uint)OLECMDF.OLECMDF_SUPPORTED) == 0)
                return CommandState.Unspecified;
            else if ((command[0].cmdf & (uint)OLECMDF.OLECMDF_ENABLED) == 0)
                return CommandState.Unavailable;
            else
                return CommandState.Available;
        }

        public virtual bool ExecuteCommand(T args, CommandExecutionContext executionContext)
        {
            ThreadHelper.ThrowIfNotOnUIThread();

            return ErrorHandler.Succeeded(GetCommandTarget(args).Exec(_commandSet, _commandId, (uint)OLECMDEXECOPT.OLECMDEXECOPT_DODEFAULT, IntPtr.Zero, IntPtr.Zero));
        }

        protected abstract IOleCommandTarget GetCommandTarget(T args);
    }
}

#endif


<|start_filename|>GitDiffMargin.Shared/TextViewCommandFilter.cs<|end_filename|>
﻿namespace GitDiffMargin
{
    using System;
    using System.Runtime.InteropServices;
    using Microsoft.VisualStudio;
    using Microsoft.VisualStudio.TextManager.Interop;

    using IOleCommandTarget = Microsoft.VisualStudio.OLE.Interop.IOleCommandTarget;

    /// <summary>
    /// This class extends <see cref="CommandFilter"/> to support command filters for
    /// text view instances (<see cref="IVsTextView"/>).
    /// </summary>
    /// <threadsafety/>
    [ComVisible(true)]
    [CLSCompliant(false)]
    public abstract class TextViewCommandFilter : CommandFilter
    {
        /// <summary>
        /// This is the backing field for the <see cref="TextViewAdapter"/> property.
        /// </summary>
        private readonly IVsTextView _textViewAdapter;

        /// <summary>
        /// Initializes a new instance of the <see cref="TextViewCommandFilter"/> class
        /// for the specified text view.
        /// </summary>
        /// <param name="textViewAdapter">The text view this command filter should attach to.</param>
        protected TextViewCommandFilter(IVsTextView textViewAdapter)
        {
            if (textViewAdapter == null)
                throw new ArgumentNullException(nameof(textViewAdapter));

            _textViewAdapter = textViewAdapter;
        }

        /// <summary>
        /// Gets the <see cref="IVsTextView"/> which this command filter should attach to.
        /// </summary>
        protected IVsTextView TextViewAdapter
        {
            get
            {
                return _textViewAdapter;
            }
        }

        /// <inheritdoc/>
        /// <remarks>
        /// This operation is implemented by calling <see cref="IVsTextView.AddCommandFilter"/>.
        /// </remarks>
        protected override IOleCommandTarget Connect()
        {
            IOleCommandTarget next;
            ErrorHandler.ThrowOnFailure(TextViewAdapter.AddCommandFilter(this, out next));
            return next;
        }

        /// <inheritdoc/>
        /// <remarks>
        /// This operation is implemented by calling <see cref="IVsTextView.RemoveCommandFilter"/>.
        /// </remarks>
        protected override void Disconnect()
        {
            ErrorHandler.ThrowOnFailure(TextViewAdapter.RemoveCommandFilter(this));
        }
    }
}


<|start_filename|>GitDiffMargin.Shim/ModuleInitializer.cs<|end_filename|>
﻿namespace GitDiffMargin.Shim
{
    using System;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.CompilerServices;

    internal static class ModuleInitializer
    {
        [ModuleInitializer]
        internal static void Initialize()
        {
            try
            {
                var shellInternal = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(
                    assembly => assembly.GetName().Name == "Microsoft.VisualStudio.Shell.UI.Internal");
                var shellVersion = shellInternal.GetCustomAttribute<AssemblyFileVersionAttribute>()?.Version;
                if (!Version.TryParse(shellVersion, out var version))
                {
                    return;
                }

                var subFolder = version switch
                {
                    // Prior to 15.6 Preview 7, use legacy command handling
                    { Major: 15, Build: < 27428 } => "dev15",

                    // 15.6 Preview 7 includes modern command handling
                    { Major: 15, Build: >= 27428 } => "dev16",

                    // All of 16.x uses dev16
                    { Major: 16 } => "dev16",

                    // All of 17.x uses dev17
                    { Major: 17 } => "dev17",

                    _ => null,
                };

                if (subFolder is null)
                {
                    return;
                }

                var baseDirectory = Path.GetDirectoryName(typeof(ModuleInitializer).Assembly.Location);
                var implementationAssembly = Path.Combine(baseDirectory, subFolder, "GitDiffMargin.Impl.dll");
                Assembly.LoadFrom(implementationAssembly);
            }
            catch
            {
                // Avoid propagating exceptions when the assembly was only loaded for access to resources
            }
        }
    }
}


<|start_filename|>GitDiffMargin.Shared/Commands/RollbackChangeCommandHandler.cs<|end_filename|>
﻿#if !LEGACY_COMMANDS

namespace GitDiffMargin.Commands
{
    using System.ComponentModel.Composition;
    using Microsoft.VisualStudio.Commanding;
    using Microsoft.VisualStudio.Utilities;

    [Export(typeof(ICommandHandler))]
    [ContentType("text")]
    [Name(nameof(RollbackChangeCommandHandler))]
    internal class RollbackChangeCommandHandler : GitDiffMarginCommandHandler<RollbackChangeCommandArgs>
    {
        public RollbackChangeCommandHandler()
            : base(GitDiffMarginCommand.RollbackChange)
        {
        }

        public override string DisplayName => "Rollback Change";
    }
}

#endif
