From 9d06bb5189215febd12046a99fba01c6a5830507 Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Wed, 27 Nov 2024 13:32:35 +1100 Subject: [PATCH 1/9] VSCT formatting --- .../Menus.vsct | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Menus.vsct b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Menus.vsct index bd16e9b7467..86b83a46d96 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Menus.vsct +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Menus.vsct @@ -76,7 +76,7 @@ - + @@ -202,7 +202,7 @@ - + @@ -210,25 +210,24 @@ - + + + - - - - + From df2ef421b5e3336d7d93532eb312c9ce33690ee7 Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Wed, 27 Nov 2024 13:39:24 +1100 Subject: [PATCH 2/9] Formatting and comment updates --- ...isualStudio.ProjectSystem.Managed.VS.csproj | 2 +- .../FrameworkReferenceAssemblyItem.cs | 18 ++++++++---------- ...bleItemBase.DefaultContextMenuController.cs | 16 ++++------------ .../Tree/Dependencies/DependencyTreeFlags.cs | 4 ++-- .../IVsThreadedWaitDialogFactoryFactory.cs | 4 ++-- 5 files changed, 17 insertions(+), 27 deletions(-) diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Microsoft.VisualStudio.ProjectSystem.Managed.VS.csproj b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Microsoft.VisualStudio.ProjectSystem.Managed.VS.csproj index 1f1066d6e51..51cf12bc77a 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Microsoft.VisualStudio.ProjectSystem.Managed.VS.csproj +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Microsoft.VisualStudio.ProjectSystem.Managed.VS.csproj @@ -13,7 +13,7 @@ false false - + true Microsoft VisualStudio ProjectSystem for Managed Languages Project hosts that interact with VisualStudio interfaces. Microsoft VisualStudio Managed Project System VS Components diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/Implementation/FrameworkReferenceAssemblyItem.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/Implementation/FrameworkReferenceAssemblyItem.cs index dd510402133..4b4f7703ba5 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/Implementation/FrameworkReferenceAssemblyItem.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/Implementation/FrameworkReferenceAssemblyItem.cs @@ -38,33 +38,31 @@ public FrameworkReferenceAssemblyItem(string assemblyName, string? path, string? public override object? GetBrowseObject() => new BrowseObject(this); - private sealed class BrowseObject : LocalizableProperties - { - private readonly FrameworkReferenceAssemblyItem _item; - public BrowseObject(FrameworkReferenceAssemblyItem log) => _item = log; - public override string GetComponentName() => _item.AssemblyName; + private sealed class BrowseObject(FrameworkReferenceAssemblyItem item) : LocalizableProperties + { + public override string GetComponentName() => item.AssemblyName; public override string GetClassName() => VSResources.FrameworkAssemblyBrowseObjectClassName; [BrowseObjectDisplayName(nameof(VSResources.FrameworkAssemblyAssemblyNameDisplayName))] [BrowseObjectDescription(nameof(VSResources.FrameworkAssemblyAssemblyNameDescription))] - public string AssemblyName => _item.Text; + public string AssemblyName => item.Text; [BrowseObjectDisplayName(nameof(VSResources.FrameworkAssemblyPathDisplayName))] [BrowseObjectDescription(nameof(VSResources.FrameworkAssemblyPathDescription))] - public string Path => _item.Path is not null - ? System.IO.Path.GetFullPath(System.IO.Path.Combine(_item.Framework.Path, _item.Path)) + public string Path => item.Path is not null + ? System.IO.Path.GetFullPath(System.IO.Path.Combine(item.Framework.Path, item.Path)) : ""; [BrowseObjectDisplayName(nameof(VSResources.FrameworkAssemblyAssemblyVersionDisplayName))] [BrowseObjectDescription(nameof(VSResources.FrameworkAssemblyAssemblyVersionDescription))] - public string AssemblyVersion => _item.AssemblyVersion ?? ""; + public string AssemblyVersion => item.AssemblyVersion ?? ""; [BrowseObjectDisplayName(nameof(VSResources.FrameworkAssemblyFileVersionDisplayName))] [BrowseObjectDescription(nameof(VSResources.FrameworkAssemblyFileVersionDescription))] - public string FileVersion => _item.FileVersion ?? ""; + public string FileVersion => item.FileVersion ?? ""; } } } diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/RelatableItemBase.DefaultContextMenuController.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/RelatableItemBase.DefaultContextMenuController.cs index 52a8d3deafa..bdf2ac22496 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/RelatableItemBase.DefaultContextMenuController.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/RelatableItemBase.DefaultContextMenuController.cs @@ -9,16 +9,8 @@ namespace Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.AttachedColl { public abstract partial class RelatableItemBase { - internal sealed class MenuController : IContextMenuController + internal sealed class MenuController(Guid menuGuid, int menuId) : IContextMenuController { - private readonly Guid _menuGuid; - private readonly int _menuId; - - public MenuController(Guid menuGuid, int menuId) - { - _menuGuid = menuGuid; - _menuId = menuId; - } public bool ShowContextMenu(IEnumerable items, Point location) { @@ -28,13 +20,13 @@ public bool ShowContextMenu(IEnumerable items, Point location) { if (Package.GetGlobalService(typeof(SVsUIShell)) is IVsUIShell shell) { - Guid guidContextMenu = _menuGuid; + Guid guidContextMenu = menuGuid; int result = shell.ShowContextMenu( dwCompRole: 0, rclsidActive: ref guidContextMenu, - nMenuId: _menuId, - pos: new[] { new POINTS { x = (short)location.X, y = (short)location.Y } }, + nMenuId: menuId, + pos: [new POINTS { x = (short)location.X, y = (short)location.Y }], pCmdTrgtActive: null); return ErrorHandler.Succeeded(result); diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/DependencyTreeFlags.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/DependencyTreeFlags.cs index 6d8c0dcb266..b0c77e63554 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/DependencyTreeFlags.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/DependencyTreeFlags.cs @@ -39,7 +39,7 @@ public static class DependencyTreeFlags public static readonly ProjectTreeFlags SupportsRemove = ProjectTreeFlags.Create(nameof(SupportsRemove)); /// - /// Indicates that the dependency supports "Open Containing Folder" and "Copy Full Path" commands. + /// Indicates that the dependency supports the "Open Containing Folder" and "Copy Full Path" commands. /// /// /// Requires the dependency's browse object to contain a BrowsePath value. @@ -47,7 +47,7 @@ public static class DependencyTreeFlags public static readonly ProjectTreeFlags SupportsBrowse = ProjectTreeFlags.Create(nameof(SupportsBrowse)); /// - /// Indicates that the dependency supports "Open Folder in File Explorer", "Open Containing Folder" and "Copy Full Path" commands. + /// Indicates that the dependency supports the "Open Folder in File Explorer", "Open Containing Folder" and "Copy Full Path" commands. /// /// /// Requires the dependency's browse object to contain a BrowsePath value. diff --git a/tests/Microsoft.VisualStudio.ProjectSystem.Managed.VS.UnitTests/Mocks/IVsThreadedWaitDialogFactoryFactory.cs b/tests/Microsoft.VisualStudio.ProjectSystem.Managed.VS.UnitTests/Mocks/IVsThreadedWaitDialogFactoryFactory.cs index 5baf7640241..0dc2c54d738 100644 --- a/tests/Microsoft.VisualStudio.ProjectSystem.Managed.VS.UnitTests/Mocks/IVsThreadedWaitDialogFactoryFactory.cs +++ b/tests/Microsoft.VisualStudio.ProjectSystem.Managed.VS.UnitTests/Mocks/IVsThreadedWaitDialogFactoryFactory.cs @@ -52,12 +52,12 @@ public static (IVsThreadedWaitDialogFactory dialogFactory, Action cancel) Create })) .Returns(HResult.OK); - void cancel() + void Cancel() { callback?.OnCanceled(); } - return (threadedWaitDialogFactoryMock.Object, (Action)cancel); + return (threadedWaitDialogFactoryMock.Object, Cancel); } } } From 434d2e09207dc4160131679d74459213c1e60f72 Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Wed, 27 Nov 2024 13:41:13 +1100 Subject: [PATCH 3/9] Fix compile warning about multiple blank lines --- .../ProjectSystem/VS/HotReload/ProjectHotReloadSession.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/HotReload/ProjectHotReloadSession.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/HotReload/ProjectHotReloadSession.cs index 52bf3ff1bde..ebb7823aa1b 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/HotReload/ProjectHotReloadSession.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/HotReload/ProjectHotReloadSession.cs @@ -165,7 +165,6 @@ public async ValueTask RestartAsync(CancellationToken cancellationToken) { WriteToOutputWindow(VSResources.HotReloadRestartInProgress, cancellationToken); - if (_callback is IProjectHotReloadSessionCallback2 callBack2) { await callBack2.RestartProjectAsync(_isRunningUnderDebugger, cancellationToken); From 38a5703bc2ffb0415719c1f37b03fd1629ea97d2 Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Wed, 27 Nov 2024 13:43:40 +1100 Subject: [PATCH 4/9] Add PolySharp to the solution This allows down-level support for several .NET features. In particular I wanted list patterns, but it offers other features too. The package uses a source generator to add to the project. --- Directory.Packages.props | 1 + eng/imports/HostAgnostic.props | 2 +- .../Microsoft.VisualStudio.ProjectSystem.Managed.VS.csproj | 1 + .../Mocks/IVsThreadedWaitDialogFactoryFactory.cs | 2 +- .../ProjectSystem/VS/Waiting/VisualStudioWaitContextTests.cs | 2 +- 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 30bb8fa8db3..c4bd950405e 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -115,6 +115,7 @@ + diff --git a/eng/imports/HostAgnostic.props b/eng/imports/HostAgnostic.props index ba5a5c4b5ce..e42bcf3d715 100644 --- a/eng/imports/HostAgnostic.props +++ b/eng/imports/HostAgnostic.props @@ -60,7 +60,7 @@ - + diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Microsoft.VisualStudio.ProjectSystem.Managed.VS.csproj b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Microsoft.VisualStudio.ProjectSystem.Managed.VS.csproj index 51cf12bc77a..979b35ffd4d 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Microsoft.VisualStudio.ProjectSystem.Managed.VS.csproj +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Microsoft.VisualStudio.ProjectSystem.Managed.VS.csproj @@ -29,6 +29,7 @@ + diff --git a/tests/Microsoft.VisualStudio.ProjectSystem.Managed.VS.UnitTests/Mocks/IVsThreadedWaitDialogFactoryFactory.cs b/tests/Microsoft.VisualStudio.ProjectSystem.Managed.VS.UnitTests/Mocks/IVsThreadedWaitDialogFactoryFactory.cs index 0dc2c54d738..75369c78021 100644 --- a/tests/Microsoft.VisualStudio.ProjectSystem.Managed.VS.UnitTests/Mocks/IVsThreadedWaitDialogFactoryFactory.cs +++ b/tests/Microsoft.VisualStudio.ProjectSystem.Managed.VS.UnitTests/Mocks/IVsThreadedWaitDialogFactoryFactory.cs @@ -20,7 +20,7 @@ public static (IVsThreadedWaitDialogFactory dialogFactory, Action cancel) Create It.Is(s => s == null), It.Is(s => s == null), It.IsAny(), - It.IsInRange(0, int.MaxValue, Range.Inclusive), + It.IsInRange(0, int.MaxValue, Moq.Range.Inclusive), It.Is(v => !v), It.Is(i => i == 0), It.Is(i => i == 0), diff --git a/tests/Microsoft.VisualStudio.ProjectSystem.Managed.VS.UnitTests/ProjectSystem/VS/Waiting/VisualStudioWaitContextTests.cs b/tests/Microsoft.VisualStudio.ProjectSystem.Managed.VS.UnitTests/ProjectSystem/VS/Waiting/VisualStudioWaitContextTests.cs index 1751e4336bc..6aedbfe35f6 100644 --- a/tests/Microsoft.VisualStudio.ProjectSystem.Managed.VS.UnitTests/ProjectSystem/VS/Waiting/VisualStudioWaitContextTests.cs +++ b/tests/Microsoft.VisualStudio.ProjectSystem.Managed.VS.UnitTests/ProjectSystem/VS/Waiting/VisualStudioWaitContextTests.cs @@ -37,7 +37,7 @@ private static VisualStudioWaitContext Create(string title, string message, bool It.Is(s => s == null), It.Is(s => s == null), It.IsAny(), - It.IsInRange(0, int.MaxValue, Range.Inclusive), + It.IsInRange(0, int.MaxValue, Moq.Range.Inclusive), It.Is(v => !v), It.Is(i => i == 0), It.Is(i => i == 0), From 87528316b1187b0a7ddaa054cc2e33028e280b7e Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Wed, 27 Nov 2024 15:18:09 +1100 Subject: [PATCH 5/9] Support "Open in Object Browser" in dependencies tree This commit adds support for the context menu item "Open in Object Browser", which is added to context menus in the dependencies tree. The previous command handler only suppressed the menu item in nearly all cases. This new code adds support for nodes to advertise their support for this feature, and to provide a path to the DLL to browse. New groups/items are added to the relevant context menus in the VSCT file. A follow-up change will be made to NuGet, to allow browsing to package DLLs using the new `IObjectBrowserItem` interface added here. --- .../Menus.vsct | 12 ++ .../AttachedCollections/IObjectBrowserItem.cs | 14 ++ .../FrameworkReferenceAssemblyItem.cs | 10 +- ...leItemBase.DefaultContextMenuController.cs | 50 +++++- .../Commands/ObjectBrowserCommand.cs | 142 ++++++++++++++++++ ...ObjectBrowserForPackageReferenceCommand.cs | 33 ---- .../PublicAPI.Shipped.txt | 4 +- .../Tree/Dependencies/DependencyTreeFlags.cs | 5 + .../AnalyzerDependencyFactory.cs | 4 +- .../AssemblyDependencyFactory.cs | 4 +- 10 files changed, 232 insertions(+), 46 deletions(-) create mode 100644 src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/IObjectBrowserItem.cs create mode 100644 src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/Commands/ObjectBrowserCommand.cs delete mode 100644 src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/Commands/SuppressObjectBrowserForPackageReferenceCommand.cs diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Menus.vsct b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Menus.vsct index 86b83a46d96..5a2055848a4 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Menus.vsct +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Menus.vsct @@ -76,6 +76,10 @@ + + + + @@ -203,6 +207,12 @@ + + + + + + @@ -246,8 +256,10 @@ + + diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/IObjectBrowserItem.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/IObjectBrowserItem.cs new file mode 100644 index 00000000000..40288fbc85f --- /dev/null +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/IObjectBrowserItem.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE.md file in the project root for more information. + +namespace Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.AttachedCollections; + +/// +/// Used by implementations of that support opening in Visual Studio's Object Browser via their context menu. +/// +public interface IObjectBrowserItem : IRelatableItem +{ + /// + /// Gets the absolute path to an assembly that should be opened in the Object Browser. + /// + string? AssemblyPath { get; } +} diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/Implementation/FrameworkReferenceAssemblyItem.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/Implementation/FrameworkReferenceAssemblyItem.cs index 4b4f7703ba5..fea1ea57180 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/Implementation/FrameworkReferenceAssemblyItem.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/Implementation/FrameworkReferenceAssemblyItem.cs @@ -7,7 +7,7 @@ namespace Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.AttachedCollections.Implementation { - internal sealed class FrameworkReferenceAssemblyItem : RelatableItemBase + internal sealed class FrameworkReferenceAssemblyItem : RelatableItemBase, IObjectBrowserItem { private const int IDM_VS_CTXT_TRANSITIVE_ASSEMBLY_REFERENCE = 0x04B1; @@ -38,7 +38,11 @@ public FrameworkReferenceAssemblyItem(string assemblyName, string? path, string? public override object? GetBrowseObject() => new BrowseObject(this); + string? IObjectBrowserItem.AssemblyPath => GetAssemblyPath(); + private string? GetAssemblyPath() => Path is not null + ? System.IO.Path.GetFullPath(System.IO.Path.Combine(Framework.Path, Path)) + : null; private sealed class BrowseObject(FrameworkReferenceAssemblyItem item) : LocalizableProperties { @@ -52,9 +56,7 @@ private sealed class BrowseObject(FrameworkReferenceAssemblyItem item) : Localiz [BrowseObjectDisplayName(nameof(VSResources.FrameworkAssemblyPathDisplayName))] [BrowseObjectDescription(nameof(VSResources.FrameworkAssemblyPathDescription))] - public string Path => item.Path is not null - ? System.IO.Path.GetFullPath(System.IO.Path.Combine(item.Framework.Path, item.Path)) - : ""; + public string Path => item.GetAssemblyPath() ?? ""; [BrowseObjectDisplayName(nameof(VSResources.FrameworkAssemblyAssemblyVersionDisplayName))] [BrowseObjectDescription(nameof(VSResources.FrameworkAssemblyAssemblyVersionDescription))] diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/RelatableItemBase.DefaultContextMenuController.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/RelatableItemBase.DefaultContextMenuController.cs index bdf2ac22496..f22e70102e7 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/RelatableItemBase.DefaultContextMenuController.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/RelatableItemBase.DefaultContextMenuController.cs @@ -11,12 +11,54 @@ public abstract partial class RelatableItemBase { internal sealed class MenuController(Guid menuGuid, int menuId) : IContextMenuController { + public static ImmutableArray CurrentItems { get; private set; } = []; public bool ShowContextMenu(IEnumerable items, Point location) { - bool shouldShowMenu = items.All(item => item is IRelatableItem); + ImmutableArray? relatableItems = GetItems(); - if (shouldShowMenu) + if (relatableItems is null) + { + return false; + } + + CurrentItems = relatableItems.Value; + + try + { + return ShowContextMenu(); + } + finally + { + CurrentItems = []; + } + + ImmutableArray? GetItems() + { + ImmutableArray.Builder? builder = null; + + foreach (object item in items) + { + if (item is IRelatableItem relatableItem) + { + builder ??= ImmutableArray.CreateBuilder(); + builder.Add(relatableItem); + } + else + { + return null; + } + } + + if (builder is null) + { + return null; + } + + return builder.ToImmutable(); + } + + bool ShowContextMenu() { if (Package.GetGlobalService(typeof(SVsUIShell)) is IVsUIShell shell) { @@ -31,9 +73,9 @@ public bool ShowContextMenu(IEnumerable items, Point location) return ErrorHandler.Succeeded(result); } - } - return false; + return false; + } } } } diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/Commands/ObjectBrowserCommand.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/Commands/ObjectBrowserCommand.cs new file mode 100644 index 00000000000..528bdee3db6 --- /dev/null +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/Commands/ObjectBrowserCommand.cs @@ -0,0 +1,142 @@ +// Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE.md file in the project root for more information. + +using Microsoft.VisualStudio.ProjectSystem.Input; +using Microsoft.VisualStudio.ProjectSystem.Tree.Dependencies; +using Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.AttachedCollections; +using Microsoft.VisualStudio.Shell.Interop; + +using Flags = Microsoft.VisualStudio.ProjectSystem.Tree.Dependencies.DependencyTreeFlags; + +namespace Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.Commands; + +/// +/// Implements Visual Studio's "Open in Object Browser" command for dependencies tree nodes. +/// +/// +/// Items that can be opened in the Object Browser must advertise the fact. +/// The approach depends on the type of node: +/// +/// +/// Direct project dependencies, modelled as , must also implement , +/// include the tree flag, and populate the BrowsePath property on the browse object. +/// +/// +/// Relatable items (attached sub-nodes) modelled as , must implement . +/// +/// +/// +[ProjectCommand(VSConstants.CMDSETID.StandardCommandSet2K_string, (long)VSConstants.VSStd2KCmdID.VIEWREFINOBJECTBROWSER)] +[AppliesTo(ProjectCapability.DependenciesTree)] +[Order(Order.Default)] +[method: ImportingConstructor] +internal sealed class ObjectBrowserCommand(UnconfiguredProject project, IVsUIService navigationTool) : AbstractSingleNodeProjectCommand +{ + // This code needs a little explanation. Consider a tree like this: + // + // - Dependencies + // - Packages + // - MyPackage + // - MyPackage.dll + // - Frameworks + // - Microsoft.NETCore.App + // - Microsoft.CSharp + // + // The "MyPackage" and "Microsoft.NETCore.App" nodes are top-level dependencies, and they have IProjectTree nodes. + // + // The "MyPackage.dll" and "Microsoft.CSharp" nodes are transitive nodes, added via the "AttachedCollections" API + // (IRelatableItem) and do not have IProjectTree nodes. + // + // When the user right-clicks on an IRelatableItem node, CPS is called with the IProjectTree node of the closest + // ancestor, which is not the node the user clicked on. There's no easy way to thread that state through on the + // call stack, so we use a static collection on the menu controller that's only populated while the context menu + // is open. If it has items here, we know we're in the transitive case and will attempt to handle the command. + + protected override async Task GetCommandStatusAsync(IProjectTree node, bool focused, string? commandText, CommandStatus progressiveStatus) + { + string? path = await TryGetAssemblyPathAsync(node); + + if (path is not null) + { + // We handle this . + return new CommandStatusResult(handled: true, commandText, CommandStatus.Enabled | CommandStatus.Supported); + } + + // We won't handle this. Allow other handlers to do so. + return CommandStatusResult.Unhandled; + } + + protected override async Task TryHandleCommandAsync(IProjectTree node, bool focused, long commandExecuteOptions, IntPtr variantArgIn, IntPtr variantArgOut) + { + string? path = await TryGetAssemblyPathAsync(node); + + if (path is not null) + { + ShowAssemblyInObjectBrowser(); + + // Handled. + return true; + } + + // Unhandled. Should not happen in the context menu, as we only show the command when we can handle it. + // Might theoretically happen if someone invoked the command directly on the tree. + return false; + + void ShowAssemblyInObjectBrowser() + { + // We're opening a file as a container (DLL). + SYMBOL_DESCRIPTION_NODE[] symbolNodes = [ + new() { dwType = (uint)_LIB_LISTTYPE.LLT_PHYSICALCONTAINERS, pszName = path } + ]; + + // The container is a "COM+" (.NET) library. This tells Object Browser how to load the file. + Guid libraryGuid = VSConstants.guidCOMPLUSLibrary; + + // Open the Object Browser. + Verify.HResult(navigationTool.Value.NavigateToSymbol(ref libraryGuid, symbolNodes, (uint)symbolNodes.Length)); + } + } + + private async Task TryGetAssemblyPathAsync(IProjectTree node) + { + if (RelatableItemBase.MenuController.CurrentItems.Length is not 0) + { + // An attached relatable items is selected. This command handler is invoked on the closest + // IProjectTree ancestor node rather than the clicked items. So "node" should be ignored. + // Instead, use the "current items" of the menu controller to access selected relatable items. + return HandleTransitiveNode(); + } + else + { + return await HandleDirectNodeAsync(); + } + + string? HandleTransitiveNode() + { + // We only handle a single item of the required type. + if (RelatableItemBase.MenuController.CurrentItems is [IObjectBrowserItem { AssemblyPath: string assemblyPath }]) + { + // Single item, with the required interface. + return IfExists(assemblyPath); + } + + // Multiple items. Unhandled. + return null; + } + + async Task HandleDirectNodeAsync() + { + if (node.Flags.ContainsAny(Flags.SupportsObjectBrowser)) + { + // Get the browse path from the browse object. + string? path = await DependencyServices.GetBrowsePathAsync(project, node); + + return IfExists(path); + } + + // Node doesn't support the object browser. + return null; + } + + static string? IfExists(string? path) => path is not null && File.Exists(path) ? path : null; + } +} diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/Commands/SuppressObjectBrowserForPackageReferenceCommand.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/Commands/SuppressObjectBrowserForPackageReferenceCommand.cs deleted file mode 100644 index 92e62dc182f..00000000000 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/Commands/SuppressObjectBrowserForPackageReferenceCommand.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE.md file in the project root for more information. - -using Microsoft.VisualStudio.ProjectSystem.Input; -using Microsoft.VisualStudio.Threading; - -using Flags = Microsoft.VisualStudio.ProjectSystem.Tree.Dependencies.DependencyTreeFlags; - -namespace Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.Commands -{ - /// - /// Suppresses the "Open in Object Browser" command for NuGet packages. - /// - [ProjectCommand(VSConstants.CMDSETID.StandardCommandSet2K_string, (long)VSConstants.VSStd2KCmdID.QUICKOBJECTSEARCH)] - [AppliesTo(ProjectCapability.PackageReferences)] - [Order(Order.Default)] - internal sealed class SuppressObjectBrowserForPackageReferenceCommand : AbstractSingleNodeProjectCommand - { - protected override Task GetCommandStatusAsync(IProjectTree node, bool focused, string? commandText, CommandStatus progressiveStatus) - { - if (node.Flags.Contains(Flags.PackageDependency)) - { - return GetCommandStatusResult.Suppressed; - } - - return GetCommandStatusResult.Unhandled; - } - - protected override Task TryHandleCommandAsync(IProjectTree node, bool focused, long commandExecuteOptions, IntPtr variantArgIn, IntPtr variantArgOut) - { - return TaskResult.False; - } - } -} diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/PublicAPI.Shipped.txt b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/PublicAPI.Shipped.txt index b7fdd332cd4..89fe9c6a353 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/PublicAPI.Shipped.txt +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/PublicAPI.Shipped.txt @@ -426,4 +426,6 @@ Microsoft.VisualStudio.ProjectSystem.VS.HotReload.IProjectHotReloadUpdateApplier Microsoft.VisualStudio.ProjectSystem.VS.HotReload.IProjectHotReloadNotificationService Microsoft.VisualStudio.ProjectSystem.VS.HotReload.IProjectHotReloadNotificationService.HotReloadStateChangedAsync -> Microsoft.VisualStudio.Threading.AsyncEventHandler! Microsoft.VisualStudio.ProjectSystem.VS.HotReload.IProjectHotReloadNotificationService.IsProjectInHotReload.get -> bool -Microsoft.VisualStudio.ProjectSystem.VS.HotReload.IProjectHotReloadNotificationService.SetHotReloadStateAsync(bool isInHotReload) -> System.Threading.Tasks.Task! \ No newline at end of file +Microsoft.VisualStudio.ProjectSystem.VS.HotReload.IProjectHotReloadNotificationService.SetHotReloadStateAsync(bool isInHotReload) -> System.Threading.Tasks.Task! +Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.AttachedCollections.IObjectBrowserItem +Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.AttachedCollections.IObjectBrowserItem.AssemblyPath.get -> string? \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/DependencyTreeFlags.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/DependencyTreeFlags.cs index b0c77e63554..b32fdaa792a 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/DependencyTreeFlags.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/DependencyTreeFlags.cs @@ -54,6 +54,11 @@ public static class DependencyTreeFlags /// public static readonly ProjectTreeFlags SupportsFolderBrowse = ProjectTreeFlags.Create(nameof(SupportsFolderBrowse)) + SupportsBrowse; + /// + /// Indicates that the dependency supports the "Open in Object Browser". + /// + internal static readonly ProjectTreeFlags SupportsObjectBrowser = ProjectTreeFlags.Create(nameof(SupportsObjectBrowser)); + /// /// Identifies nodes used to group dependencies specific to a given slice, which is most commonly the target framework. /// diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/Subscriptions/MSBuildDependencies/AnalyzerDependencyFactory.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/Subscriptions/MSBuildDependencies/AnalyzerDependencyFactory.cs index 765687bbd51..b863964db6c 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/Subscriptions/MSBuildDependencies/AnalyzerDependencyFactory.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/Subscriptions/MSBuildDependencies/AnalyzerDependencyFactory.cs @@ -14,8 +14,8 @@ internal sealed class AnalyzerDependencyFactory : MSBuildDependencyFactoryBase // Without this flag, CPS will remove whatever file path we pass during tree construction (for // performance reasons). private static readonly DependencyFlagCache s_flagCache = new( - resolved: DependencyTreeFlags.AnalyzerDependency + DependencyTreeFlags.SupportsBrowse + ProjectTreeFlags.FileSystemEntity, - unresolved: DependencyTreeFlags.AnalyzerDependency + DependencyTreeFlags.SupportsBrowse + ProjectTreeFlags.FileSystemEntity); + resolved: DependencyTreeFlags.AnalyzerDependency + DependencyTreeFlags.SupportsBrowse + DependencyTreeFlags.SupportsObjectBrowser + ProjectTreeFlags.FileSystemEntity, + unresolved: DependencyTreeFlags.AnalyzerDependency + DependencyTreeFlags.SupportsBrowse + DependencyTreeFlags.SupportsObjectBrowser + ProjectTreeFlags.FileSystemEntity); public override DependencyGroupType DependencyGroupType => DependencyGroupTypes.Analyzers; diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/Subscriptions/MSBuildDependencies/AssemblyDependencyFactory.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/Subscriptions/MSBuildDependencies/AssemblyDependencyFactory.cs index dbbfe509520..7e0110a1b53 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/Subscriptions/MSBuildDependencies/AssemblyDependencyFactory.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/Subscriptions/MSBuildDependencies/AssemblyDependencyFactory.cs @@ -12,8 +12,8 @@ internal sealed class AssemblyDependencyFactory : MSBuildDependencyFactoryBase public const string AppliesTo = ProjectCapability.DependenciesTree + " & (" + ProjectCapabilities.AssemblyReferences + " | " + ProjectCapabilities.WinRTReferences + ")"; private static readonly DependencyFlagCache s_flagCache = new( - resolved: DependencyTreeFlags.AssemblyDependency + DependencyTreeFlags.SupportsBrowse, - unresolved: DependencyTreeFlags.AssemblyDependency); + resolved: DependencyTreeFlags.AssemblyDependency + DependencyTreeFlags.SupportsObjectBrowser + DependencyTreeFlags.SupportsBrowse, + unresolved: DependencyTreeFlags.AssemblyDependency + DependencyTreeFlags.SupportsObjectBrowser); public override DependencyGroupType DependencyGroupType => DependencyGroupTypes.Assemblies; From 823fbd22b55aa1f3f1eaf73881589b62651b949e Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Wed, 27 Nov 2024 22:55:15 +1100 Subject: [PATCH 6/9] Create a public API for creating IContextMenuController External code that adds `IObjectBrowserItem` items to the dependencies tree needs to use an `IContextMenuController` provided by `RelatableItemBase.CreateContextMenuController`, as this implementation will track the selected item. This commit adds public API for external code to use. --- .../Implementation/FrameworkReferenceAssemblyItem.cs | 2 +- .../RelatableItemBase.DefaultContextMenuController.cs | 5 +++++ .../Dependencies/AttachedCollections/RelatableItemBase.cs | 2 +- .../PublicAPI.Shipped.txt | 3 ++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/Implementation/FrameworkReferenceAssemblyItem.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/Implementation/FrameworkReferenceAssemblyItem.cs index fea1ea57180..b94e7cd1d71 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/Implementation/FrameworkReferenceAssemblyItem.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/Implementation/FrameworkReferenceAssemblyItem.cs @@ -11,7 +11,7 @@ internal sealed class FrameworkReferenceAssemblyItem : RelatableItemBase, IObjec { private const int IDM_VS_CTXT_TRANSITIVE_ASSEMBLY_REFERENCE = 0x04B1; - private static readonly IContextMenuController s_defaultMenuController = new MenuController(VsMenus.guidSHLMainMenu, IDM_VS_CTXT_TRANSITIVE_ASSEMBLY_REFERENCE); + private static readonly IContextMenuController s_defaultMenuController = CreateContextMenuController(VsMenus.guidSHLMainMenu, IDM_VS_CTXT_TRANSITIVE_ASSEMBLY_REFERENCE); public string AssemblyName { get; } public string? Path { get; } diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/RelatableItemBase.DefaultContextMenuController.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/RelatableItemBase.DefaultContextMenuController.cs index f22e70102e7..d7b2c8ab025 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/RelatableItemBase.DefaultContextMenuController.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/RelatableItemBase.DefaultContextMenuController.cs @@ -9,6 +9,11 @@ namespace Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.AttachedColl { public abstract partial class RelatableItemBase { + /// + /// Creates a for use in overrides of . + /// + public static IContextMenuController CreateContextMenuController(Guid menuGuid, int menuId) => new MenuController(menuGuid, menuId); + internal sealed class MenuController(Guid menuGuid, int menuId) : IContextMenuController { public static ImmutableArray CurrentItems { get; private set; } = []; diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/RelatableItemBase.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/RelatableItemBase.cs index 2f152d15aea..e6739c5964c 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/RelatableItemBase.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/AttachedCollections/RelatableItemBase.cs @@ -14,7 +14,7 @@ public abstract partial class RelatableItemBase : AttachedCollectionItemBase, IR { private const int IDM_VS_CTXT_DEPENDENCY_TRANSITIVE_ITEM = 0x04B0; - private static readonly IContextMenuController s_defaultMenuController = new MenuController(VsMenus.guidSHLMainMenu, IDM_VS_CTXT_DEPENDENCY_TRANSITIVE_ITEM); + private static readonly IContextMenuController s_defaultMenuController = CreateContextMenuController(VsMenus.guidSHLMainMenu, IDM_VS_CTXT_DEPENDENCY_TRANSITIVE_ITEM); private AggregateContainsRelationCollection? _containsCollection; diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/PublicAPI.Shipped.txt b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/PublicAPI.Shipped.txt index 89fe9c6a353..24bc3838565 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/PublicAPI.Shipped.txt +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/PublicAPI.Shipped.txt @@ -428,4 +428,5 @@ Microsoft.VisualStudio.ProjectSystem.VS.HotReload.IProjectHotReloadNotificationS Microsoft.VisualStudio.ProjectSystem.VS.HotReload.IProjectHotReloadNotificationService.IsProjectInHotReload.get -> bool Microsoft.VisualStudio.ProjectSystem.VS.HotReload.IProjectHotReloadNotificationService.SetHotReloadStateAsync(bool isInHotReload) -> System.Threading.Tasks.Task! Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.AttachedCollections.IObjectBrowserItem -Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.AttachedCollections.IObjectBrowserItem.AssemblyPath.get -> string? \ No newline at end of file +Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.AttachedCollections.IObjectBrowserItem.AssemblyPath.get -> string? +static Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.AttachedCollections.RelatableItemBase.CreateContextMenuController(System.Guid menuGuid, int menuId) -> Microsoft.Internal.VisualStudio.PlatformUI.IContextMenuController! \ No newline at end of file From 0cc24ddb46753d6e9f539dbec803c0b1aaf80ae7 Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Wed, 27 Nov 2024 22:55:52 +1100 Subject: [PATCH 7/9] Support showing project references in the object browser --- .../Menus.vsct | 4 ++++ .../Rules/Dependencies/ResolvedProjectReference.xaml | 4 +--- .../MSBuildDependencies/ProjectDependencyFactory.cs | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Menus.vsct b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Menus.vsct index 5a2055848a4..5103b6cd0bf 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Menus.vsct +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Menus.vsct @@ -80,6 +80,10 @@ + + + + diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Rules/Dependencies/ResolvedProjectReference.xaml b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Rules/Dependencies/ResolvedProjectReference.xaml index 779ef417102..c6c104fae5d 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Rules/Dependencies/ResolvedProjectReference.xaml +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Rules/Dependencies/ResolvedProjectReference.xaml @@ -30,9 +30,7 @@ ReadOnly="True" Visible="False"> - diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/Subscriptions/MSBuildDependencies/ProjectDependencyFactory.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/Subscriptions/MSBuildDependencies/ProjectDependencyFactory.cs index e392ebc232e..100aac0bde7 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/Subscriptions/MSBuildDependencies/ProjectDependencyFactory.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/Subscriptions/MSBuildDependencies/ProjectDependencyFactory.cs @@ -9,8 +9,8 @@ internal sealed class ProjectDependencyFactory : MSBuildDependencyFactoryBase public const string AppliesTo = ProjectCapability.DependenciesTree + " & " + ProjectCapabilities.ProjectReferences; private static readonly DependencyFlagCache s_flagCache = new( - resolved: DependencyTreeFlags.ProjectDependency + DependencyTreeFlags.SupportsBrowse, - unresolved: DependencyTreeFlags.ProjectDependency + DependencyTreeFlags.SupportsBrowse); + resolved: DependencyTreeFlags.ProjectDependency + DependencyTreeFlags.SupportsBrowse + DependencyTreeFlags.SupportsObjectBrowser, + unresolved: DependencyTreeFlags.ProjectDependency + DependencyTreeFlags.SupportsBrowse + DependencyTreeFlags.SupportsObjectBrowser); public override DependencyGroupType DependencyGroupType => DependencyGroupTypes.Projects; From 32b7a4ffc3a571f76ee261eee252854fb696350d Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Wed, 27 Nov 2024 22:56:06 +1100 Subject: [PATCH 8/9] Support showing COM references in the object browser --- .../Menus.vsct | 5 +++++ .../Rules/Dependencies/ResolvedCOMReference.xaml | 4 +--- .../MSBuildDependencies/ComDependencyFactory.cs | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Menus.vsct b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Menus.vsct index 5103b6cd0bf..07bac97f04b 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Menus.vsct +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/Menus.vsct @@ -80,6 +80,10 @@ + + + + @@ -260,6 +264,7 @@ + diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Rules/Dependencies/ResolvedCOMReference.xaml b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Rules/Dependencies/ResolvedCOMReference.xaml index ee97448c44a..aa96a218564 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Rules/Dependencies/ResolvedCOMReference.xaml +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Rules/Dependencies/ResolvedCOMReference.xaml @@ -30,9 +30,7 @@ ReadOnly="True" Visible="False"> - diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/Subscriptions/MSBuildDependencies/ComDependencyFactory.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/Subscriptions/MSBuildDependencies/ComDependencyFactory.cs index 759a06ef75a..2da23c58b45 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/Subscriptions/MSBuildDependencies/ComDependencyFactory.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/Subscriptions/MSBuildDependencies/ComDependencyFactory.cs @@ -9,8 +9,8 @@ internal sealed class ComDependencyFactory : MSBuildDependencyFactoryBase public const string AppliesTo = ProjectCapability.DependenciesTree + " & " + ProjectCapabilities.ComReferences; private static readonly DependencyFlagCache s_flagCache = new( - resolved: DependencyTreeFlags.ComDependency + DependencyTreeFlags.SupportsBrowse, - unresolved: DependencyTreeFlags.ComDependency); + resolved: DependencyTreeFlags.ComDependency + DependencyTreeFlags.SupportsObjectBrowser + DependencyTreeFlags.SupportsBrowse, + unresolved: DependencyTreeFlags.ComDependency + DependencyTreeFlags.SupportsObjectBrowser); public override DependencyGroupType DependencyGroupType => DependencyGroupTypes.Com; From d2feb6efec0e7010427511b5df019c1e3e388e71 Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Thu, 5 Dec 2024 14:54:01 +1100 Subject: [PATCH 9/9] Remove extra white space --- .../VS/Tree/Dependencies/Commands/ObjectBrowserCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/Commands/ObjectBrowserCommand.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/Commands/ObjectBrowserCommand.cs index 528bdee3db6..9517a4017ec 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/Commands/ObjectBrowserCommand.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/Commands/ObjectBrowserCommand.cs @@ -57,7 +57,7 @@ protected override async Task GetCommandStatusAsync(IProjec if (path is not null) { - // We handle this . + // We handle this. return new CommandStatusResult(handled: true, commandText, CommandStatus.Enabled | CommandStatus.Supported); }