/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/EditorFeatures/Core/Interactive/ResetInteractive.cs
152 строки
7 KB
Cyrus Najmabadi
Move files
25 апр 2025, 01:10
25 апр 2025, 01:10
46f9987
Код
Авторство
О чём код?
// 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. #nullable disable extern alias InteractiveHost; using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks; using InteractiveHost::Microsoft.CodeAnalysis.Interactive; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.InteractiveWindow; using Microsoft.VisualStudio.Text.Editor.OptionsExtensionMethods; using Microsoft.VisualStudio.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Interactive; /// <summary> /// ResetInteractive class that implements base functionality for reset interactive command. /// Does not depend on VS classes to make it easier to stub out and test. /// </summary> internal abstract class ResetInteractive { private readonly Func<string, string> _createReference; private readonly Func<string, string> _createImport; private readonly EditorOptionsService _editorOptionsService; internal event EventHandler ExecutionCompleted; internal ResetInteractive(EditorOptionsService editorOptionsService, Func<string, string> createReference, Func<string, string> createImport) { _editorOptionsService = editorOptionsService; _createReference = createReference; _createImport = createImport; } internal async Task ExecuteAsync(IInteractiveWindow interactiveWindow, string title) { if (GetProjectProperties(out var references, out var referenceSearchPaths, out var sourceSearchPaths, out var projectNamespaces, out var projectDirectory, out var platform)) { try { // Now, we're going to do a bunch of async operations. So create a wait // indicator so the user knows something is happening, and also so they cancel. var uiThreadOperationExecutor = GetUIThreadOperationExecutor(); using var context = uiThreadOperationExecutor.BeginExecute(title, EditorFeaturesWpfResources.Building_Project, allowCancellation: true, showProgress: false); // We want to come back onto the calling context to dismiss the wait indicator and to notify about // execution completion. await ResetInteractiveAsync( interactiveWindow, references, referenceSearchPaths, sourceSearchPaths, projectNamespaces, projectDirectory, platform, context).ConfigureAwait(true); } finally { // Once we're done resetting focus the REPL window. ExecutionCompleted?.Invoke(this, new EventArgs()); } } } private async Task ResetInteractiveAsync( IInteractiveWindow interactiveWindow, ImmutableArray<string> referencePaths, ImmutableArray<string> referenceSearchPaths, ImmutableArray<string> sourceSearchPaths, ImmutableArray<string> projectNamespaces, string projectDirectory, InteractiveHostPlatform? platform, IUIThreadOperationContext uiThreadOperationContext) { // First, open the repl window. var evaluator = (IResettableInteractiveEvaluator)interactiveWindow.Evaluator; // If the user hits the cancel button on the wait indicator, then we want to stop the // build. using (uiThreadOperationContext.UserCancellationToken.Register(() => CancelBuildProject(), useSynchronizationContext: true)) { // First, start a build. // If the build fails do not reset the REPL. var builtSuccessfully = await BuildProjectAsync().ConfigureAwait(true); if (!builtSuccessfully) { return; } } // Then reset the REPL using var scope = uiThreadOperationContext.AddScope(allowCancellation: true, EditorFeaturesWpfResources.Resetting_Interactive); evaluator.ResetOptions = new InteractiveEvaluatorResetOptions(platform); await interactiveWindow.Operations.ResetAsync(initialize: true).ConfigureAwait(true); // TODO: load context from an rsp file. // Now send the reference paths we've collected to the repl. await evaluator.SetPathsAsync(referenceSearchPaths, sourceSearchPaths, projectDirectory).ConfigureAwait(true); var editorOptions = _editorOptionsService.Factory.GetOptions(interactiveWindow.CurrentLanguageBuffer); var importReferencesCommand = referencePaths.Select(_createReference); await interactiveWindow.SubmitAsync(importReferencesCommand).ConfigureAwait(true); // Project's default namespace might be different from namespace used within project. // Filter out namespace imports that do not exist in interactive compilation. var namespacesToImport = await GetNamespacesToImportAsync(projectNamespaces, interactiveWindow).ConfigureAwait(true); var importNamespacesCommand = namespacesToImport.Select(_createImport).Join(editorOptions.GetNewLineCharacter()); if (!string.IsNullOrWhiteSpace(importNamespacesCommand)) { await interactiveWindow.SubmitAsync([importNamespacesCommand]).ConfigureAwait(true); } } protected abstract Task<IEnumerable<string>> GetNamespacesToImportAsync(IEnumerable<string> namespacesToImport, IInteractiveWindow interactiveWindow); /// <summary> /// Gets the properties of the currently selected projects necessary for reset. /// </summary> protected abstract bool GetProjectProperties( out ImmutableArray<string> references, out ImmutableArray<string> referenceSearchPaths, out ImmutableArray<string> sourceSearchPaths, out ImmutableArray<string> projectNamespaces, out string projectDirectory, out InteractiveHostPlatform? platform); /// <summary> /// A method that should trigger an async project build. /// </summary> /// <returns>Whether or not the build was successful.</returns> protected abstract Task<bool> BuildProjectAsync(); /// <summary> /// A method that should trigger a project cancellation. /// </summary> protected abstract void CancelBuildProject(); protected abstract IUIThreadOperationExecutor GetUIThreadOperationExecutor(); }