提交 c517a927 编写于 作者: G Gen Lu

Revert #31132

上级 553cba01
......@@ -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();
/// <summary>
/// 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.
/// </summary>
private bool _resharperExtensionInstalledAndEnabled = false;
private bool _infoBarOpen = false;
private bool _isFirstRun = true;
private bool _resharperExtensionEnabled = false;
/// <summary>
/// Chain all update tasks so that task runs serially
/// </summary>
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<IVsRegisterPriorityCommandTarget, SVsRegisterPriorityCommandTarget>();
......@@ -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<IInfoBarService>();
infoBarService.ShowInfoBarInGlobalView(
......@@ -260,69 +217,37 @@ private void ShowGoldBar()
action: InfoBarClose));
}
/// <summary>
/// Returns true if ReSharper is installed, enabled, and not suspended.
/// </summary>
private async Task<ReSharperStatus> 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);
if (_oleCommandTarget == null)
{
_oleCommandTarget = _serviceProvider.GetService<IOleCommandTarget, SUIHostCommandDispatcher>();
}
var cmds = new OLECMD[1];
cmds[0].cmdID = ResumeId;
cmds[0].cmdID = SuspendId;
cmds[0].cmdf = 0;
for (var count = 0; count < 10; count++)
{
cancellationToken.ThrowIfCancellationRequested();
var hr = await QueryStatusOnUIThreadAsync().ConfigureAwait(false);
var hr = _oleCommandTarget.QueryStatus(ReSharperCommandGroup, (uint)cmds.Length, cmds, IntPtr.Zero);
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);
Shutdown();
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);
}
// If resume button doesn't become active within a reasonable amount of time, assume ReSharper is Enabled
return ReSharperStatus.Enabled;
async Task<int> QueryStatusOnUIThreadAsync()
{
await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
return _oleCommandTarget.QueryStatus(ReSharperCommandGroup, (uint)cmds.Length, cmds, IntPtr.Zero);
}
async Task EnsureOleCommandTargetAsync()
{
if (_oleCommandTarget != null)
{
return;
}
await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
_oleCommandTarget = _serviceProvider.GetService<IOleCommandTarget, SUIHostCommandDispatcher>();
}
// 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<IVsRegisterPriorityCommandTarget, SVsRegisterPriorityCommandTarget>();
var cookie = _priorityCommandTargetCookie;
_priorityCommandTargetCookie = VSConstants.VSCOOKIE_NIL;
var hr = priorityCommandTargetRegistrar.UnregisterPriorityCommandTarget(cookie);
if (ErrorHandler.Failed(hr))
{
FatalError.ReportWithoutCrash(Marshal.GetExceptionForHR(hr));
......
......@@ -13,7 +13,7 @@ internal enum ReSharperStatus
/// </summary>
Suspended,
/// <summary>
/// ReSharper is installed and enabled.
/// ReSharper is running.
/// </summary>
Enabled
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册