/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowProvider.cs
189 строк
8 KB
Cyrus Najmabadi
Use args
12 апр 2025, 07:50
12 апр 2025, 07:50
ce7c5fe
Код
Авторство
О чём код?
// 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.Diagnostics; using System.Linq; using InteractiveHost::Microsoft.CodeAnalysis.Interactive; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Interactive; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.VisualStudio.InteractiveWindow.Commands; using Microsoft.VisualStudio.InteractiveWindow.Shell; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text.Classification; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Utilities; using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Interactive; internal abstract class VsInteractiveWindowProvider { private readonly IVsInteractiveWindowFactory _vsInteractiveWindowFactory; private readonly SVsServiceProvider _vsServiceProvider; private readonly VisualStudioWorkspace _vsWorkspace; private readonly IViewClassifierAggregatorService _classifierAggregator; private readonly IContentTypeRegistryService _contentTypeRegistry; // TODO: support multi-instance windows // single instance of the Interactive Window private IVsInteractiveWindow _vsInteractiveWindow; public VsInteractiveWindowProvider( SVsServiceProvider serviceProvider, IVsInteractiveWindowFactory interactiveWindowFactory, IViewClassifierAggregatorService classifierAggregator, IContentTypeRegistryService contentTypeRegistry, IInteractiveWindowCommandsFactory commandsFactory, IInteractiveWindowCommand[] commands, VisualStudioWorkspace workspace) { _vsServiceProvider = serviceProvider; _classifierAggregator = classifierAggregator; _contentTypeRegistry = contentTypeRegistry; _vsWorkspace = workspace; Commands = GetApplicableCommands(commands, coreContentType: PredefinedInteractiveCommandsContentTypes.InteractiveCommandContentTypeName, specializedContentType: InteractiveWindowContentTypes.CommandContentTypeName); _vsInteractiveWindowFactory = interactiveWindowFactory; CommandsFactory = commandsFactory; } protected abstract CSharpInteractiveEvaluator CreateInteractiveEvaluator( SVsServiceProvider serviceProvider, IViewClassifierAggregatorService classifierAggregator, IContentTypeRegistryService contentTypeRegistry, VisualStudioWorkspace workspace); protected abstract Guid LanguageServiceGuid { get; } protected abstract Guid Id { get; } protected abstract string Title { get; } protected abstract FunctionId InteractiveWindowFunctionId { get; } protected IInteractiveWindowCommandsFactory CommandsFactory { get; } protected ImmutableArray<IInteractiveWindowCommand> Commands { get; } public void Create(int instanceId) { var evaluator = CreateInteractiveEvaluator(_vsServiceProvider, _classifierAggregator, _contentTypeRegistry, _vsWorkspace); Debug.Assert(_vsInteractiveWindow == null); // ForceCreate means that the window should be created if the persisted layout indicates that it is visible. _vsInteractiveWindow = _vsInteractiveWindowFactory.Create(Id, instanceId, Title, evaluator, __VSCREATETOOLWIN.CTW_fForceCreate); _vsInteractiveWindow.SetLanguage(LanguageServiceGuid, evaluator.ContentType); if (_vsInteractiveWindow is ToolWindowPane interactiveWindowPane) { var defaultPlatform = evaluator.ResetOptions.Platform; Contract.ThrowIfFalse(defaultPlatform.HasValue); interactiveWindowPane.Caption = Title + GetFrameworkForTitle(defaultPlatform.Value); evaluator.OnBeforeReset += platform => interactiveWindowPane.Caption = Title + GetFrameworkForTitle(platform); } var window = _vsInteractiveWindow.InteractiveWindow; window.TextView.Options.SetOptionValue(DefaultTextViewHostOptions.SuggestionMarginId, true); void closeEventDelegate(object sender, EventArgs e) { window.TextView.Closed -= closeEventDelegate; LogCloseSession(evaluator.SubmissionCount); evaluator.Dispose(); } // the tool window now owns the engine: window.TextView.Closed += closeEventDelegate; // vsWindow.AutoSaveOptions = true; // fire and forget: window.InitializeAsync(); LogSession(LogMessage.Window, LogMessage.Create); static string GetFrameworkForTitle(InteractiveHostPlatform platform) => platform switch { InteractiveHostPlatform.Desktop64 => " (.NET Framework " + ServicesVSResources.Bitness64 + ")", InteractiveHostPlatform.Desktop32 => " (.NET Framework " + ServicesVSResources.Bitness32 + ")", InteractiveHostPlatform.Core => " (.NET Core)", _ => throw ExceptionUtilities.Unreachable() }; } public IVsInteractiveWindow Open(int instanceId, bool focus) { // TODO: we don't support multi-instance yet Debug.Assert(instanceId == 0); if (_vsInteractiveWindow == null) { Create(instanceId); } _vsInteractiveWindow.Show(focus); return _vsInteractiveWindow; } protected void LogSession(string key, string value) => Logger.Log(InteractiveWindowFunctionId, KeyValueLogMessage.Create( static (m, args) => m.Add(args.key, args.value), (key, value))); private void LogCloseSession(int languageBufferCount) { Logger.Log(InteractiveWindowFunctionId, KeyValueLogMessage.Create(static (m, languageBufferCount) => { m.Add(LogMessage.Window, LogMessage.Close); m.Add(LogMessage.LanguageBufferCount, languageBufferCount); }, languageBufferCount)); } private static ImmutableArray<IInteractiveWindowCommand> GetApplicableCommands(IInteractiveWindowCommand[] commands, string coreContentType, string specializedContentType) { // get all commands of coreContentType - generic interactive window commands var interactiveCommands = commands.Where( c => c.GetType().GetCustomAttributes(typeof(ContentTypeAttribute), inherit: true).Any( a => ((ContentTypeAttribute)a).ContentTypes == coreContentType)).ToArray(); // get all commands of specializedContentType - smart C#/VB command implementations var specializedInteractiveCommands = commands.Where( c => c.GetType().GetCustomAttributes(typeof(ContentTypeAttribute), inherit: true).Any( a => ((ContentTypeAttribute)a).ContentTypes == specializedContentType)).ToArray(); // We should choose specialized C#/VB commands over generic core interactive window commands // Build a map of names and associated core command first var interactiveCommandMap = new Dictionary<string, int>(); for (var i = 0; i < interactiveCommands.Length; i++) { foreach (var name in interactiveCommands[i].Names) { interactiveCommandMap.Add(name, i); } } // swap core commands with specialized command if both exist // Command can have multiple names. We need to compare every name to find match. foreach (var command in specializedInteractiveCommands) { foreach (var name in command.Names) { if (interactiveCommandMap.TryGetValue(name, out var value)) { interactiveCommands[value] = command; break; } } } return [.. interactiveCommands]; } }