File: Interactive\ResetInteractiveWindowFromProjectCommand.cs
Web Access
Project: src\src\VisualStudio\CSharp\Impl\Microsoft.VisualStudio.LanguageServices.CSharp_vqvzewbc_wpftmp.csproj (Microsoft.VisualStudio.LanguageServices.CSharp)
// 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 file in the project root for more information.
 
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Options;
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.Commands;
using Microsoft.VisualStudio.Extensibility.VSSdkCompatibility;
using Microsoft.VisualStudio.LanguageServices.Interactive;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Utilities;
 
namespace Microsoft.VisualStudio.LanguageServices.CSharp.Interactive;
 
/// <summary>
/// Implements View/Other Windows/C# Interactive command.
/// </summary>
[VisualStudioContribution]
internal class ResetInteractiveWindowFromProjectCommand(
    MefInjection<IThreadingContext> mefThreadingContext,
    MefInjection<CSharpVsInteractiveWindowProvider> mefInteractiveWindowProvider,
    MefInjection<VisualStudioWorkspace> mefWorkspace,
    MefInjection<IUIThreadOperationExecutor> mefUIThreadOperationExecutor,
    MefInjection<EditorOptionsService> mefEditorOptionsService,
    AsyncServiceProviderInjection<SDTE, EnvDTE.DTE> dteProvider,
    AsyncServiceProviderInjection<SVsShellMonitorSelection, IVsMonitorSelection> monitorSelectionProvider,
    AsyncServiceProviderInjection<SVsSolutionBuildManager, IVsSolutionBuildManager> solutionBuildManagerProvider) : Command
{
    public override CommandConfiguration CommandConfiguration => new("%CSharpLanguageServiceExtension.ResetInteractiveWindowFromProject.DisplayName%")
    {
        VisibleWhen =
            ActivationConstraint.ActiveProjectCapability(ProjectCapability.CSharp) &
            // This doesn't activate when a multi-targeted project has a netfx target. We currently do not support that scenario.
            // Ideally, we would remove this constraint entirely and support reset for .NET as well.
            ActivationConstraint.ActiveProjectBuildProperty("TargetFrameworkMoniker", "[.]NETFramework.*")
    };
 
    public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
    {
        var threadingContext = await mefThreadingContext.GetServiceAsync().ConfigureAwait(false);
        var interactiveWindowProvider = await mefInteractiveWindowProvider.GetServiceAsync().ConfigureAwait(false);
        var workspace = await mefWorkspace.GetServiceAsync().ConfigureAwait(false);
        var editorOptionsService = await mefEditorOptionsService.GetServiceAsync().ConfigureAwait(false);
        var uiThreadOperationExecutor = await mefUIThreadOperationExecutor.GetServiceAsync().ConfigureAwait(false);
 
        await threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
 
        // fetch services on UI thread and stay on UI thread:
        var dte = await dteProvider.GetServiceAsync().ConfigureAwait(true);
        var monitorSelection = await monitorSelectionProvider.GetServiceAsync().ConfigureAwait(true);
        var solutionBuildManager = await solutionBuildManagerProvider.GetServiceAsync().ConfigureAwait(true);
 
        var resetInteractive = new VsResetInteractive(
            workspace,
            dte,
            editorOptionsService,
            uiThreadOperationExecutor,
            monitorSelection,
            solutionBuildManager,
            static referenceName => $"#r \"{referenceName}\"",
            static namespaceName => $"using {namespaceName};");
 
        var vsInteractiveWindow = interactiveWindowProvider.Open(instanceId: 0, focus: true);
 
        // TODO: potential race condition (https://github.com/dotnet/roslyn/issues/71871):
        await resetInteractive.ExecuteAsync(vsInteractiveWindow.InteractiveWindow, CSharpVSResources.CSharp_Interactive).ConfigureAwait(true);
        resetInteractive.ExecutionCompleted += FocusWindow;
 
        void FocusWindow(object s, EventArgs e)
        {
            // We have to set focus to the Interactive Window *after* the wait indicator is dismissed.
            vsInteractiveWindow.Show(focus: true);
            resetInteractive.ExecutionCompleted -= FocusWindow;
        }
    }
}