From c864ff4ad6679b2c2d35f5909ac70f7d9b34dd9a Mon Sep 17 00:00:00 2001 From: reduckted Date: Thu, 26 Jan 2023 12:00:38 +1000 Subject: [PATCH] Allow command interceptors to be unregistered. --- .../Commands/Commands.cs | 17 ++++++++----- .../Helpers/Disposable.cs | 24 +++++++++++++++++++ .../VSSDK.Helpers.Shared.projitems | 1 + 3 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 src/toolkit/Community.VisualStudio.Toolkit.Shared/Helpers/Disposable.cs diff --git a/src/toolkit/Community.VisualStudio.Toolkit.Shared/Commands/Commands.cs b/src/toolkit/Community.VisualStudio.Toolkit.Shared/Commands/Commands.cs index e8b7ad2..a7e3072 100644 --- a/src/toolkit/Community.VisualStudio.Toolkit.Shared/Commands/Commands.cs +++ b/src/toolkit/Community.VisualStudio.Toolkit.Shared/Commands/Commands.cs @@ -5,7 +5,6 @@ using Microsoft.VisualStudio.OLE.Interop; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; -using Task = System.Threading.Tasks.Task; namespace Community.VisualStudio.Toolkit { @@ -93,32 +92,38 @@ public Task ExecuteAsync(CommandID cmd, string argument = "") /// /// Intercept any command before it is being handled by other command handlers. /// - public Task InterceptAsync(VSConstants.VSStd97CmdID command, Func func) + /// Returns an that will remove the command interceptor when disposed. + public Task InterceptAsync(VSConstants.VSStd97CmdID command, Func func) => InterceptAsync(typeof(VSConstants.VSStd97CmdID).GUID, (int)command, func); /// /// Intercept any command before it is being handled by other command handlers. /// - public Task InterceptAsync(VSConstants.VSStd2KCmdID command, Func func) + /// Returns an that will remove the command interceptor when disposed. + public Task InterceptAsync(VSConstants.VSStd2KCmdID command, Func func) => InterceptAsync(typeof(VSConstants.VSStd2KCmdID).GUID, (int)command, func); /// /// Intercept any command before it is being handled by other command handlers. /// - public Task InterceptAsync(Guid menuGroup, int commandId, Func func) + /// Returns an that will remove the command interceptor when disposed. + public Task InterceptAsync(Guid menuGroup, int commandId, Func func) => InterceptAsync(new CommandID(menuGroup, commandId), func); /// /// Intercept any command before it is being handled by other command handlers. /// - public async Task InterceptAsync(CommandID cmd, Func func) + /// Returns an that will remove the command interceptor when disposed. + public async Task InterceptAsync(CommandID cmd, Func func) { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); IVsRegisterPriorityCommandTarget? priority = await VS.Services.GetPriorityCommandTargetAsync(); CommandInterceptor interceptor = new(cmd, func); - ErrorHandler.ThrowOnFailure(priority.RegisterPriorityCommandTarget(0, interceptor, out _)); + ErrorHandler.ThrowOnFailure(priority.RegisterPriorityCommandTarget(0, interceptor, out uint cookie)); + + return new Disposable(() => priority.UnregisterPriorityCommandTarget(cookie)); } } diff --git a/src/toolkit/Community.VisualStudio.Toolkit.Shared/Helpers/Disposable.cs b/src/toolkit/Community.VisualStudio.Toolkit.Shared/Helpers/Disposable.cs new file mode 100644 index 0000000..f484045 --- /dev/null +++ b/src/toolkit/Community.VisualStudio.Toolkit.Shared/Helpers/Disposable.cs @@ -0,0 +1,24 @@ +using System; + +namespace Community.VisualStudio.Toolkit +{ + internal sealed class Disposable : IDisposable + { + private readonly Action _action; + private bool _disposed; + + public Disposable(Action action) + { + _action = action; + } + + public void Dispose() + { + if (!_disposed) + { + _disposed = true; + _action(); + } + } + } +} diff --git a/src/toolkit/Community.VisualStudio.Toolkit.Shared/VSSDK.Helpers.Shared.projitems b/src/toolkit/Community.VisualStudio.Toolkit.Shared/VSSDK.Helpers.Shared.projitems index 968b78f..e5c6c98 100644 --- a/src/toolkit/Community.VisualStudio.Toolkit.Shared/VSSDK.Helpers.Shared.projitems +++ b/src/toolkit/Community.VisualStudio.Toolkit.Shared/VSSDK.Helpers.Shared.projitems @@ -10,6 +10,7 @@ +