/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/VisualStudio/Core/Def/ValueTracking/ValueTrackingCommandHandler.cs
203 строки
9 KB
Cyrus Najmabadi
Make sealed
26 мар 2025, 22:21
26 мар 2025, 22:21
d99b771
Код
Авторство
О чём код?
// 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.Collections.Immutable; using System.ComponentModel.Composition; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.ValueTracking; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.LanguageServices.Setup; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Text.Classification; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Utilities; using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider; using Task = System.Threading.Tasks.Task; namespace Microsoft.VisualStudio.LanguageServices.ValueTracking; [Export(typeof(ICommandHandler))] [ContentType(ContentTypeNames.RoslynContentType)] [Name(PredefinedCommandHandlerNames.ShowValueTracking)] internal sealed class ValueTrackingCommandHandler : ICommandHandler<ValueTrackingEditorCommandArgs> { private readonly IAsyncServiceProvider _serviceProvider; private readonly IThreadingContext _threadingContext; private readonly ClassificationTypeMap _typeMap; private readonly IClassificationFormatMapService _classificationFormatMapService; private readonly IGlyphService _glyphService; private readonly IEditorFormatMapService _formatMapService; private readonly IGlobalOptionService _globalOptions; private readonly IUIThreadOperationExecutor _threadOperationExecutor; private readonly IAsynchronousOperationListener _listener; private readonly Workspace _workspace; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public ValueTrackingCommandHandler( SVsServiceProvider serviceProvider, IThreadingContext threadingContext, ClassificationTypeMap typeMap, IClassificationFormatMapService classificationFormatMapService, IGlyphService glyphService, IEditorFormatMapService formatMapService, IGlobalOptionService globalOptions, IAsynchronousOperationListenerProvider listenerProvider, IUIThreadOperationExecutor threadOperationExecutor, VisualStudioWorkspace workspace) { _serviceProvider = (IAsyncServiceProvider)serviceProvider; _threadingContext = threadingContext; _typeMap = typeMap; _classificationFormatMapService = classificationFormatMapService; _glyphService = glyphService; _formatMapService = formatMapService; _globalOptions = globalOptions; _threadOperationExecutor = threadOperationExecutor; _listener = listenerProvider.GetListener(FeatureAttribute.ValueTracking); _workspace = workspace; } public string DisplayName => "Go to value tracking"; public CommandState GetCommandState(ValueTrackingEditorCommandArgs args) => CommandState.Available; public bool ExecuteCommand(ValueTrackingEditorCommandArgs args, CommandExecutionContext executionContext) { using var logger = Logger.LogBlock(FunctionId.ValueTracking_Command, CancellationToken.None, LogLevel.Information); var cancellationToken = executionContext.OperationContext.UserCancellationToken; var caretPosition = args.TextView.GetCaretPoint(args.SubjectBuffer); if (!caretPosition.HasValue) { return false; } var textSpan = new TextSpan(caretPosition.Value.Position, 0); var sourceTextContainer = args.SubjectBuffer.AsTextContainer(); var document = sourceTextContainer.GetOpenDocumentInCurrentContext(); if (document is null) { return false; } _threadingContext.JoinableTaskFactory.RunAsync(async () => { var service = document.Project.Solution.Services.GetRequiredService<IValueTrackingService>(); var items = await service.TrackValueSourceAsync(textSpan, document, cancellationToken).ConfigureAwait(false); if (items.Length == 0) { return; } await ShowToolWindowAsync(args.TextView, document, items, cancellationToken).ConfigureAwait(false); }); return true; } private async Task ShowToolWindowAsync(ITextView textView, Document document, ImmutableArray<ValueTrackedItem> items, CancellationToken cancellationToken) { var toolWindow = await GetOrCreateToolWindowAsync(textView, cancellationToken).ConfigureAwait(false); if (toolWindow?.ViewModel is null) { return; } var classificationFormatMap = _classificationFormatMapService.GetClassificationFormatMap(textView); var solution = document.Project.Solution; var valueTrackingService = solution.Services.GetRequiredService<IValueTrackingService>(); var rootItemMap = items.GroupBy(i => i.Parent, resultSelector: (key, items) => (parent: key, children: items)); using var _ = CodeAnalysis.PooledObjects.ArrayBuilder<TreeItemViewModel>.GetInstance(out var rootItems); foreach (var (parent, children) in rootItemMap) { if (parent is null) { foreach (var child in children) { var root = await ValueTrackedTreeItemViewModel.CreateAsync( solution, child, children: [], toolWindow.ViewModel, _glyphService, valueTrackingService, _globalOptions, _threadingContext, _listener, _threadOperationExecutor, cancellationToken).ConfigureAwait(false); rootItems.Add(root); } } else { using var _1 = CodeAnalysis.PooledObjects.ArrayBuilder<TreeItemViewModel>.GetInstance(out var childItems); foreach (var child in children) { var childViewModel = await ValueTrackedTreeItemViewModel.CreateAsync( solution, child, children: [], toolWindow.ViewModel, _glyphService, valueTrackingService, _globalOptions, _threadingContext, _listener, _threadOperationExecutor, cancellationToken).ConfigureAwait(false); childItems.Add(childViewModel); } var root = await ValueTrackedTreeItemViewModel.CreateAsync( solution, parent, childItems.ToImmutable(), toolWindow.ViewModel, _glyphService, valueTrackingService, _globalOptions, _threadingContext, _listener, _threadOperationExecutor, cancellationToken).ConfigureAwait(false); rootItems.Add(root); } } await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); toolWindow.ViewModel.Roots.Clear(); foreach (var root in rootItems) { toolWindow.ViewModel.Roots.Add(root); } await ShowToolWindowAsync(cancellationToken).ConfigureAwait(true); } private async Task ShowToolWindowAsync(CancellationToken cancellationToken) { var roslynPackage = await RoslynPackage.GetOrLoadAsync(_threadingContext, _serviceProvider, cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(roslynPackage); await roslynPackage.ShowToolWindowAsync( typeof(ValueTrackingToolWindow), 0, true, roslynPackage.DisposalToken).ConfigureAwait(false); } private async Task<ValueTrackingToolWindow?> GetOrCreateToolWindowAsync(ITextView textView, CancellationToken cancellationToken) { var roslynPackage = await RoslynPackage.GetOrLoadAsync(_threadingContext, _serviceProvider, cancellationToken).ConfigureAwait(false); if (roslynPackage is null) { return null; } var window = (ValueTrackingToolWindow)await roslynPackage.FindWindowPaneAsync( typeof(ValueTrackingToolWindow), 0, create: true, roslynPackage.DisposalToken).ConfigureAwait(false); await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); if (!window.Initialized) { var viewModel = new ValueTrackingTreeViewModel(_classificationFormatMapService.GetClassificationFormatMap(textView), _typeMap, _formatMapService); window.Initialize(viewModel, _workspace, _threadingContext); } return window; } }