Расширение Visual Studio — получить ссылку на текущий выбранный элемент в истории Git

Мне удалось добавить пользовательскую кнопку в контекстное меню истории Git благодаря предложенной помощи здесь.

Я продолжаю работать с тем же расширением и снова застрял. После нажатия кнопки, которую я добавил в контекстное меню, мне нужно получить ссылку на фиксацию, выбранную при нажатии. Идея состоит в том, что затем мне нужно получить изменения кода, связанные с этой фиксацией.

введите здесь описание изображения

Мне удалось получить ссылку на ActiveWindow с заголовком History - master. Что заставляет меня поверить, что я близко. Однако ActiveWindow.Selection имеет значение null. Поэтому я не уверен, куда идти дальше, чтобы получить выбранный коммит.

Это то, что я использую для получения свойства ActiveWindow.

EnvDTE80.DTE2 dte = ServiceProvider.GetService(typeof(DTE)) as EnvDTE80.DTE2;

Кто-нибудь знает, как получить ссылку на выбранный коммит? Затем использовать это, чтобы получить информацию о коммите, включая измененные файлы?

Мой вопрос похож на этот, но для Git вместо TFS.

Заранее спасибо за помощь!


person Chris    schedule 21.06.2020    source источник
comment
Я пытаюсь помочь, не запуская никакого кода, но когда у вас есть объект dte, вы видите на нем свойство коллекции ToolWindows? Если да, указано ли окно Git History?   -  person Jazimov    schedule 21.06.2020
comment
У него есть свойство ToolWindows, но это не коллекция. У него есть метод GetToolWindow, который принимает имя. Было бы многообещающе, если бы я знал правильное имя для передачи. Все еще ищу.   -  person Chris    schedule 22.06.2020
comment
документы кажутся предлагают передать заголовок в метод GetToolWindow. Я пробовал это, но только что получил ноль. EnvDTE80.DTE2 dte = ServiceProvider.GetService(typeof(DTE)) as EnvDTE80.DTE2; object toolWindow = dte.ToolWindows.GetToolWindow(dte.ActiveWindow.Caption);   -  person Chris    schedule 22.06.2020
comment
После дальнейшего изучения ToolWindows, похоже, не включает Git. Если вы можете получить дескриптор главного окна «История», попробуйте получить дескрипторы его дочерних элементов управления, используя метод Джеймса МакКэффри здесь (jamesmccaffrey.wordpress.com/2013/02/03/). Вы можете преобразовать каждый дескриптор в элемент управления с помощью Control.FromHandle(controlIntPtr); и посмотреть, что это за элемент управления. Как только вы найдете элемент управления, содержащий элементы Git, вы сможете использовать свойства этого элемента управления для получения подробной информации о выбранном элементе.   -  person Jazimov    schedule 22.06.2020
comment
Спасибо @Jazimov. Является ли свойство .HWnd тем, о котором вы говорите, для получения дескриптора окна? Если это так, то в моем тестировании он всегда возвращает 0. Есть ли другой способ получить правильный дескриптор? int windowHandle = dte.ActiveWindow.HWnd;   -  person Chris    schedule 22.06.2020


Ответы (1)


Это заняло целую вечность, но мне наконец удалось добраться до выбранного коммита. Это включает в себя отражение, потому что многие типы, используемые в расширении git, являются внутренними. Должен быть лучший способ сделать это.

IGitCommit, который я могу получить, не содержит изменений для заполненной фиксации. Надеюсь, получить изменения, которые являются частью коммита, не так сложно.

    private IGitCommit GetSelectedCommit()
    {
        ThreadHelper.ThrowIfNotOnUIThread();
        EnvDTE80.DTE2 dte = ServiceProvider.GetService(typeof(DTE)) as EnvDTE80.DTE2;
        // GUID found via dte.ActiveWindow.ObjectKind
        Guid gitHistoryWindowGuid = new Guid("116D2292-E37D-41CD-A077-EBACAC4C8CC4");
        IVsUIShell vsUIShell = (IVsUIShell)Package.GetGlobalService(typeof(SVsUIShell));
        int toolWindowReturn = vsUIShell.FindToolWindow((uint)__VSFINDTOOLWIN.FTW_fFrameOnly, ref gitHistoryWindowGuid, out IVsWindowFrame vsWindowFrame);
        WindowFrame windowFrame = (WindowFrame)vsWindowFrame;
        ToolWindowView toolWindowView = (ToolWindowView)windowFrame.FrameView;
        // panel is of innaccessible type Microsoft.VisualStudio.Platform.WindowManagement.WindowFrame.ContentHostingPanel
        // so use base System.Windows.Controls.Grid
        Grid contentHostingPanel = (Grid)toolWindowView.Content;
        // Type Microsoft.VisualStudio.Platform.WindowManagement.Controls.GenericPaneContentPresenter is internal
        // so use base ContentPresenter
        ContentPresenter genericPaneContentPresenter = contentHostingPanel.Children[1] as ContentPresenter;
        // Microsoft.VisualStudio.TeamFoundation.ToolWindowBase.ToolWindowBaseProxy is innaccessible
        // so use base ContentPresenter
        ContentPresenter toolWindowBaseProxy = (ContentPresenter)genericPaneContentPresenter.Content;
        // Is of type Microsoft.TeamFoundation.Git.Controls.History.HistoryView, 
        // but this class is defined as internal so using base UserControl.
        UserControl historyView = (UserControl)toolWindowBaseProxy.Content;
        // Is of type Microsoft.TeamFoundation.Git.Controls.History.HistoryViewModel, 
        // but this class is defined as internal so using base Microsoft.TeamFoundation.MVVM.ViewModelBase.
        ViewModelBase historyViewModel = (ViewModelBase)historyView.DataContext;
        // Use reflection to get at properties of internal type HistoryViewModel and ObservableCollection<GitHistoryItem>
        object gitHistoryItem = ((IList)historyViewModel.GetType().GetProperty("SelectedItems").GetValue(historyViewModel, null))[0];
        IGitCommit gitCommit = (IGitCommit)gitHistoryItem.GetType().GetProperty("Commit").GetValue(gitHistoryItem, null);
        return gitCommit;
    }
person Chris    schedule 23.06.2020