From c517a927823be11c98a8dce0ef6b462b7434e453 Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Wed, 12 Dec 2018 15:35:36 -0800 Subject: [PATCH] Revert #31132 --- .../KeybindingResetDetector.cs | 152 +++++------------- .../Experimentation/ReSharperStatus.cs | 2 +- 2 files changed, 37 insertions(+), 117 deletions(-) diff --git a/src/VisualStudio/Core/Def/Implementation/Experimentation/KeybindingResetDetector.cs b/src/VisualStudio/Core/Def/Implementation/Experimentation/KeybindingResetDetector.cs index 613d3f9d336..6e27596a6a6 100644 --- a/src/VisualStudio/Core/Def/Implementation/Experimentation/KeybindingResetDetector.cs +++ b/src/VisualStudio/Core/Def/Implementation/Experimentation/KeybindingResetDetector.cs @@ -4,8 +4,6 @@ using System.ComponentModel.Composition; using System.Diagnostics; using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Experimentation; @@ -68,19 +66,13 @@ internal sealed class KeybindingResetDetector : ForegroundThreadAffinitizedObjec private OleComponent _oleComponent; private uint _priorityCommandTargetCookie = VSConstants.VSCOOKIE_NIL; - private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); /// /// If false, ReSharper is either not installed, or has been disabled in the extension manager. /// If true, the ReSharper extension is enabled. ReSharper's internal status could be either suspended or enabled. /// - private bool _resharperExtensionInstalledAndEnabled = false; - private bool _infoBarOpen = false; - private bool _isFirstRun = true; + private bool _resharperExtensionEnabled = false; - /// - /// Chain all update tasks so that task runs serially - /// - private Task _lastTask = Task.CompletedTask; + private bool _infoBarOpen = false; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -121,9 +113,9 @@ private void InitializeCore() return; } - _resharperExtensionInstalledAndEnabled = extensionEnabled != 0; + _resharperExtensionEnabled = extensionEnabled != 0; - if (_resharperExtensionInstalledAndEnabled) + if (_resharperExtensionEnabled) { // We need to monitor for suspend/resume commands, so create and install the command target and the modal callback. var priorityCommandTargetRegistrar = _serviceProvider.GetService(); @@ -143,46 +135,16 @@ private void InitializeCore() _oleComponent.ModalStateChanged += OnModalStateChanged; } - // run it from background and fire and forget - StartUpdateStateMachine(); + UpdateStateMachine(); } - private void StartUpdateStateMachine() + private void UpdateStateMachine() { - // cancel previous state machine update request - _cancellationTokenSource.Cancel(); - _cancellationTokenSource = new CancellationTokenSource(); - - var cancellationToken = _cancellationTokenSource.Token; - - // make sure all state machine change work is serialized so that cancellation - // doesn't mess the state up. - _lastTask = _lastTask.ContinueWith(async _ => - { - await UpdateStateMachineWorkerAsync(cancellationToken).ConfigureAwait(false); - }, cancellationToken, TaskContinuationOptions.LazyCancellation, TaskScheduler.Default).Unwrap(); - } + AssertIsForeground(); - private async Task UpdateStateMachineWorkerAsync(CancellationToken cancellationToken) - { + var currentStatus = IsReSharperEnabled(); var options = _workspace.Options; - var lastStatus = options.GetOption(KeybindingResetOptions.ReSharperStatus); - - ReSharperStatus currentStatus; - try - { - currentStatus = await IsReSharperRunningAsync(lastStatus, cancellationToken) - .ConfigureAwait(false); - } - catch (OperationCanceledException) - { - return; - } - - if (!_isFirstRun && currentStatus == lastStatus) - { - return; - } + ReSharperStatus lastStatus = options.GetOption(KeybindingResetOptions.ReSharperStatus); options = options.WithChangedOption(KeybindingResetOptions.ReSharperStatus, currentStatus); @@ -199,12 +161,6 @@ private async Task UpdateStateMachineWorkerAsync(CancellationToken cancellationT // the extension, then reenables the extension. We will show the gold bar after the switch // if there is still a pending show. - // If ReSharper was suspended and the user closed and reopened VS, we want to reset the gold bar - else if (_isFirstRun) - { - options = options.WithChangedOption(KeybindingResetOptions.NeedsReset, true); - } - break; case ReSharperStatus.Enabled: if (currentStatus != ReSharperStatus.Enabled) @@ -218,16 +174,17 @@ private async Task UpdateStateMachineWorkerAsync(CancellationToken cancellationT } _workspace.Options = options; + if (options.GetOption(KeybindingResetOptions.NeedsReset)) { ShowGoldBar(); } - - _isFirstRun = false; } private void ShowGoldBar() { + AssertIsForeground(); + // If the gold bar is already open, do not show if (_infoBarOpen) { @@ -239,7 +196,7 @@ private void ShowGoldBar() Debug.Assert(_experimentationService.IsExperimentEnabled(InternalFlightName) || _experimentationService.IsExperimentEnabled(ExternalFlightName)); - var message = ServicesVSResources.We_notice_you_suspended_0_Reset_keymappings_to_continue_to_navigate_and_refactor; + string message = ServicesVSResources.We_notice_you_suspended_0_Reset_keymappings_to_continue_to_navigate_and_refactor; KeybindingsResetLogger.Log("InfoBarShown"); var infoBarService = _workspace.Services.GetRequiredService(); infoBarService.ShowInfoBarInGlobalView( @@ -260,69 +217,37 @@ private void ShowGoldBar() action: InfoBarClose)); } - /// - /// Returns true if ReSharper is installed, enabled, and not suspended. - /// - private async Task IsReSharperRunningAsync(ReSharperStatus lastStatus, CancellationToken cancellationToken) + private ReSharperStatus IsReSharperEnabled() { + AssertIsForeground(); + // Quick exit if resharper is either uninstalled or not enabled - if (!_resharperExtensionInstalledAndEnabled) + if (!_resharperExtensionEnabled) { return ReSharperStatus.NotInstalledOrDisabled; } - await EnsureOleCommandTargetAsync().ConfigureAwait(false); - - var cmds = new OLECMD[1]; - cmds[0].cmdID = ResumeId; - cmds[0].cmdf = 0; - - for (var count = 0; count < 10; count++) + if (_oleCommandTarget == null) { - cancellationToken.ThrowIfCancellationRequested(); - - var hr = await QueryStatusOnUIThreadAsync().ConfigureAwait(false); - if (ErrorHandler.Failed(hr)) - { - // In the case of an error when attempting to get the status, pretend that ReSharper isn't enabled. We also - // shut down monitoring so we don't keep hitting this. - FatalError.ReportWithoutCrash(Marshal.GetExceptionForHR(hr)); - await ShutdownAsync().ConfigureAwait(false); - - return ReSharperStatus.NotInstalledOrDisabled; - } - - // When ReSharper is suspended, the ReSharper_Resume command has the Enabled | Supported flags. - if (((OLECMDF)cmds[0].cmdf).HasFlag(OLECMDF.OLECMDF_ENABLED)) - { - return ReSharperStatus.Suspended; - } - - //otherwise sleep for a bit and check again - await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken).ConfigureAwait(false); + _oleCommandTarget = _serviceProvider.GetService(); } - // If resume button doesn't become active within a reasonable amount of time, assume ReSharper is Enabled - return ReSharperStatus.Enabled; + var cmds = new OLECMD[1]; + cmds[0].cmdID = SuspendId; + cmds[0].cmdf = 0; - async Task QueryStatusOnUIThreadAsync() + var hr = _oleCommandTarget.QueryStatus(ReSharperCommandGroup, (uint)cmds.Length, cmds, IntPtr.Zero); + if (ErrorHandler.Failed(hr)) { - await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - - return _oleCommandTarget.QueryStatus(ReSharperCommandGroup, (uint)cmds.Length, cmds, IntPtr.Zero); + // In the case of an error when attempting to get the status, pretend that ReSharper isn't enabled. We also + // shut down monitoring so we don't keep hitting this. + FatalError.ReportWithoutCrash(Marshal.GetExceptionForHR(hr)); + Shutdown(); + return ReSharperStatus.NotInstalledOrDisabled; } - async Task EnsureOleCommandTargetAsync() - { - if (_oleCommandTarget != null) - { - return; - } - - await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - - _oleCommandTarget = _serviceProvider.GetService(); - } + // When ReSharper is enabled, the ReSharper_Suspend command has the Enabled | Supported flags. When disabled, it has Invisible | Supported. + return ((OLECMDF)cmds[0].cmdf).HasFlag(OLECMDF.OLECMDF_ENABLED) ? ReSharperStatus.Enabled : ReSharperStatus.Suspended; } private void RestoreVsKeybindings() @@ -370,7 +295,7 @@ private void NeverShowAgain() KeybindingsResetLogger.Log("NeverShowAgain"); // The only external references to this object are as callbacks, which are removed by the Shutdown method. - ThreadingContext.JoinableTaskFactory.Run(ShutdownAsync); + Shutdown(); } private void InfoBarClose() @@ -394,7 +319,7 @@ public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pv if (pguidCmdGroup == ReSharperCommandGroup && nCmdID >= ResumeId && nCmdID <= ToggleSuspendId) { // Don't delay command processing to update resharper status - StartUpdateStateMachine(); + Task.Run(() => InvokeBelowInputPriorityAsync(UpdateStateMachine)); } // No matter the command, we never actually want to respond to it, so always return not supported. We're just monitoring. @@ -410,24 +335,19 @@ private void OnModalStateChanged(object sender, StateChangedEventArgs args) // extra QueryStatus. if (args.TransitionType == StateTransitionType.Exit) { - StartUpdateStateMachine(); + InvokeBelowInputPriorityAsync(UpdateStateMachine); } } - private async Task ShutdownAsync() + public void Shutdown() { - // we are shutting down, cancel any pending work. - _cancellationTokenSource.Cancel(); - - await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); - + AssertIsForeground(); if (_priorityCommandTargetCookie != VSConstants.VSCOOKIE_NIL) { var priorityCommandTargetRegistrar = _serviceProvider.GetService(); var cookie = _priorityCommandTargetCookie; _priorityCommandTargetCookie = VSConstants.VSCOOKIE_NIL; var hr = priorityCommandTargetRegistrar.UnregisterPriorityCommandTarget(cookie); - if (ErrorHandler.Failed(hr)) { FatalError.ReportWithoutCrash(Marshal.GetExceptionForHR(hr)); diff --git a/src/VisualStudio/Core/Def/Implementation/Experimentation/ReSharperStatus.cs b/src/VisualStudio/Core/Def/Implementation/Experimentation/ReSharperStatus.cs index f146dc270b8..080da66c8b5 100644 --- a/src/VisualStudio/Core/Def/Implementation/Experimentation/ReSharperStatus.cs +++ b/src/VisualStudio/Core/Def/Implementation/Experimentation/ReSharperStatus.cs @@ -13,7 +13,7 @@ internal enum ReSharperStatus /// Suspended, /// - /// ReSharper is installed and enabled. + /// ReSharper is running. /// Enabled } -- GitLab