private void UpdateStateMachine()
        {
            AssertIsForeground();

            var             currentStatus = IsReSharperEnabled();
            var             options       = _workspace.Options;
            ReSharperStatus lastStatus    = options.GetOption(KeybindingResetOptions.ReSharperStatus);

            options = options.WithChangedOption(KeybindingResetOptions.ReSharperStatus, currentStatus);

            switch (lastStatus)
            {
            case ReSharperStatus.NotInstalledOrDisabled:
            case ReSharperStatus.Suspended:
                if (currentStatus == ReSharperStatus.Enabled)
                {
                    // N->E or S->E. If ReSharper was just installed and is enabled, reset NeedsReset.
                    options = options.WithChangedOption(KeybindingResetOptions.NeedsReset, false);
                }
                // Else is N->N, N->S, S->N, S->S. N->S can occur if the user suspends ReSharper, then disables
                // the extension, then reenables the extension. We will show the gold bar after the switch
                // if there is still a pending show.

                break;

            case ReSharperStatus.Enabled:
                if (currentStatus != ReSharperStatus.Enabled)
                {
                    // E->N or E->S. Set NeedsReset. Pop the gold bar to the user.
                    options = options.WithChangedOption(KeybindingResetOptions.NeedsReset, true);
                }

                // Else is E->E. No actions to take
                break;
            }

            _workspace.Options = options;

            if (options.GetOption(KeybindingResetOptions.NeedsReset))
            {
                ShowGoldBar();
            }
        }
Beispiel #2
0
        /// <summary>
        /// Returns true if ReSharper is installed, enabled, and not suspended.
        /// </summary>
        private async ValueTask <ReSharperStatus> IsReSharperRunningAsync(ReSharperStatus lastStatus, CancellationToken cancellationToken)
        {
            // Quick exit if resharper is either uninstalled or not enabled
            if (!_resharperExtensionInstalledAndEnabled)
            {
                return(ReSharperStatus.NotInstalledOrDisabled);
            }

            await EnsureOleCommandTargetAsync().ConfigureAwait(false);

            // poll until either suspend or resume botton is available, or until operation is canceled
            while (true)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var suspendFlag = await QueryStatusAsync(SuspendId).ConfigureAwait(false);

                // 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.
                if (suspendFlag == 0)
                {
                    return(ReSharperStatus.NotInstalledOrDisabled);
                }

                var resumeFlag = await QueryStatusAsync(ResumeId).ConfigureAwait(false);

                if (resumeFlag == 0)
                {
                    return(ReSharperStatus.NotInstalledOrDisabled);
                }

                // When ReSharper is running, the ReSharper_Suspend command is Enabled and not Invisible
                if (suspendFlag.HasFlag(OLECMDF.OLECMDF_ENABLED) && !suspendFlag.HasFlag(OLECMDF.OLECMDF_INVISIBLE))
                {
                    return(ReSharperStatus.Enabled);
                }

                // When ReSharper is suspended, the ReSharper_Resume command is Enabled and not Invisible
                if (resumeFlag.HasFlag(OLECMDF.OLECMDF_ENABLED) && !resumeFlag.HasFlag(OLECMDF.OLECMDF_INVISIBLE))
                {
                    return(ReSharperStatus.Suspended);
                }

                // ReSharper has not finished initializing, so try again later
                await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken).ConfigureAwait(false);
            }

            async Task <OLECMDF> QueryStatusAsync(uint cmdId)
            {
                var cmds = new OLECMD[1];

                cmds[0].cmdID = cmdId;
                cmds[0].cmdf  = 0;

                await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

                cancellationToken.ThrowIfCancellationRequested();

                var hr = _oleCommandTarget.QueryStatus(ReSharperCommandGroup, (uint)cmds.Length, cmds, IntPtr.Zero);

                if (ErrorHandler.Failed(hr))
                {
                    FatalError.ReportWithoutCrash(Marshal.GetExceptionForHR(hr));
                    await ShutdownAsync().ConfigureAwait(false);

                    return(0);
                }

                return((OLECMDF)cmds[0].cmdf);
            }

            async Task EnsureOleCommandTargetAsync()
            {
                if (_oleCommandTarget != null)
                {
                    return;
                }

                await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

                cancellationToken.ThrowIfCancellationRequested();

                _oleCommandTarget = _serviceProvider.GetService <IOleCommandTarget, SUIHostCommandDispatcher>();
            }
        }
Beispiel #3
0
        /// <summary>
        /// Returns true if ReSharper is installed, enabled, and not suspended.
        /// </summary>
        private async Task <ReSharperStatus> IsReSharperRunningAsync(ReSharperStatus lastStatus, CancellationToken cancellationToken)
        {
            // Quick exit if resharper is either uninstalled or not enabled
            if (!_resharperExtensionInstalledAndEnabled)
            {
                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++)
            {
                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);
            }

            // 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>();
            }
        }