/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/EditorFeatures/Core/EncapsulateField/AbstractEncapsulateFieldCommandHandler.cs
138 строк
6 KB
Cyrus Najmabadi
Switch to lock instead
10 окт 2025, 16:48
10 окт 2025, 16:48
0466900
Код
Авторство
О чём код?
// 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.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.BackgroundWorkIndicator; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Microsoft.VisualStudio.Text.Operations; namespace Microsoft.CodeAnalysis.EncapsulateField; internal abstract class AbstractEncapsulateFieldCommandHandler( IThreadingContext threadingContext, ITextBufferUndoManagerProvider undoManager, IAsynchronousOperationListenerProvider listenerProvider) : ICommandHandler<EncapsulateFieldCommandArgs> { private readonly IThreadingContext _threadingContext = threadingContext; private readonly ITextBufferUndoManagerProvider _undoManager = undoManager; private readonly IAsynchronousOperationListener _listener = listenerProvider.GetListener(FeatureAttribute.EncapsulateField); public string DisplayName => EditorFeaturesResources.Encapsulate_Field; public CommandState GetCommandState(EncapsulateFieldCommandArgs args) => args.SubjectBuffer.SupportsRefactorings() ? CommandState.Available : CommandState.Unspecified; public bool ExecuteCommand(EncapsulateFieldCommandArgs args, CommandExecutionContext context) { var textBuffer = args.SubjectBuffer; if (!textBuffer.SupportsRefactorings()) return false; var spans = args.TextView.Selection.GetSnapshotSpansOnBuffer(textBuffer); if (spans.Count != 1) return false; var document = args.SubjectBuffer.AsTextContainer().GetOpenDocumentInCurrentContext(); if (document == null) return false; // Fire and forget var token = _listener.BeginAsyncOperation(FeatureAttribute.EncapsulateField); _ = ExecuteAsync(args, document, spans.Single()).CompletesAsyncOperation(token); return true; } private async Task ExecuteAsync( EncapsulateFieldCommandArgs args, Document initialDocument, SnapshotSpan span) { _threadingContext.ThrowIfNotOnUIThread(); var subjectBuffer = args.SubjectBuffer; var workspace = initialDocument.Project.Solution.Workspace; var indicatorFactory = workspace.Services.GetRequiredService<IBackgroundWorkIndicatorFactory>(); using var context = indicatorFactory.Create( args.TextView, span, EditorFeaturesResources.Computing_Encapsulate_Field_information, cancelOnEdit: true, cancelOnFocusLost: true); var cancellationToken = context.UserCancellationToken; var document = await subjectBuffer.CurrentSnapshot.GetFullyLoadedOpenDocumentInCurrentContextWithChangesAsync(context).ConfigureAwait(false); Contract.ThrowIfNull(document); var service = document.GetRequiredLanguageService<IEncapsulateFieldService>(); var result = await service.EncapsulateFieldsInSpanAsync( document, span.Span.ToTextSpan(), useDefaultBehavior: true, cancellationToken).ConfigureAwait(false); if (result == null) { await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); // We are about to show a modal UI dialog so we should take over the command execution // wait context. That means the command system won't attempt to show its own wait dialog // and also will take it into consideration when measuring command handling duration. context.TakeOwnership(); var notificationService = workspace.Services.GetRequiredService<INotificationService>(); notificationService.SendNotification(EditorFeaturesResources.Please_select_the_definition_of_the_field_to_encapsulate, severity: NotificationSeverity.Error); return; } await ApplyChangeAsync(subjectBuffer, document, result, cancellationToken).ConfigureAwait(false); } private async Task ApplyChangeAsync( ITextBuffer subjectBuffer, Document document, EncapsulateFieldResult result, CancellationToken cancellationToken) { var finalSolution = await result.GetSolutionAsync(cancellationToken).ConfigureAwait(false); var solution = document.Project.Solution; var workspace = solution.Workspace; var previewService = workspace.Services.GetService<IPreviewDialogService>(); if (previewService != null) { await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); finalSolution = previewService.PreviewChanges( string.Format(EditorFeaturesResources.Preview_Changes_0, EditorFeaturesResources.Encapsulate_Field), "vs.csharp.refactoring.preview", EditorFeaturesResources.Encapsulate_Field_colon, result.Name, result.Glyph, finalSolution, solution); } if (finalSolution == null) { // User clicked cancel. return; } using var undoTransaction = _undoManager.GetTextBufferUndoManager(subjectBuffer).TextBufferUndoHistory.CreateTransaction(EditorFeaturesResources.Encapsulate_Field); if (workspace.TryApplyChanges(finalSolution)) { undoTransaction.Complete(); } else { undoTransaction.Cancel(); } } }