From a540480bcc8b34b74bced5039b387ba8f625301d Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 14 Aug 2024 11:48:04 -0700 Subject: [PATCH 01/59] Link the cancellationToken --- .../Core/InlineRename/InlineRenameSession.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 55933f7fc5e81..48cba39334946 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -780,7 +780,7 @@ private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackg _triggerView, TriggerSpan, EditorFeaturesResources.Computing_Rename_information, cancelOnEdit: false, cancelOnFocusLost: false); - await CommitCoreAsync(context, previewChanges).ConfigureAwait(true); + await CommitCoreAsync(context, previewChanges, cancellationToken).ConfigureAwait(true); } else { @@ -793,7 +793,7 @@ private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackg // .ConfigureAwait(true); so we can return to the UI thread to dispose the operation context. It // has a non-JTF threading dependency on the main thread. So it can deadlock if you call it on a BG // thread when in a blocking JTF call. - await CommitCoreAsync(context, previewChanges).ConfigureAwait(true); + await CommitCoreAsync(context, previewChanges, cancellationToken).ConfigureAwait(true); } } catch (OperationCanceledException) @@ -806,13 +806,14 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( return true; } - private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, bool previewChanges) + private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, bool previewChanges, CancellationToken cancellationToken) { - var cancellationToken = operationContext.UserCancellationToken; + using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(operationContext.UserCancellationToken, cancellationToken); + var linkedCancellationToken = operationContext.UserCancellationToken; var eventName = previewChanges ? FunctionId.Rename_CommitCoreWithPreview : FunctionId.Rename_CommitCore; - using (Logger.LogBlock(eventName, KeyValueLogMessage.Create(LogType.UserAction), cancellationToken)) + using (Logger.LogBlock(eventName, KeyValueLogMessage.Create(LogType.UserAction), linkedCancellationToken)) { - var info = await _conflictResolutionTask.JoinAsync(cancellationToken).ConfigureAwait(true); + var info = await _conflictResolutionTask.JoinAsync(linkedCancellationToken).ConfigureAwait(true); var newSolution = info.NewSolution; if (previewChanges) @@ -820,7 +821,7 @@ private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, b var previewService = Workspace.Services.GetService(); // The preview service needs to be called from the UI thread, since it's doing COM calls underneath. - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(linkedCancellationToken); newSolution = previewService.PreviewChanges( string.Format(EditorFeaturesResources.Preview_Changes_0, EditorFeaturesResources.Rename), "vs.csharp.refactoring.rename", @@ -844,11 +845,11 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( RenameLogMessage.UserActionOutcome.Committed, previewChanges, async () => { - var error = await TryApplyRenameAsync(newSolution, cancellationToken).ConfigureAwait(false); + var error = await TryApplyRenameAsync(newSolution, linkedCancellationToken).ConfigureAwait(false); if (error is not null) { - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(linkedCancellationToken); var notificationService = Workspace.Services.GetService(); notificationService.SendNotification( error.Value.message, EditorFeaturesResources.Rename_Symbol, error.Value.severity); From 09cc8e78d8959c6feb5918dd8aef3808b0e67e8c Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 14 Aug 2024 13:20:05 -0700 Subject: [PATCH 02/59] Add another entry --- .../Core/InlineRename/InlineRenameSession.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 48cba39334946..b919a860765bc 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -723,6 +723,18 @@ void DismissUIAndRollbackEdits() } } + public async Task CommitXAsync(bool previewChanges, bool forceCommitSynchronously, CancellationToken cancellationToken) + { + if (!forceCommitSynchronously && this.RenameService.GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameAsynchronously)) + { + await CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: true, cancellationToken).ConfigureAwait(false); + } + else + { + return _threadingContext.JoinableTaskFactory.Run(() => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: false, cancellationToken)); + } + } + public void Commit(bool previewChanges = false) => CommitWorker(previewChanges); From d033ed50b2119ece74dcf7ac52052aea3bc40dc1 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 14 Aug 2024 13:48:31 -0700 Subject: [PATCH 03/59] Revise the meaning of rename async option --- src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index b919a860765bc..f49f673596606 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -727,7 +727,7 @@ public async Task CommitXAsync(bool previewChanges, bool forceCommitSynchr { if (!forceCommitSynchronously && this.RenameService.GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameAsynchronously)) { - await CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: true, cancellationToken).ConfigureAwait(false); + return await CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: true, cancellationToken).ConfigureAwait(false); } else { @@ -747,7 +747,7 @@ private bool CommitWorker(bool previewChanges) // which at least will allow the user to cancel the rename if they want. // // In the future we should remove this entrypoint and have all callers use CommitAsync instead. - return _threadingContext.JoinableTaskFactory.Run(() => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: false, CancellationToken.None)); + return _threadingContext.JoinableTaskFactory.Run(() => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: true, CancellationToken.None)); } public Task CommitAsync(bool previewChanges, CancellationToken cancellationToken) @@ -780,7 +780,7 @@ private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackg try { - if (canUseBackgroundWorkIndicator && this.RenameService.GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameAsynchronously)) + if (canUseBackgroundWorkIndicator) { // We do not cancel on edit because as part of the rename system we have asynchronous work still // occurring that itself may be asynchronously editing the buffer (for example, updating reference From 0ad7ba7ad5b19a2e25c4c75bd3d3a30b98cbb615 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 14 Aug 2024 15:49:49 -0700 Subject: [PATCH 04/59] Link call --- .../InlineRename/UI/Adornment/RenameFlyoutViewModel.cs | 3 ++- .../Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs | 3 ++- src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index 20f2fe198a151..dfccf90f09ac5 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -9,6 +9,7 @@ using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; +using System.Threading; using System.Windows.Interop; using Microsoft.CodeAnalysis.Editor.InlineRename; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; @@ -216,7 +217,7 @@ public bool Submit() } SmartRenameViewModel?.Commit(IdentifierText); - Session.Commit(); + _ = Session.CommitXAsync(previewChanges: false, forceCommitSynchronously: false, cancellationToken: CancellationToken.None); return true; } diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs index 482304aa00701..df2d81b90b076 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Windows; using System.Windows.Automation.Peers; using System.Windows.Controls; @@ -331,7 +332,7 @@ private void Commit() { try { - _model.Session.Commit(); + _ = _model.Session.CommitXAsync(previewChanges: false, forceCommitSynchronously: false, cancellationToken: CancellationToken.None); _textView.VisualElement.Focus(); } catch (NotSupportedException ex) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index f49f673596606..304edcbf33319 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -753,7 +753,7 @@ private bool CommitWorker(bool previewChanges) public Task CommitAsync(bool previewChanges, CancellationToken cancellationToken) => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: true, cancellationToken); - /// if the rename operation was commited, if the rename operation was committed, otherwise private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackgroundWorkIndicator, CancellationToken cancellationToken) { From 22881fefa64d62c0e6dd8a0dffcbe9ecb76b8d62 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 16 Aug 2024 11:29:10 -0700 Subject: [PATCH 05/59] Make it async in ExtractMethodCommandHandler --- .../ExtractMethodCommandHandler.cs | 18 ++++++++++-------- .../Core/IInlineRenameSession.cs | 2 ++ .../Core/InlineRename/InlineRenameSession.cs | 10 +++++++++- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs b/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs index 6d08010693760..e323b62d23124 100644 --- a/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs +++ b/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs @@ -84,13 +84,6 @@ public CommandState GetCommandState(ExtractMethodCommandArgs args) public bool ExecuteCommand(ExtractMethodCommandArgs args, CommandExecutionContext context) { - // Finish any rename that had been started. We'll do this here before we enter the - // wait indicator for Extract Method - if (_renameService.ActiveSession != null) - { - _threadingContext.JoinableTaskFactory.Run(() => _renameService.ActiveSession.CommitAsync(previewChanges: false, CancellationToken.None)); - } - if (!args.SubjectBuffer.SupportsRefactorings()) return false; @@ -106,7 +99,7 @@ public bool ExecuteCommand(ExtractMethodCommandArgs args, CommandExecutionContex if (document is null) return false; - _ = ExecuteAsync(view, textBuffer, document, span); + _ = ExecuteAsync(view, textBuffer, document, span).ReportNonFatalErrorAsync(); return true; } @@ -117,6 +110,15 @@ private async Task ExecuteAsync( SnapshotSpan span) { _threadingContext.ThrowIfNotOnUIThread(); + + // Finish any rename that had been started. We'll do this here before we enter the + // wait indicator for Extract Method + if (_renameService.ActiveSession != null) + { + // ConfigureAwait(true) to make sure the next wait indicator would be created correctly. + await _renameService.ActiveSession.CommitXAsync(previewChanges: false, forceCommitSynchronously: false, CancellationToken.None).ConfigureAwait(true); + } + var indicatorFactory = document.Project.Solution.Services.GetRequiredService(); using var indicatorContext = indicatorFactory.Create( view, span, EditorFeaturesResources.Applying_Extract_Method_refactoring, cancelOnEdit: true, cancelOnFocusLost: true); diff --git a/src/EditorFeatures/Core/IInlineRenameSession.cs b/src/EditorFeatures/Core/IInlineRenameSession.cs index 3ae70a4d091a2..f5bf187ad6ef1 100644 --- a/src/EditorFeatures/Core/IInlineRenameSession.cs +++ b/src/EditorFeatures/Core/IInlineRenameSession.cs @@ -51,4 +51,6 @@ internal interface IInlineRenameSession /// Dismisses the rename session, completing the rename operation across all files. /// Task CommitAsync(bool previewChanges, CancellationToken cancellationToken); + + Task CommitXAsync(bool previewChanges, bool forceCommitSynchronously, CancellationToken cancellationToken); } diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 304edcbf33319..a591e5fddab45 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -778,8 +778,11 @@ private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackg previewChanges = previewChanges || PreviewChanges; + var prohibitUserInputValue = _triggerView.Options.GetOptionValue(DefaultTextViewOptions.ViewProhibitUserInputName); + try { + _triggerView.Options.SetOptionValue(DefaultTextViewOptions.ViewProhibitUserInputName, true); if (canUseBackgroundWorkIndicator) { // We do not cancel on edit because as part of the rename system we have asynchronous work still @@ -811,9 +814,14 @@ private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackg catch (OperationCanceledException) { await DismissUIAndRollbackEditsAndEndRenameSessionAsync( - RenameLogMessage.UserActionOutcome.Canceled | RenameLogMessage.UserActionOutcome.Committed, previewChanges).ConfigureAwait(false); + RenameLogMessage.UserActionOutcome.Canceled | RenameLogMessage.UserActionOutcome.Committed, + previewChanges).ConfigureAwait(false); return false; } + finally + { + _triggerView.Options.SetOptionValue(DefaultTextViewOptions.ViewProhibitUserInputName, prohibitUserInputValue); + } return true; } From 51bac52356043dff272ba99f8c86f7d813ecf54c Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 16 Aug 2024 11:53:19 -0700 Subject: [PATCH 06/59] Update async in SaveHandler --- .../AbstractRenameCommandHandler_SaveHandler.cs | 3 ++- .../VisualBasicTest/LineCommit/CommitTestData.vb | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs index 4a9bb0c50b1e1..d799727a2cbd9 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs @@ -16,7 +16,8 @@ public bool ExecuteCommand(SaveCommandArgs args, CommandExecutionContext context { if (_renameService.ActiveSession != null) { - _renameService.ActiveSession.Commit(); + // Need to commit the rename session synchronously to make sure save command saves the changes from rename change. + _ = _renameService.ActiveSession.CommitXAsync(previewChanges: false, forceCommitSynchronously: true, context.OperationContext.UserCancellationToken); SetFocusToTextView(args.TextView); } diff --git a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb index 6443f03fd5b28..7a381540c0987 100644 --- a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb +++ b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb @@ -114,6 +114,10 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.LineCommit Public Function CommitAsync(previewChanges As Boolean, cancellationToken As CancellationToken) As Task Implements IInlineRenameSession.CommitAsync Throw New NotImplementedException() End Function + + Public Function CommitXAsync(previewChanges As Boolean, forceCommitSynchronously As Boolean, cancellationToken As CancellationToken) As Task(Of Boolean) Implements IInlineRenameSession.CommitXAsync + Throw New NotImplementedException + End Function End Class End Class From f6014e1cc84de0b7311ce14f88d4e39fc55e6afe Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 16 Aug 2024 12:00:54 -0700 Subject: [PATCH 07/59] Update async in ReturnKey Handler --- .../AbstractRenameCommandHandler_ReturnHandler.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs index 5cb04c3f18579..957f9e9fbf5a6 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs @@ -2,9 +2,12 @@ // 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.Threading; +using System.Threading.Tasks; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename; @@ -18,19 +21,18 @@ public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext co if (_renameService.ActiveSession != null) { // Prevent Editor's typing responsiveness auto canceling the rename operation. - // InlineRenameSession will call IUIThreadOperationExecutor to sets up our own IUIThreadOperationContext + // InlineRenameSession will call IBackgroundWorkIndicator to sets up our own IUIThreadOperationContext context.OperationContext.TakeOwnership(); - - Commit(_renameService.ActiveSession, args.TextView); + _ = CommitAndSetFocusAsync(_renameService.ActiveSession, args.TextView, CancellationToken.None).ReportNonFatalErrorAsync(); return true; } return false; } - protected virtual void Commit(InlineRenameSession activeSession, ITextView textView) + private async Task CommitAndSetFocusAsync(InlineRenameSession activeSession, ITextView textView, CancellationToken cancellationToken) { - activeSession.Commit(); + await activeSession.CommitXAsync(previewChanges: false, forceCommitSynchronously: false, cancellationToken).ConfigureAwait(true); SetFocusToTextView(textView); } } From 02ebbc2c9252a5e7400bdf59abe6d510a7862cf3 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 16 Aug 2024 13:48:52 -0700 Subject: [PATCH 08/59] Update async in RenameHandler --- .../CommandHandlers/RenameCommandHandler.cs | 7 +++++-- .../AbstractRenameCommandHandler_RenameHandler.cs | 15 ++++++++------- .../AbstractRenameCommandHandler_ReturnHandler.cs | 2 +- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs index 57f249768fa80..d99b07484b468 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs @@ -5,6 +5,8 @@ using System; using System.ComponentModel.Composition; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.Commanding; @@ -94,11 +96,12 @@ protected override void SetAdornmentFocusToPreviousElement(ITextView textView) } } - protected override void Commit(InlineRenameSession activeSession, ITextView textView) + + protected override async Task CommitAndSetFocusAsync(InlineRenameSession activeSession, ITextView textView, CancellationToken cancellationToken) { try { - base.Commit(activeSession, textView); + await base.CommitAndSetFocusAsync(activeSession, textView, cancellationToken).ConfigureAwait(false); } catch (NotSupportedException ex) { diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs index 25d0fb76612a0..7bfb6ad08fd0d 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs @@ -5,6 +5,7 @@ #nullable disable using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.BackgroundWorkIndicator; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; @@ -63,12 +64,6 @@ private async Task ExecuteCommandAsync(RenameCommandArgs args) return; } - var backgroundWorkIndicatorFactory = workspace.Services.GetRequiredService(); - using var context = backgroundWorkIndicatorFactory.Create( - args.TextView, - args.TextView.GetTextElementSpan(caretPoint.Value), - EditorFeaturesResources.Finding_token_to_rename); - // If there is already an active session, commit it first if (_renameService.ActiveSession != null) { @@ -82,10 +77,16 @@ private async Task ExecuteCommandAsync(RenameCommandArgs args) else { // Otherwise, commit the existing session and start a new one. - _renameService.ActiveSession.Commit(); + await _renameService.ActiveSession.CommitXAsync(previewChanges: false, forceCommitSynchronously: false, CancellationToken.None).ConfigureAwait(true); } } + var backgroundWorkIndicatorFactory = workspace.Services.GetRequiredService(); + using var context = backgroundWorkIndicatorFactory.Create( + args.TextView, + args.TextView.GetTextElementSpan(caretPoint.Value), + EditorFeaturesResources.Finding_token_to_rename); + var cancellationToken = context.UserCancellationToken; var document = await args diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs index 957f9e9fbf5a6..53e4ce6cdcb6b 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs @@ -30,7 +30,7 @@ public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext co return false; } - private async Task CommitAndSetFocusAsync(InlineRenameSession activeSession, ITextView textView, CancellationToken cancellationToken) + protected virtual async Task CommitAndSetFocusAsync(InlineRenameSession activeSession, ITextView textView, CancellationToken cancellationToken) { await activeSession.CommitXAsync(previewChanges: false, forceCommitSynchronously: false, cancellationToken).ConfigureAwait(true); SetFocusToTextView(textView); From e87179ceb77d1a41f5f9b43358c045972e91eea0 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 16 Aug 2024 13:58:34 -0700 Subject: [PATCH 09/59] Update in openline above --- .../AbstractRenameCommandHandler_OpenLineAboveHandler.cs | 3 ++- .../AbstractRenameCommandHandler_OpenLineBelowHandler.cs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs index 6670627524316..134d8421b2c64 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Threading; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; @@ -17,7 +18,7 @@ public void ExecuteCommand(OpenLineAboveCommandArgs args, Action nextHandler, Co { HandlePossibleTypingCommand(args, nextHandler, (activeSession, span) => { - activeSession.Commit(); + _ = activeSession.CommitXAsync(previewChanges: false, forceCommitSynchronously: true, CancellationToken.None); nextHandler(); }); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs index e8649fbf5577c..ac03e7cc39e6b 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Threading; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; @@ -17,7 +18,7 @@ public void ExecuteCommand(OpenLineBelowCommandArgs args, Action nextHandler, Co { HandlePossibleTypingCommand(args, nextHandler, (activeSession, span) => { - activeSession.Commit(); + _ = activeSession.CommitXAsync(previewChanges: false, forceCommitSynchronously: true, CancellationToken.None); nextHandler(); }); } From 879e7198e31f49bc5af0212bc567979cc741a25a Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 16 Aug 2024 14:02:06 -0700 Subject: [PATCH 10/59] Reset to sync --- .../AbstractRenameCommandHandler_OpenLineAboveHandler.cs | 2 +- .../AbstractRenameCommandHandler_OpenLineBelowHandler.cs | 2 +- .../AbstractRenameCommandHandler_SaveHandler.cs | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs index 134d8421b2c64..219a4b1d8c67a 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs @@ -18,7 +18,7 @@ public void ExecuteCommand(OpenLineAboveCommandArgs args, Action nextHandler, Co { HandlePossibleTypingCommand(args, nextHandler, (activeSession, span) => { - _ = activeSession.CommitXAsync(previewChanges: false, forceCommitSynchronously: true, CancellationToken.None); + activeSession.Commit(); nextHandler(); }); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs index ac03e7cc39e6b..226313dcb2cbb 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs @@ -18,7 +18,7 @@ public void ExecuteCommand(OpenLineBelowCommandArgs args, Action nextHandler, Co { HandlePossibleTypingCommand(args, nextHandler, (activeSession, span) => { - _ = activeSession.CommitXAsync(previewChanges: false, forceCommitSynchronously: true, CancellationToken.None); + activeSession.Commit(); nextHandler(); }); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs index d799727a2cbd9..4a9bb0c50b1e1 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs @@ -16,8 +16,7 @@ public bool ExecuteCommand(SaveCommandArgs args, CommandExecutionContext context { if (_renameService.ActiveSession != null) { - // Need to commit the rename session synchronously to make sure save command saves the changes from rename change. - _ = _renameService.ActiveSession.CommitXAsync(previewChanges: false, forceCommitSynchronously: true, context.OperationContext.UserCancellationToken); + _renameService.ActiveSession.Commit(); SetFocusToTextView(args.TextView); } From 0c6b511c997857c2c19f2b093d97bbb2fc3c35de Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 16 Aug 2024 14:06:41 -0700 Subject: [PATCH 11/59] Reset change --- .../UI/Adornment/RenameFlyoutViewModel.cs | 2 +- .../UI/Dashboard/RenameDashboard.xaml.cs | 2 +- .../ExtractMethodCommandHandler.cs | 2 +- .../Core/IInlineRenameSession.cs | 2 -- ...tractRenameCommandHandler_RenameHandler.cs | 2 +- ...tractRenameCommandHandler_ReturnHandler.cs | 2 +- .../Core/InlineRename/InlineRenameSession.cs | 25 ++++++++----------- .../LineCommit/CommitTestData.vb | 4 --- 8 files changed, 16 insertions(+), 25 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index dfccf90f09ac5..f24e839cbb2ef 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -217,7 +217,7 @@ public bool Submit() } SmartRenameViewModel?.Commit(IdentifierText); - _ = Session.CommitXAsync(previewChanges: false, forceCommitSynchronously: false, cancellationToken: CancellationToken.None); + _ = Session.CommitAsync(previewChanges: false, cancellationToken: CancellationToken.None); return true; } diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs index df2d81b90b076..b19421d01db3e 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs @@ -332,7 +332,7 @@ private void Commit() { try { - _ = _model.Session.CommitXAsync(previewChanges: false, forceCommitSynchronously: false, cancellationToken: CancellationToken.None); + _ = _model.Session.CommitAsync(previewChanges: false, cancellationToken: CancellationToken.None); _textView.VisualElement.Focus(); } catch (NotSupportedException ex) diff --git a/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs b/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs index e323b62d23124..399d12000ac31 100644 --- a/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs +++ b/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs @@ -116,7 +116,7 @@ private async Task ExecuteAsync( if (_renameService.ActiveSession != null) { // ConfigureAwait(true) to make sure the next wait indicator would be created correctly. - await _renameService.ActiveSession.CommitXAsync(previewChanges: false, forceCommitSynchronously: false, CancellationToken.None).ConfigureAwait(true); + await _renameService.ActiveSession.CommitAsync(previewChanges: false, CancellationToken.None).ConfigureAwait(true); } var indicatorFactory = document.Project.Solution.Services.GetRequiredService(); diff --git a/src/EditorFeatures/Core/IInlineRenameSession.cs b/src/EditorFeatures/Core/IInlineRenameSession.cs index f5bf187ad6ef1..3ae70a4d091a2 100644 --- a/src/EditorFeatures/Core/IInlineRenameSession.cs +++ b/src/EditorFeatures/Core/IInlineRenameSession.cs @@ -51,6 +51,4 @@ internal interface IInlineRenameSession /// Dismisses the rename session, completing the rename operation across all files. /// Task CommitAsync(bool previewChanges, CancellationToken cancellationToken); - - Task CommitXAsync(bool previewChanges, bool forceCommitSynchronously, CancellationToken cancellationToken); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs index 7bfb6ad08fd0d..8ee3b8b06fb1e 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs @@ -77,7 +77,7 @@ private async Task ExecuteCommandAsync(RenameCommandArgs args) else { // Otherwise, commit the existing session and start a new one. - await _renameService.ActiveSession.CommitXAsync(previewChanges: false, forceCommitSynchronously: false, CancellationToken.None).ConfigureAwait(true); + await _renameService.ActiveSession.CommitAsync(previewChanges: false, CancellationToken.None).ConfigureAwait(true); } } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs index 53e4ce6cdcb6b..afc6a9b52d5bc 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs @@ -32,7 +32,7 @@ public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext co protected virtual async Task CommitAndSetFocusAsync(InlineRenameSession activeSession, ITextView textView, CancellationToken cancellationToken) { - await activeSession.CommitXAsync(previewChanges: false, forceCommitSynchronously: false, cancellationToken).ConfigureAwait(true); + await activeSession.CommitAsync(previewChanges: false, cancellationToken).ConfigureAwait(true); SetFocusToTextView(textView); } } diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index a591e5fddab45..2f244476d4f9d 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -723,18 +723,6 @@ void DismissUIAndRollbackEdits() } } - public async Task CommitXAsync(bool previewChanges, bool forceCommitSynchronously, CancellationToken cancellationToken) - { - if (!forceCommitSynchronously && this.RenameService.GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameAsynchronously)) - { - return await CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: true, cancellationToken).ConfigureAwait(false); - } - else - { - return _threadingContext.JoinableTaskFactory.Run(() => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: false, cancellationToken)); - } - } - public void Commit(bool previewChanges = false) => CommitWorker(previewChanges); @@ -750,8 +738,17 @@ private bool CommitWorker(bool previewChanges) return _threadingContext.JoinableTaskFactory.Run(() => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: true, CancellationToken.None)); } - public Task CommitAsync(bool previewChanges, CancellationToken cancellationToken) - => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: true, cancellationToken); + public async Task CommitAsync(bool previewChanges, CancellationToken cancellationToken) + { + if (this.RenameService.GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameAsynchronously)) + { + await CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: true, cancellationToken).ConfigureAwait(false); + } + else + { + Commit(previewChanges); + } + } /// if the rename operation was committed, otherwise diff --git a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb index 7a381540c0987..6443f03fd5b28 100644 --- a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb +++ b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb @@ -114,10 +114,6 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.LineCommit Public Function CommitAsync(previewChanges As Boolean, cancellationToken As CancellationToken) As Task Implements IInlineRenameSession.CommitAsync Throw New NotImplementedException() End Function - - Public Function CommitXAsync(previewChanges As Boolean, forceCommitSynchronously As Boolean, cancellationToken As CancellationToken) As Task(Of Boolean) Implements IInlineRenameSession.CommitXAsync - Throw New NotImplementedException - End Function End Class End Class From 5128476cec2297665b46d02f5613a3eb6367b30b Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 16 Aug 2024 14:20:14 -0700 Subject: [PATCH 12/59] Add test hook --- .../InlineRename/UI/Adornment/RenameFlyoutViewModel.cs | 6 +++++- .../InlineRename/UI/Dashboard/RenameDashboard.xaml.cs | 8 ++++++-- .../Core/InlineRename/InlineRenameSession.cs | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index f24e839cbb2ef..8be7c8a19e7d3 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -24,6 +24,7 @@ using Microsoft.VisualStudio.Imaging.Interop; using Microsoft.VisualStudio.PlatformUI.OleComponentSupport; using Microsoft.VisualStudio.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename { @@ -31,6 +32,7 @@ internal class RenameFlyoutViewModel : INotifyPropertyChanged, IDisposable { private readonly bool _registerOleComponent; private readonly IGlobalOptionService _globalOptionService; + private readonly IAsynchronousOperationListener _asyncListener; private OleComponent? _oleComponent; private bool _disposedValue; private bool _isReplacementTextValid = true; @@ -55,6 +57,7 @@ public RenameFlyoutViewModel( Session.ReferenceLocationsChanged += OnReferenceLocationsChanged; StartingSelection = selectionSpan; InitialTrackingSpan = session.TriggerSpan.CreateTrackingSpan(SpanTrackingMode.EdgeInclusive); + _asyncListener = listenerProvider.GetListener(FeatureAttribute.Rename); var smartRenameSession = smartRenameSessionFactory?.Value.CreateSmartRenameSession(Session.TriggerSpan); if (smartRenameSession is not null) { @@ -211,13 +214,14 @@ public bool IsRenameOverloadsVisible public bool Submit() { + using var token = _asyncListener.BeginAsyncOperation(nameof(Submit)); if (StatusSeverity == Severity.Error) { return false; } SmartRenameViewModel?.Commit(IdentifierText); - _ = Session.CommitAsync(previewChanges: false, cancellationToken: CancellationToken.None); + _ = Session.CommitAsync(previewChanges: false, cancellationToken: CancellationToken.None).ReportNonFatalErrorAsync(); return true; } diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs index b19421d01db3e..4f3925a59e030 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; +using System.Threading.Tasks; using System.Windows; using System.Windows.Automation.Peers; using System.Windows.Controls; @@ -19,6 +20,7 @@ using Microsoft.CodeAnalysis.Telemetry; using Microsoft.VisualStudio.Text.Classification; using Microsoft.VisualStudio.Text.Editor; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename { @@ -328,11 +330,13 @@ private void CloseButton_Click(object sender, RoutedEventArgs e) private void Apply_Click(object sender, RoutedEventArgs e) => Commit(); - private void Commit() + private void Commit() => _ = CommitAsync().ReportNonFatalErrorAsync(); + + private async Task CommitAsync() { try { - _ = _model.Session.CommitAsync(previewChanges: false, cancellationToken: CancellationToken.None); + await _model.Session.CommitAsync(previewChanges: false, cancellationToken: CancellationToken.None).ConfigureAwait(true); _textView.VisualElement.Focus(); } catch (NotSupportedException ex) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 2f244476d4f9d..54ce9c0654ae6 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -735,7 +735,7 @@ private bool CommitWorker(bool previewChanges) // which at least will allow the user to cancel the rename if they want. // // In the future we should remove this entrypoint and have all callers use CommitAsync instead. - return _threadingContext.JoinableTaskFactory.Run(() => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: true, CancellationToken.None)); + return _threadingContext.JoinableTaskFactory.Run(() => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: false, CancellationToken.None)); } public async Task CommitAsync(bool previewChanges, CancellationToken cancellationToken) From 51ca38e128b400f51901e10df0d43b950af2b169 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 16 Aug 2024 14:33:53 -0700 Subject: [PATCH 13/59] Reset --- .../Core/InlineRename/InlineRenameSession.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 54ce9c0654ae6..2688dd45d7073 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -775,11 +775,8 @@ private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackg previewChanges = previewChanges || PreviewChanges; - var prohibitUserInputValue = _triggerView.Options.GetOptionValue(DefaultTextViewOptions.ViewProhibitUserInputName); - try { - _triggerView.Options.SetOptionValue(DefaultTextViewOptions.ViewProhibitUserInputName, true); if (canUseBackgroundWorkIndicator) { // We do not cancel on edit because as part of the rename system we have asynchronous work still @@ -815,10 +812,6 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( previewChanges).ConfigureAwait(false); return false; } - finally - { - _triggerView.Options.SetOptionValue(DefaultTextViewOptions.ViewProhibitUserInputName, prohibitUserInputValue); - } return true; } From 0ec2779fc945e500c5a95fca2b4bd6ab48e7df8d Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 16 Aug 2024 14:35:05 -0700 Subject: [PATCH 14/59] Clean and remove usings --- .../AbstractRenameCommandHandler_OpenLineAboveHandler.cs | 1 - .../AbstractRenameCommandHandler_OpenLineBelowHandler.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs index 219a4b1d8c67a..6670627524316 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Threading; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs index 226313dcb2cbb..e8649fbf5577c 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Threading; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; From 55d45e4319beb2893ad1dd7592686ad6af41fd1f Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 16 Aug 2024 16:58:13 -0700 Subject: [PATCH 15/59] Avoid commit a same session twice --- .../Core/InlineRename/InlineRenameSession.cs | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 2688dd45d7073..4a99974b04ea6 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -124,7 +124,9 @@ private set /// /// The cancellation source for . /// - private CancellationTokenSource _conflictResolutionTaskCancellationSource = new CancellationTokenSource(); + private CancellationTokenSource _conflictResolutionTaskCancellationSource = new(); + + private Task _commitTask; /// /// The initial text being renamed. @@ -724,35 +726,38 @@ void DismissUIAndRollbackEdits() } public void Commit(bool previewChanges = false) - => CommitWorker(previewChanges); + => CommitSynchronously(previewChanges); /// if the rename operation was committed, otherwise - private bool CommitWorker(bool previewChanges) + private void CommitSynchronously(bool previewChanges) { // We're going to synchronously block the UI thread here. So we can't use the background work indicator (as // it needs the UI thread to update itself. This will force us to go through the Threaded-Wait-Dialog path // which at least will allow the user to cancel the rename if they want. // // In the future we should remove this entrypoint and have all callers use CommitAsync instead. - return _threadingContext.JoinableTaskFactory.Run(() => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: false, CancellationToken.None)); + _threadingContext.JoinableTaskFactory.Run(() => StartCommitAsync(previewChanges, CancellationToken.None)); } - public async Task CommitAsync(bool previewChanges, CancellationToken cancellationToken) + public Task CommitAsync(bool previewChanges, CancellationToken cancellationToken) + => StartCommitAsync(previewChanges, cancellationToken) + + private async Task StartCommitAsync(bool previewChanges, CancellationToken cancellationToken) { - if (this.RenameService.GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameAsynchronously)) - { - await CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: true, cancellationToken).ConfigureAwait(false); - } - else + if (_dismissed) { - Commit(previewChanges); + return; } + + _commitTask ??= CommitWorkerAsync(previewChanges, cancellationToken); + + await _commitTask.ConfigureAwait(false); } /// if the rename operation was committed, otherwise - private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackgroundWorkIndicator, CancellationToken cancellationToken) + private async Task CommitWorkerAsync(bool previewChanges, CancellationToken cancellationToken) { await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); VerifyNotDismissed(); @@ -777,7 +782,7 @@ private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackg try { - if (canUseBackgroundWorkIndicator) + if (this.RenameService.GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameAsynchronously)) { // We do not cancel on edit because as part of the rename system we have asynchronous work still // occurring that itself may be asynchronously editing the buffer (for example, updating reference @@ -986,6 +991,6 @@ public readonly struct TestAccessor(InlineRenameSession inlineRenameSession) private readonly InlineRenameSession _inlineRenameSession = inlineRenameSession; public bool CommitWorker(bool previewChanges) - => _inlineRenameSession.CommitWorker(previewChanges); + => _inlineRenameSession.CommitSynchronously(previewChanges); } } From 88ba81a9b0efd333eb2b53fbd470f407196de84b Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 16 Aug 2024 17:23:27 -0700 Subject: [PATCH 16/59] Cancel when background task is not completed --- .../Core/InlineRename/InlineRenameSession.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 4a99974b04ea6..90f43035d357b 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -395,6 +395,14 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs args) Cancel(); } + + if (args.Kind == WorkspaceChangeKind.DocumentChanged) + { + if (_conflictResolutionTask.Task.Status is not TaskStatus.RanToCompletion and not TaskStatus.Faulted) + { + Cancel(); + } + } } private void RaiseSessionSpansUpdated(ImmutableArray locations) @@ -741,17 +749,16 @@ private void CommitSynchronously(bool previewChanges) } public Task CommitAsync(bool previewChanges, CancellationToken cancellationToken) - => StartCommitAsync(previewChanges, cancellationToken) + => StartCommitAsync(previewChanges, cancellationToken); - private async Task StartCommitAsync(bool previewChanges, CancellationToken cancellationToken) + private async Task StartCommitAsync(bool previewChanges, CancellationToken cancellationToken) { if (_dismissed) { - return; + return false; } _commitTask ??= CommitWorkerAsync(previewChanges, cancellationToken); - await _commitTask.ConfigureAwait(false); } From 4f1a7e769b0169df465c4e628bdf33af9b0666f1 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 16 Aug 2024 20:49:05 -0700 Subject: [PATCH 17/59] Prevent input from user when commit in progress --- .../AbstractRenameCommandHandler.cs | 5 +++ .../Core/InlineRename/InlineRenameSession.cs | 39 ++++++++++--------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs index 3a54313a64f99..a30194f9813cf 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs @@ -64,6 +64,11 @@ private void HandlePossibleTypingCommand(TArgs args, Action nextHandler, return; } + if (_renameService.ActiveSession.IsCommitInProgress) + { + return; + } + var selectedSpans = args.TextView.Selection.GetSnapshotSpansOnBuffer(args.SubjectBuffer); if (selectedSpans.Count > 1) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 90f43035d357b..2f66311b883c5 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -126,7 +126,9 @@ private set /// private CancellationTokenSource _conflictResolutionTaskCancellationSource = new(); - private Task _commitTask; + private Task _commitTask; + + public bool IsCommitInProgress => _commitTask is not { Status: TaskStatus.RanToCompletion or TaskStatus.Faulted or TaskStatus.Canceled }; /// /// The initial text being renamed. @@ -395,14 +397,6 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs args) Cancel(); } - - if (args.Kind == WorkspaceChangeKind.DocumentChanged) - { - if (_conflictResolutionTask.Task.Status is not TaskStatus.RanToCompletion and not TaskStatus.Faulted) - { - Cancel(); - } - } } private void RaiseSessionSpansUpdated(ImmutableArray locations) @@ -738,33 +732,42 @@ public void Commit(bool previewChanges = false) /// if the rename operation was committed, otherwise - private void CommitSynchronously(bool previewChanges) + private bool CommitSynchronously(bool previewChanges) { // We're going to synchronously block the UI thread here. So we can't use the background work indicator (as // it needs the UI thread to update itself. This will force us to go through the Threaded-Wait-Dialog path // which at least will allow the user to cancel the rename if they want. // // In the future we should remove this entrypoint and have all callers use CommitAsync instead. - _threadingContext.JoinableTaskFactory.Run(() => StartCommitAsync(previewChanges, CancellationToken.None)); + return _threadingContext.JoinableTaskFactory.Run(() => StartCommitAsync(previewChanges, canUseBackgroundWorkIndicator: false, CancellationToken.None)); } - public Task CommitAsync(bool previewChanges, CancellationToken cancellationToken) - => StartCommitAsync(previewChanges, cancellationToken); + public async Task CommitAsync(bool previewChanges, CancellationToken cancellationToken) + { + if (this.RenameService.GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameAsynchronously)) + { + await StartCommitAsync(previewChanges, canUseBackgroundWorkIndicator: true, cancellationToken).ConfigureAwait(false); + } + else + { + CommitSynchronously(previewChanges); + } + } - private async Task StartCommitAsync(bool previewChanges, CancellationToken cancellationToken) + private async Task StartCommitAsync(bool previewChanges, bool canUseBackgroundWorkIndicator, CancellationToken cancellationToken) { if (_dismissed) { return false; } - _commitTask ??= CommitWorkerAsync(previewChanges, cancellationToken); - await _commitTask.ConfigureAwait(false); + _commitTask ??= CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator, cancellationToken); + return await _commitTask.ConfigureAwait(false); } /// if the rename operation was committed, otherwise - private async Task CommitWorkerAsync(bool previewChanges, CancellationToken cancellationToken) + private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackgroundWorkIndicator, CancellationToken cancellationToken) { await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); VerifyNotDismissed(); @@ -789,7 +792,7 @@ private async Task CommitWorkerAsync(bool previewChanges, CancellationToke try { - if (this.RenameService.GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameAsynchronously)) + if (canUseBackgroundWorkIndicator) { // We do not cancel on edit because as part of the rename system we have asynchronous work still // occurring that itself may be asynchronously editing the buffer (for example, updating reference From 2116ed993aa24138a2ded64ff89609865b792bc6 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 16 Aug 2024 23:54:00 -0700 Subject: [PATCH 18/59] Introduce a simple way to hide the UI when commit in progress --- .../UI/Adornment/RenameFlyout.xaml | 1 + .../UI/Adornment/RenameFlyoutViewModel.cs | 33 +++++++++++++++++++ .../Core/InlineRename/InlineRenameSession.cs | 6 +++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml index 1809edb0025e0..be642b6dfac18 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml @@ -20,6 +20,7 @@ Focusable="False" UseLayoutRounding="True" Cursor="Arrow" + Visibility="{Binding Path=Visibility}" x:Name="control"> diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index 8be7c8a19e7d3..076693d9d299d 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Threading; +using System.Windows; using System.Windows.Interop; using Microsoft.CodeAnalysis.Editor.InlineRename; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; @@ -55,6 +56,7 @@ public RenameFlyoutViewModel( Session.ReplacementTextChanged += OnReplacementTextChanged; Session.ReplacementsComputed += OnReplacementsComputed; Session.ReferenceLocationsChanged += OnReferenceLocationsChanged; + Session.CommitStateChange += SessionOnCommitStateChange; StartingSelection = selectionSpan; InitialTrackingSpan = session.TriggerSpan.CreateTrackingSpan(SpanTrackingMode.EdgeInclusive); _asyncListener = listenerProvider.GetListener(FeatureAttribute.Rename); @@ -67,6 +69,18 @@ public RenameFlyoutViewModel( RegisterOleComponent(); } + private void SessionOnCommitStateChange(object sender, bool e) + { + if (e) + { + Visibility = Visibility.Hidden; + } + else + { + Visibility = Visibility.Visible; + } + } + public SmartRenameViewModel? SmartRenameViewModel { get; } public string IdentifierText @@ -210,6 +224,24 @@ public bool IsRenameOverloadsEditable public bool IsRenameOverloadsVisible => Session.HasRenameOverloads; + public bool AllowUserInput + => !Session.IsCommitInProgress; + + + private Visibility _visibility; + public Visibility Visibility + { + get => _visibility; + set + { + if (value != _visibility) + { + _visibility = value; + NotifyPropertyChanged(); + } + } + } + public TextSpan StartingSelection { get; } public bool Submit() @@ -315,6 +347,7 @@ protected virtual void Dispose(bool disposing) { Session.ReplacementTextChanged -= OnReplacementTextChanged; Session.ReplacementsComputed -= OnReplacementsComputed; + Session.CommitStateChange -= SessionOnCommitStateChange; if (SmartRenameViewModel is not null) { diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 2f66311b883c5..0034087694fde 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -128,7 +128,7 @@ private set private Task _commitTask; - public bool IsCommitInProgress => _commitTask is not { Status: TaskStatus.RanToCompletion or TaskStatus.Faulted or TaskStatus.Canceled }; + public bool IsCommitInProgress => !_dismissed && _commitTask is not { Status: TaskStatus.RanToCompletion or TaskStatus.Faulted or TaskStatus.Canceled }; /// /// The initial text being renamed. @@ -349,6 +349,7 @@ private void UpdateReferenceLocationsTask() public event EventHandler> ReferenceLocationsChanged; public event EventHandler ReplacementsComputed; public event EventHandler ReplacementTextChanged; + public event EventHandler CommitStateChange; internal OpenTextBufferManager GetBufferManager(ITextBuffer buffer) => _openTextBuffers[buffer]; @@ -788,6 +789,7 @@ private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackg return false; } + previewChanges = previewChanges || PreviewChanges; try @@ -833,6 +835,7 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, bool previewChanges, CancellationToken cancellationToken) { + CommitStateChange?.Invoke(this, true); using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(operationContext.UserCancellationToken, cancellationToken); var linkedCancellationToken = operationContext.UserCancellationToken; var eventName = previewChanges ? FunctionId.Rename_CommitCoreWithPreview : FunctionId.Rename_CommitCore; @@ -859,6 +862,7 @@ private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, b if (newSolution == null) { // User clicked cancel. + CommitStateChange?.Invoke(this, false); return; } } From 2ec6fac1a1a022d97775206a4d71f8c5bd5dbc96 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Sat, 17 Aug 2024 00:48:19 -0700 Subject: [PATCH 19/59] Don't handle ESC --- .../AbstractRenameCommandHandler_EscapeHandler.cs | 3 ++- src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_EscapeHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_EscapeHandler.cs index 9d80929da596a..25d65d0cf8c71 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_EscapeHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_EscapeHandler.cs @@ -18,7 +18,8 @@ public bool ExecuteCommand(EscapeKeyCommandArgs args, CommandExecutionContext co { _renameService.ActiveSession.Cancel(); SetFocusToTextView(args.TextView); - return true; + // When ESC is pressed, don't handle the command here because rename might rely on + // BackgroundWorkIndicator to show the progress. Let platform propagates ESC to let indicator also get cancelled. } return false; diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 0034087694fde..6ebeba9533cdf 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -837,6 +837,7 @@ private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, b { CommitStateChange?.Invoke(this, true); using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(operationContext.UserCancellationToken, cancellationToken); + var linkedCancellationToken = operationContext.UserCancellationToken; var eventName = previewChanges ? FunctionId.Rename_CommitCoreWithPreview : FunctionId.Rename_CommitCore; using (Logger.LogBlock(eventName, KeyValueLogMessage.Create(LogType.UserAction), linkedCancellationToken)) From 3b199f9125e8de19a92587ff77576eb36a2509a7 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Mon, 19 Aug 2024 11:10:19 -0700 Subject: [PATCH 20/59] Add a null check --- .../CommandHandlers/AbstractRenameCommandHandler.cs | 1 - src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs index a30194f9813cf..589867cf73e34 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs @@ -70,7 +70,6 @@ private void HandlePossibleTypingCommand(TArgs args, Action nextHandler, } var selectedSpans = args.TextView.Selection.GetSnapshotSpansOnBuffer(args.SubjectBuffer); - if (selectedSpans.Count > 1) { // If we have multiple spans active, then that means we have something like box diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 6ebeba9533cdf..b16caed1c45d9 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -128,7 +128,7 @@ private set private Task _commitTask; - public bool IsCommitInProgress => !_dismissed && _commitTask is not { Status: TaskStatus.RanToCompletion or TaskStatus.Faulted or TaskStatus.Canceled }; + public bool IsCommitInProgress => !_dismissed && _commitTask is not null && _commitTask is not { Status: TaskStatus.RanToCompletion or TaskStatus.Faulted or TaskStatus.Canceled }; /// /// The initial text being renamed. From d8bb916a7d6831d0178cd5b300b5b24add419e7c Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Mon, 19 Aug 2024 11:42:46 -0700 Subject: [PATCH 21/59] Wrap try catch --- .../UI/Adornment/RenameFlyoutViewModel.cs | 31 ++++++++++++++++++- .../Core/IInlineRenameSession.cs | 2 +- .../AbstractRenameCommandHandler.cs | 3 +- .../Core/InlineRename/InlineRenameSession.cs | 10 ++++-- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index 076693d9d299d..183182cec4cb1 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -10,16 +10,19 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Threading; +using System.Threading.Tasks; using System.Windows; using System.Windows.Interop; using Microsoft.CodeAnalysis.Editor.InlineRename; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.EditorFeatures.Lightup; +using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.InlineRename; using Microsoft.CodeAnalysis.InlineRename.UI.SmartRename; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Telemetry; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Imaging.Interop; @@ -253,10 +256,36 @@ public bool Submit() } SmartRenameViewModel?.Commit(IdentifierText); - _ = Session.CommitAsync(previewChanges: false, cancellationToken: CancellationToken.None).ReportNonFatalErrorAsync(); + _ = CommitAsync().ReportNonFatalErrorAsync(); return true; } + private async Task CommitAsync() + { + try + { + await Session.CommitAsync(previewChanges: false, cancellationToken: CancellationToken.None).ReportNonFatalErrorAsync().ConfigureAwait(false); + } + catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.Critical)) + { + // Show a nice error to the user via an info bar + var errorReportingService = Session.Workspace.Services.GetService(); + if (errorReportingService is null) + { + return; + } + + errorReportingService.ShowGlobalErrorInfo( + message: string.Format(EditorFeaturesWpfResources.Error_performing_rename_0, ex.Message), + TelemetryFeatureName.InlineRename, + ex, + new InfoBarUI( + WorkspacesResources.Show_Stack_Trace, + InfoBarUI.UIKind.HyperLink, + () => errorReportingService.ShowDetailedErrorInfo(ex), closeAfterAction: true)); + } + } + public void Cancel() { SmartRenameViewModel?.Cancel(); diff --git a/src/EditorFeatures/Core/IInlineRenameSession.cs b/src/EditorFeatures/Core/IInlineRenameSession.cs index 3ae70a4d091a2..a7985cdbba4f4 100644 --- a/src/EditorFeatures/Core/IInlineRenameSession.cs +++ b/src/EditorFeatures/Core/IInlineRenameSession.cs @@ -50,5 +50,5 @@ internal interface IInlineRenameSession /// /// Dismisses the rename session, completing the rename operation across all files. /// - Task CommitAsync(bool previewChanges, CancellationToken cancellationToken); + Task CommitAsync(bool previewChanges, CancellationToken cancellationToken); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs index 589867cf73e34..c36996ecad017 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs @@ -4,6 +4,7 @@ using System; using System.Linq; +using System.Threading; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -104,7 +105,7 @@ private void CommitIfActive(EditorCommandArgs args) { var selection = args.TextView.Selection.VirtualSelectedSpans.First(); - _renameService.ActiveSession.Commit(); + _ = _renameService.ActiveSession.CommitAsync(previewChanges: false, CancellationToken.None); var translatedSelection = selection.TranslateTo(args.TextView.TextBuffer.CurrentSnapshot); args.TextView.Selection.Select(translatedSelection.Start, translatedSelection.End); diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index b16caed1c45d9..1d53778a37c2b 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -349,6 +349,10 @@ private void UpdateReferenceLocationsTask() public event EventHandler> ReferenceLocationsChanged; public event EventHandler ReplacementsComputed; public event EventHandler ReplacementTextChanged; + + /// + /// True if commit operation starts, False if commit operation ends. + /// public event EventHandler CommitStateChange; internal OpenTextBufferManager GetBufferManager(ITextBuffer buffer) @@ -740,10 +744,10 @@ private bool CommitSynchronously(bool previewChanges) // which at least will allow the user to cancel the rename if they want. // // In the future we should remove this entrypoint and have all callers use CommitAsync instead. - return _threadingContext.JoinableTaskFactory.Run(() => StartCommitAsync(previewChanges, canUseBackgroundWorkIndicator: false, CancellationToken.None)); + return _threadingContext.JoinableTaskFactory.Run(() => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: false, CancellationToken.None)); } - public async Task CommitAsync(bool previewChanges, CancellationToken cancellationToken) + public async Task CommitAsync(bool previewChanges, CancellationToken cancellationToken) { if (this.RenameService.GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameAsynchronously)) { @@ -876,7 +880,6 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( async () => { var error = await TryApplyRenameAsync(newSolution, linkedCancellationToken).ConfigureAwait(false); - if (error is not null) { await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(linkedCancellationToken); @@ -884,6 +887,7 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( notificationService.SendNotification( error.Value.message, EditorFeaturesResources.Rename_Symbol, error.Value.severity); } + CommitStateChange?.Invoke(this, false); }).ConfigureAwait(false); } } From 7e1c13ea349c76c3a3d83f981c9d211e772fe2d1 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Mon, 19 Aug 2024 11:43:35 -0700 Subject: [PATCH 22/59] Reset the legacy UI to sync --- .../InlineRename/UI/Dashboard/RenameDashboard.xaml.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs index 4f3925a59e030..482304aa00701 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs @@ -7,8 +7,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading; -using System.Threading.Tasks; using System.Windows; using System.Windows.Automation.Peers; using System.Windows.Controls; @@ -20,7 +18,6 @@ using Microsoft.CodeAnalysis.Telemetry; using Microsoft.VisualStudio.Text.Classification; using Microsoft.VisualStudio.Text.Editor; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename { @@ -330,13 +327,11 @@ private void CloseButton_Click(object sender, RoutedEventArgs e) private void Apply_Click(object sender, RoutedEventArgs e) => Commit(); - private void Commit() => _ = CommitAsync().ReportNonFatalErrorAsync(); - - private async Task CommitAsync() + private void Commit() { try { - await _model.Session.CommitAsync(previewChanges: false, cancellationToken: CancellationToken.None).ConfigureAwait(true); + _model.Session.Commit(); _textView.VisualElement.Focus(); } catch (NotSupportedException ex) From 226cb7cd252f241224f88faa87af9bb32037b954 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Mon, 19 Aug 2024 13:23:46 -0700 Subject: [PATCH 23/59] Code clean --- .../InlineRename/CommandHandlers/RenameCommandHandler.cs | 1 - .../InlineRename/UI/Adornment/RenameFlyoutViewModel.cs | 3 +-- src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs | 5 ++--- .../VisualBasicTest/LineCommit/CommitTestData.vb | 4 ++-- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs index d99b07484b468..03e0c6fd140a1 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs @@ -96,7 +96,6 @@ protected override void SetAdornmentFocusToPreviousElement(ITextView textView) } } - protected override async Task CommitAndSetFocusAsync(InlineRenameSession activeSession, ITextView textView, CancellationToken cancellationToken) { try diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index 183182cec4cb1..e139a745883ff 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -230,7 +230,6 @@ public bool IsRenameOverloadsVisible public bool AllowUserInput => !Session.IsCommitInProgress; - private Visibility _visibility; public Visibility Visibility { @@ -239,7 +238,7 @@ public Visibility Visibility { if (value != _visibility) { - _visibility = value; + Set(ref _visibility, value); NotifyPropertyChanged(); } } diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 1d53778a37c2b..92b8d1c2d36bf 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -751,11 +751,11 @@ public async Task CommitAsync(bool previewChanges, CancellationToken cance { if (this.RenameService.GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameAsynchronously)) { - await StartCommitAsync(previewChanges, canUseBackgroundWorkIndicator: true, cancellationToken).ConfigureAwait(false); + return await StartCommitAsync(previewChanges, canUseBackgroundWorkIndicator: true, cancellationToken).ConfigureAwait(false); } else { - CommitSynchronously(previewChanges); + return CommitSynchronously(previewChanges); } } @@ -793,7 +793,6 @@ private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackg return false; } - previewChanges = previewChanges || PreviewChanges; try diff --git a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb index 6443f03fd5b28..397b10d83d23a 100644 --- a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb +++ b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb @@ -111,8 +111,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.LineCommit Throw New NotImplementedException() End Sub - Public Function CommitAsync(previewChanges As Boolean, cancellationToken As CancellationToken) As Task Implements IInlineRenameSession.CommitAsync - Throw New NotImplementedException() + Public Function CommitAsync(previewChanges As Boolean, cancellationToken As CancellationToken) As Task(Of Boolean) Implements IInlineRenameSession.CommitAsync + Throw New NotImplementedException End Function End Class End Class From c2a6b1dfc4370a564796f249257d25911cc04216 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Mon, 19 Aug 2024 13:26:30 -0700 Subject: [PATCH 24/59] Clean up --- .../InlineRename/UI/Adornment/RenameFlyoutViewModel.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index e139a745883ff..3f01241fb78db 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -74,14 +74,7 @@ public RenameFlyoutViewModel( private void SessionOnCommitStateChange(object sender, bool e) { - if (e) - { - Visibility = Visibility.Hidden; - } - else - { - Visibility = Visibility.Visible; - } + Visibility = e ? Visibility.Collapsed : Visibility.Visible; } public SmartRenameViewModel? SmartRenameViewModel { get; } From 98d9f5c38998dcd17dfb1fc0cc635b6ebb59c0c8 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Mon, 19 Aug 2024 14:02:06 -0700 Subject: [PATCH 25/59] Clean up --- .../Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index 3f01241fb78db..2dce040b84009 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -87,7 +87,7 @@ public string IdentifierText if (value != Session.ReplacementText) { Session.ApplyReplacementText(value, propagateEditImmediately: true, updateSelection: false); - NotifyPropertyChanged(nameof(IdentifierText)); + NotifyPropertyChanged(); } } } From 9d066625a7f6dc8003477056cbccc5a368676863 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Mon, 19 Aug 2024 15:32:45 -0700 Subject: [PATCH 26/59] Add CommitState --- .../Core/InlineRename/InlineRenameSession.cs | 4 ++++ .../InlineRename/InlineRenameSessionCommitState.cs | 12 ++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 src/EditorFeatures/Core/InlineRename/InlineRenameSessionCommitState.cs diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 92b8d1c2d36bf..8616fa457b12a 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -126,6 +126,10 @@ private set /// private CancellationTokenSource _conflictResolutionTaskCancellationSource = new(); + /// + /// Task tracking the commit operation. + /// Null if commit never starts. + /// private Task _commitTask; public bool IsCommitInProgress => !_dismissed && _commitTask is not null && _commitTask is not { Status: TaskStatus.RanToCompletion or TaskStatus.Faulted or TaskStatus.Canceled }; diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSessionCommitState.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSessionCommitState.cs new file mode 100644 index 0000000000000..d0ca7911b964e --- /dev/null +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSessionCommitState.cs @@ -0,0 +1,12 @@ +// 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. + +namespace Microsoft.CodeAnalysis.InlineRename; + +internal enum InlineRenameSessionCommitState +{ + None, + WaitConflictResolution, + CancelledByPreview, +} From 56708dfc93033d4bc015f5e8f6741512b48ec204 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Mon, 19 Aug 2024 16:10:01 -0700 Subject: [PATCH 27/59] Revise using the state --- .../UI/Adornment/RenameFlyoutViewModel.cs | 8 ++++-- ...meSessionCommitState.cs => CommitState.cs} | 10 ++++--- ...lineRenameSession.OpenTextBufferManager.cs | 9 ++++--- .../Core/InlineRename/InlineRenameSession.cs | 27 +++++++++++++++---- 4 files changed, 40 insertions(+), 14 deletions(-) rename src/EditorFeatures/Core/InlineRename/{InlineRenameSessionCommitState.cs => CommitState.cs} (61%) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index 2dce040b84009..33e90f5af5a06 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -72,9 +72,13 @@ public RenameFlyoutViewModel( RegisterOleComponent(); } - private void SessionOnCommitStateChange(object sender, bool e) + private void SessionOnCommitStateChange(object sender, CommitState e) { - Visibility = e ? Visibility.Collapsed : Visibility.Visible; + Visibility = e switch + { + CommitState.NotStart => Visibility.Visible, + _ => Visibility.Collapsed, + }; } public SmartRenameViewModel? SmartRenameViewModel { get; } diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSessionCommitState.cs b/src/EditorFeatures/Core/InlineRename/CommitState.cs similarity index 61% rename from src/EditorFeatures/Core/InlineRename/InlineRenameSessionCommitState.cs rename to src/EditorFeatures/Core/InlineRename/CommitState.cs index d0ca7911b964e..93934dc8232ab 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSessionCommitState.cs +++ b/src/EditorFeatures/Core/InlineRename/CommitState.cs @@ -4,9 +4,13 @@ namespace Microsoft.CodeAnalysis.InlineRename; -internal enum InlineRenameSessionCommitState +/// +/// State represents different stages when commit starts in InlineRenameSession. +/// +internal enum CommitState { - None, + NotStart, WaitConflictResolution, - CancelledByPreview, + StartApplyChanges, + End, } diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs index 01c02a309551b..530a7e44acbc0 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs @@ -36,7 +36,6 @@ internal class OpenTextBufferManager private readonly DynamicReadOnlyRegionQuery _isBufferReadOnly; private readonly InlineRenameSession _session; private readonly ITextBuffer _subjectBuffer; - private readonly IEnumerable _baseDocuments; private readonly ITextBufferFactoryService _textBufferFactoryService; private readonly ITextBufferCloneService _textBufferCloneService; @@ -62,7 +61,7 @@ public OpenTextBufferManager( { _session = session; _subjectBuffer = subjectBuffer; - _baseDocuments = subjectBuffer.GetRelatedDocuments(); + BaseDocuments = subjectBuffer.GetRelatedDocuments().ToImmutableArray(); _textBufferFactoryService = textBufferFactoryService; _textBufferCloneService = textBufferCloneService; _subjectBuffer.ChangedLowPriority += OnTextBufferChanged; @@ -78,6 +77,8 @@ public OpenTextBufferManager( UpdateReadOnlyRegions(); } + public ImmutableArray BaseDocuments { get; } + public ITextView ActiveTextView { get @@ -184,7 +185,7 @@ internal void SetReferenceSpans(IEnumerable spans) _referenceSpanToLinkedRenameSpanMap.Clear(); foreach (var span in spans) { - var document = _baseDocuments.First(); + var document = BaseDocuments.First(); var renameableSpan = _session.RenameInfo.GetReferenceEditSpan( new InlineRenameLocation(document, span), GetTriggerText(document, span), CancellationToken.None); var trackingSpan = new RenameTrackingSpan( @@ -328,7 +329,7 @@ internal void ApplyConflictResolutionEdits(IInlineRenameReplacementInfo conflict _session.UndoManager.UndoTemporaryEdits(_subjectBuffer, disconnect: false); var newDocument = mergeResult.MergedSolution.GetDocument(documents.First().Id); - var originalDocument = _baseDocuments.Single(d => d.Id == newDocument.Id); + var originalDocument = BaseDocuments.Single(d => d.Id == newDocument.Id); var changes = GetTextChangesFromTextDifferencingServiceAsync(originalDocument, newDocument, cancellationToken).WaitAndGetResult(cancellationToken); diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 8616fa457b12a..5d69b3683625f 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -342,6 +342,21 @@ private void UpdateReferenceLocationsTask() QueueApplyReplacements(); } + + private CommitState _commitState = CommitState.NotStart; + public CommitState CommitState + { + get => _commitState; + set + { + if (_commitState != value) + { + _commitState = value; + CommitStateChange?.Invoke(this, value); + } + } + } + public Workspace Workspace { get; } public SymbolRenameOptions Options { get; private set; } public bool PreviewChanges { get; private set; } @@ -357,7 +372,7 @@ private void UpdateReferenceLocationsTask() /// /// True if commit operation starts, False if commit operation ends. /// - public event EventHandler CommitStateChange; + public event EventHandler CommitStateChange; internal OpenTextBufferManager GetBufferManager(ITextBuffer buffer) => _openTextBuffers[buffer]; @@ -842,13 +857,13 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, bool previewChanges, CancellationToken cancellationToken) { - CommitStateChange?.Invoke(this, true); using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(operationContext.UserCancellationToken, cancellationToken); var linkedCancellationToken = operationContext.UserCancellationToken; var eventName = previewChanges ? FunctionId.Rename_CommitCoreWithPreview : FunctionId.Rename_CommitCore; using (Logger.LogBlock(eventName, KeyValueLogMessage.Create(LogType.UserAction), linkedCancellationToken)) { + CommitState = CommitState.WaitConflictResolution; var info = await _conflictResolutionTask.JoinAsync(linkedCancellationToken).ConfigureAwait(true); var newSolution = info.NewSolution; @@ -869,8 +884,8 @@ private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, b if (newSolution == null) { - // User clicked cancel. - CommitStateChange?.Invoke(this, false); + // User clicked cancel. Head back to NotStart state. + CommitState = CommitState.NotStart; return; } } @@ -882,6 +897,7 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( RenameLogMessage.UserActionOutcome.Committed, previewChanges, async () => { + CommitState = CommitState.StartApplyChanges; var error = await TryApplyRenameAsync(newSolution, linkedCancellationToken).ConfigureAwait(false); if (error is not null) { @@ -890,7 +906,8 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( notificationService.SendNotification( error.Value.message, EditorFeaturesResources.Rename_Symbol, error.Value.severity); } - CommitStateChange?.Invoke(this, false); + + CommitState = CommitState.End; }).ConfigureAwait(false); } } From 17efc48ebafb89a60933ed111370ba972eac38d1 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Mon, 19 Aug 2024 16:27:03 -0700 Subject: [PATCH 28/59] Use State to cancel --- .../Core/InlineRename/CommitState.cs | 1 + .../Core/InlineRename/InlineRenameSession.cs | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core/InlineRename/CommitState.cs b/src/EditorFeatures/Core/InlineRename/CommitState.cs index 93934dc8232ab..bef7019761251 100644 --- a/src/EditorFeatures/Core/InlineRename/CommitState.cs +++ b/src/EditorFeatures/Core/InlineRename/CommitState.cs @@ -11,6 +11,7 @@ internal enum CommitState { NotStart, WaitConflictResolution, + PreviewChanges, StartApplyChanges, End, } diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 5d69b3683625f..c88fedc3a7cd7 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -421,6 +421,20 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs args) Cancel(); } + else + { + if (_commitState == CommitState.WaitConflictResolution) + { + var openDocuments = _openTextBuffers.Values + .SelectMany(static textBufferManager => textBufferManager.BaseDocuments) + .Select(doc => doc.Id) + .Distinct(); + if (openDocuments.Contains(args.DocumentId)) + { + Cancel(); + } + } + } } private void RaiseSessionSpansUpdated(ImmutableArray locations) @@ -869,6 +883,7 @@ private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, b if (previewChanges) { + CommitState = CommitState.PreviewChanges; var previewService = Workspace.Services.GetService(); // The preview service needs to be called from the UI thread, since it's doing COM calls underneath. @@ -891,13 +906,13 @@ private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, b } // The user hasn't canceled by now, so we're done waiting for them. Off to rename! + CommitState = CommitState.StartApplyChanges; using var _ = operationContext.AddScope(allowCancellation: false, EditorFeaturesResources.Updating_files); await DismissUIAndRollbackEditsAndEndRenameSessionAsync( RenameLogMessage.UserActionOutcome.Committed, previewChanges, async () => { - CommitState = CommitState.StartApplyChanges; var error = await TryApplyRenameAsync(newSolution, linkedCancellationToken).ConfigureAwait(false); if (error is not null) { From cd99b6b38219b6e177ab0bbf4a02c2e7bbab22a2 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Mon, 19 Aug 2024 20:17:13 -0700 Subject: [PATCH 29/59] Revert "Add CommitState" This reverts commit ec4a78a5259ed8cdc49cea5937b250c7b2796e9d. --- src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index c88fedc3a7cd7..2606e5b3302e2 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -126,10 +126,6 @@ private set /// private CancellationTokenSource _conflictResolutionTaskCancellationSource = new(); - /// - /// Task tracking the commit operation. - /// Null if commit never starts. - /// private Task _commitTask; public bool IsCommitInProgress => !_dismissed && _commitTask is not null && _commitTask is not { Status: TaskStatus.RanToCompletion or TaskStatus.Faulted or TaskStatus.Canceled }; From 491e45352466a029ebafbfaae929ef05206ffaf8 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Mon, 19 Aug 2024 20:17:45 -0700 Subject: [PATCH 30/59] Revert "Revise using the state" This reverts commit 8420e6cbc2a8ff9f1c695da27d9153e12f0d8143. --- .../UI/Adornment/RenameFlyoutViewModel.cs | 8 ++---- .../Core/InlineRename/CommitState.cs | 17 ------------ ...lineRenameSession.OpenTextBufferManager.cs | 9 +++---- .../Core/InlineRename/InlineRenameSession.cs | 26 ++++--------------- 4 files changed, 11 insertions(+), 49 deletions(-) delete mode 100644 src/EditorFeatures/Core/InlineRename/CommitState.cs diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index 33e90f5af5a06..2dce040b84009 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -72,13 +72,9 @@ public RenameFlyoutViewModel( RegisterOleComponent(); } - private void SessionOnCommitStateChange(object sender, CommitState e) + private void SessionOnCommitStateChange(object sender, bool e) { - Visibility = e switch - { - CommitState.NotStart => Visibility.Visible, - _ => Visibility.Collapsed, - }; + Visibility = e ? Visibility.Collapsed : Visibility.Visible; } public SmartRenameViewModel? SmartRenameViewModel { get; } diff --git a/src/EditorFeatures/Core/InlineRename/CommitState.cs b/src/EditorFeatures/Core/InlineRename/CommitState.cs deleted file mode 100644 index bef7019761251..0000000000000 --- a/src/EditorFeatures/Core/InlineRename/CommitState.cs +++ /dev/null @@ -1,17 +0,0 @@ -// 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. - -namespace Microsoft.CodeAnalysis.InlineRename; - -/// -/// State represents different stages when commit starts in InlineRenameSession. -/// -internal enum CommitState -{ - NotStart, - WaitConflictResolution, - PreviewChanges, - StartApplyChanges, - End, -} diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs index 530a7e44acbc0..01c02a309551b 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs @@ -36,6 +36,7 @@ internal class OpenTextBufferManager private readonly DynamicReadOnlyRegionQuery _isBufferReadOnly; private readonly InlineRenameSession _session; private readonly ITextBuffer _subjectBuffer; + private readonly IEnumerable _baseDocuments; private readonly ITextBufferFactoryService _textBufferFactoryService; private readonly ITextBufferCloneService _textBufferCloneService; @@ -61,7 +62,7 @@ public OpenTextBufferManager( { _session = session; _subjectBuffer = subjectBuffer; - BaseDocuments = subjectBuffer.GetRelatedDocuments().ToImmutableArray(); + _baseDocuments = subjectBuffer.GetRelatedDocuments(); _textBufferFactoryService = textBufferFactoryService; _textBufferCloneService = textBufferCloneService; _subjectBuffer.ChangedLowPriority += OnTextBufferChanged; @@ -77,8 +78,6 @@ public OpenTextBufferManager( UpdateReadOnlyRegions(); } - public ImmutableArray BaseDocuments { get; } - public ITextView ActiveTextView { get @@ -185,7 +184,7 @@ internal void SetReferenceSpans(IEnumerable spans) _referenceSpanToLinkedRenameSpanMap.Clear(); foreach (var span in spans) { - var document = BaseDocuments.First(); + var document = _baseDocuments.First(); var renameableSpan = _session.RenameInfo.GetReferenceEditSpan( new InlineRenameLocation(document, span), GetTriggerText(document, span), CancellationToken.None); var trackingSpan = new RenameTrackingSpan( @@ -329,7 +328,7 @@ internal void ApplyConflictResolutionEdits(IInlineRenameReplacementInfo conflict _session.UndoManager.UndoTemporaryEdits(_subjectBuffer, disconnect: false); var newDocument = mergeResult.MergedSolution.GetDocument(documents.First().Id); - var originalDocument = BaseDocuments.Single(d => d.Id == newDocument.Id); + var originalDocument = _baseDocuments.Single(d => d.Id == newDocument.Id); var changes = GetTextChangesFromTextDifferencingServiceAsync(originalDocument, newDocument, cancellationToken).WaitAndGetResult(cancellationToken); diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 2606e5b3302e2..5af087b821bbb 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -338,21 +338,6 @@ private void UpdateReferenceLocationsTask() QueueApplyReplacements(); } - - private CommitState _commitState = CommitState.NotStart; - public CommitState CommitState - { - get => _commitState; - set - { - if (_commitState != value) - { - _commitState = value; - CommitStateChange?.Invoke(this, value); - } - } - } - public Workspace Workspace { get; } public SymbolRenameOptions Options { get; private set; } public bool PreviewChanges { get; private set; } @@ -368,7 +353,7 @@ public CommitState CommitState /// /// True if commit operation starts, False if commit operation ends. /// - public event EventHandler CommitStateChange; + public event EventHandler CommitStateChange; internal OpenTextBufferManager GetBufferManager(ITextBuffer buffer) => _openTextBuffers[buffer]; @@ -867,13 +852,13 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, bool previewChanges, CancellationToken cancellationToken) { + CommitStateChange?.Invoke(this, true); using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(operationContext.UserCancellationToken, cancellationToken); var linkedCancellationToken = operationContext.UserCancellationToken; var eventName = previewChanges ? FunctionId.Rename_CommitCoreWithPreview : FunctionId.Rename_CommitCore; using (Logger.LogBlock(eventName, KeyValueLogMessage.Create(LogType.UserAction), linkedCancellationToken)) { - CommitState = CommitState.WaitConflictResolution; var info = await _conflictResolutionTask.JoinAsync(linkedCancellationToken).ConfigureAwait(true); var newSolution = info.NewSolution; @@ -895,8 +880,8 @@ private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, b if (newSolution == null) { - // User clicked cancel. Head back to NotStart state. - CommitState = CommitState.NotStart; + // User clicked cancel. + CommitStateChange?.Invoke(this, false); return; } } @@ -917,8 +902,7 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( notificationService.SendNotification( error.Value.message, EditorFeaturesResources.Rename_Symbol, error.Value.severity); } - - CommitState = CommitState.End; + CommitStateChange?.Invoke(this, false); }).ConfigureAwait(false); } } From 39ac7cdabdf94b9d5a924bcae8893ecfee9dc35d Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Mon, 19 Aug 2024 20:17:56 -0700 Subject: [PATCH 31/59] Revert "Use State to cancel" This reverts commit cda7a87427fd5f12d8c1bdcd9b3a6a94c2a54a5d. --- .../Core/InlineRename/CommitState.cs | 16 ++++++++++++++++ .../Core/InlineRename/InlineRenameSession.cs | 17 +---------------- 2 files changed, 17 insertions(+), 16 deletions(-) create mode 100644 src/EditorFeatures/Core/InlineRename/CommitState.cs diff --git a/src/EditorFeatures/Core/InlineRename/CommitState.cs b/src/EditorFeatures/Core/InlineRename/CommitState.cs new file mode 100644 index 0000000000000..93934dc8232ab --- /dev/null +++ b/src/EditorFeatures/Core/InlineRename/CommitState.cs @@ -0,0 +1,16 @@ +// 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. + +namespace Microsoft.CodeAnalysis.InlineRename; + +/// +/// State represents different stages when commit starts in InlineRenameSession. +/// +internal enum CommitState +{ + NotStart, + WaitConflictResolution, + StartApplyChanges, + End, +} diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 5af087b821bbb..deb1a633b9810 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -402,20 +402,6 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs args) Cancel(); } - else - { - if (_commitState == CommitState.WaitConflictResolution) - { - var openDocuments = _openTextBuffers.Values - .SelectMany(static textBufferManager => textBufferManager.BaseDocuments) - .Select(doc => doc.Id) - .Distinct(); - if (openDocuments.Contains(args.DocumentId)) - { - Cancel(); - } - } - } } private void RaiseSessionSpansUpdated(ImmutableArray locations) @@ -864,7 +850,6 @@ private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, b if (previewChanges) { - CommitState = CommitState.PreviewChanges; var previewService = Workspace.Services.GetService(); // The preview service needs to be called from the UI thread, since it's doing COM calls underneath. @@ -887,13 +872,13 @@ private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, b } // The user hasn't canceled by now, so we're done waiting for them. Off to rename! - CommitState = CommitState.StartApplyChanges; using var _ = operationContext.AddScope(allowCancellation: false, EditorFeaturesResources.Updating_files); await DismissUIAndRollbackEditsAndEndRenameSessionAsync( RenameLogMessage.UserActionOutcome.Committed, previewChanges, async () => { + CommitState = CommitState.StartApplyChanges; var error = await TryApplyRenameAsync(newSolution, linkedCancellationToken).ConfigureAwait(false); if (error is not null) { From b61d2eb8d9ea9a3ff9746add9cccf4bd4a00587d Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Mon, 19 Aug 2024 20:32:29 -0700 Subject: [PATCH 32/59] Clean cancellationToken --- .../UI/Adornment/RenameFlyoutViewModel.cs | 2 +- .../ExtractMethodCommandHandler.cs | 2 +- .../Core/IInlineRenameSession.cs | 2 +- .../AbstractRenameCommandHandler.cs | 2 +- ...tractRenameCommandHandler_RenameHandler.cs | 2 +- ...tractRenameCommandHandler_ReturnHandler.cs | 6 ++--- .../Core/InlineRename/CommitState.cs | 16 -------------- .../Core/InlineRename/InlineRenameSession.cs | 22 +++++++++++++------ .../Test2/Rename/RenameTagProducerTests.vb | 2 +- .../LineCommit/CommitTestData.vb | 2 +- 10 files changed, 25 insertions(+), 33 deletions(-) delete mode 100644 src/EditorFeatures/Core/InlineRename/CommitState.cs diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index 2dce040b84009..9a2748af8a7da 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -256,7 +256,7 @@ private async Task CommitAsync() { try { - await Session.CommitAsync(previewChanges: false, cancellationToken: CancellationToken.None).ReportNonFatalErrorAsync().ConfigureAwait(false); + await Session.CommitAsync(previewChanges: false).ReportNonFatalErrorAsync().ConfigureAwait(false); } catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.Critical)) { diff --git a/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs b/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs index 399d12000ac31..b4fdef4f521a0 100644 --- a/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs +++ b/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs @@ -116,7 +116,7 @@ private async Task ExecuteAsync( if (_renameService.ActiveSession != null) { // ConfigureAwait(true) to make sure the next wait indicator would be created correctly. - await _renameService.ActiveSession.CommitAsync(previewChanges: false, CancellationToken.None).ConfigureAwait(true); + await _renameService.ActiveSession.CommitAsync(previewChanges: false).ConfigureAwait(true); } var indicatorFactory = document.Project.Solution.Services.GetRequiredService(); diff --git a/src/EditorFeatures/Core/IInlineRenameSession.cs b/src/EditorFeatures/Core/IInlineRenameSession.cs index a7985cdbba4f4..5308f7243c2e8 100644 --- a/src/EditorFeatures/Core/IInlineRenameSession.cs +++ b/src/EditorFeatures/Core/IInlineRenameSession.cs @@ -50,5 +50,5 @@ internal interface IInlineRenameSession /// /// Dismisses the rename session, completing the rename operation across all files. /// - Task CommitAsync(bool previewChanges, CancellationToken cancellationToken); + Task CommitAsync(bool previewChanges); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs index c36996ecad017..d98a8ca2534ae 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs @@ -105,7 +105,7 @@ private void CommitIfActive(EditorCommandArgs args) { var selection = args.TextView.Selection.VirtualSelectedSpans.First(); - _ = _renameService.ActiveSession.CommitAsync(previewChanges: false, CancellationToken.None); + _ = _renameService.ActiveSession.CommitAsync(previewChanges: false); var translatedSelection = selection.TranslateTo(args.TextView.TextBuffer.CurrentSnapshot); args.TextView.Selection.Select(translatedSelection.Start, translatedSelection.End); diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs index 8ee3b8b06fb1e..d9627c0f263f2 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs @@ -77,7 +77,7 @@ private async Task ExecuteCommandAsync(RenameCommandArgs args) else { // Otherwise, commit the existing session and start a new one. - await _renameService.ActiveSession.CommitAsync(previewChanges: false, CancellationToken.None).ConfigureAwait(true); + await _renameService.ActiveSession.CommitAsync(previewChanges: false).ConfigureAwait(true); } } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs index afc6a9b52d5bc..abddebadd7847 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs @@ -23,16 +23,16 @@ public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext co // Prevent Editor's typing responsiveness auto canceling the rename operation. // InlineRenameSession will call IBackgroundWorkIndicator to sets up our own IUIThreadOperationContext context.OperationContext.TakeOwnership(); - _ = CommitAndSetFocusAsync(_renameService.ActiveSession, args.TextView, CancellationToken.None).ReportNonFatalErrorAsync(); + _ = CommitAndSetFocusAsync(_renameService.ActiveSession, args.TextView).ReportNonFatalErrorAsync(); return true; } return false; } - protected virtual async Task CommitAndSetFocusAsync(InlineRenameSession activeSession, ITextView textView, CancellationToken cancellationToken) + protected virtual async Task CommitAndSetFocusAsync(InlineRenameSession activeSession, ITextView textView) { - await activeSession.CommitAsync(previewChanges: false, cancellationToken).ConfigureAwait(true); + await activeSession.CommitAsync(previewChanges: false).ConfigureAwait(true); SetFocusToTextView(textView); } } diff --git a/src/EditorFeatures/Core/InlineRename/CommitState.cs b/src/EditorFeatures/Core/InlineRename/CommitState.cs deleted file mode 100644 index 93934dc8232ab..0000000000000 --- a/src/EditorFeatures/Core/InlineRename/CommitState.cs +++ /dev/null @@ -1,16 +0,0 @@ -// 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. - -namespace Microsoft.CodeAnalysis.InlineRename; - -/// -/// State represents different stages when commit starts in InlineRenameSession. -/// -internal enum CommitState -{ - NotStart, - WaitConflictResolution, - StartApplyChanges, - End, -} diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index deb1a633b9810..5bbb24ba42003 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -126,6 +126,8 @@ private set /// private CancellationTokenSource _conflictResolutionTaskCancellationSource = new(); + private CancellationTokenSource _commitCancellationTokenSource; + private Task _commitTask; public bool IsCommitInProgress => !_dismissed && _commitTask is not null && _commitTask is not { Status: TaskStatus.RanToCompletion or TaskStatus.Faulted or TaskStatus.Canceled }; @@ -682,6 +684,7 @@ private async Task DismissUIAndRollbackEditsAndEndRenameSessionAsync( // We're about to perform the final commit action. No need to do any of our BG work to find-refs or compute conflicts. _cancellationTokenSource.Cancel(); _conflictResolutionTaskCancellationSource.Cancel(); + _commitCancellationTokenSource?.Cancel(); // Close the keep alive session we have open with OOP, allowing it to release the solution it is holding onto. _keepAliveSession.Dispose(); @@ -744,14 +747,14 @@ private bool CommitSynchronously(bool previewChanges) // which at least will allow the user to cancel the rename if they want. // // In the future we should remove this entrypoint and have all callers use CommitAsync instead. - return _threadingContext.JoinableTaskFactory.Run(() => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: false, CancellationToken.None)); + return _threadingContext.JoinableTaskFactory.Run(() => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: false)); } - public async Task CommitAsync(bool previewChanges, CancellationToken cancellationToken) + public async Task CommitAsync(bool previewChanges) { if (this.RenameService.GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameAsynchronously)) { - return await StartCommitAsync(previewChanges, canUseBackgroundWorkIndicator: true, cancellationToken).ConfigureAwait(false); + return await StartCommitAsync(previewChanges, canUseBackgroundWorkIndicator: true).ConfigureAwait(false); } else { @@ -759,21 +762,24 @@ public async Task CommitAsync(bool previewChanges, CancellationToken cance } } - private async Task StartCommitAsync(bool previewChanges, bool canUseBackgroundWorkIndicator, CancellationToken cancellationToken) + private async Task StartCommitAsync(bool previewChanges, bool canUseBackgroundWorkIndicator) { if (_dismissed) { return false; } - _commitTask ??= CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator, cancellationToken); + _commitTask ??= CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator); return await _commitTask.ConfigureAwait(false); } /// if the rename operation was committed, otherwise - private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackgroundWorkIndicator, CancellationToken cancellationToken) + private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackgroundWorkIndicator) { + _commitCancellationTokenSource?.Dispose(); + _commitCancellationTokenSource = new(); + var cancellationToken = _commitCancellationTokenSource.Token; await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); VerifyNotDismissed(); @@ -839,6 +845,9 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, bool previewChanges, CancellationToken cancellationToken) { CommitStateChange?.Invoke(this, true); + // Create a cancellationToken will be cancelled by either: + // 1. Cancel() is called. + // 2. IUIThreadOperationContext get cancelled. using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(operationContext.UserCancellationToken, cancellationToken); var linkedCancellationToken = operationContext.UserCancellationToken; @@ -878,7 +887,6 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( RenameLogMessage.UserActionOutcome.Committed, previewChanges, async () => { - CommitState = CommitState.StartApplyChanges; var error = await TryApplyRenameAsync(newSolution, linkedCancellationToken).ConfigureAwait(false); if (error is not null) { diff --git a/src/EditorFeatures/Test2/Rename/RenameTagProducerTests.vb b/src/EditorFeatures/Test2/Rename/RenameTagProducerTests.vb index 4a5512f974280..8a3efbe29e7f9 100644 --- a/src/EditorFeatures/Test2/Rename/RenameTagProducerTests.vb +++ b/src/EditorFeatures/Test2/Rename/RenameTagProducerTests.vb @@ -89,7 +89,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename session.Cancel() VerifyBufferContentsInWorkspace(actualWorkspace, actualWorkspace) ElseIf sessionCommit Then - Await session.CommitAsync(previewChanges:=False, CancellationToken.None) + Await session.CommitAsync(previewChanges:=False) VerifyBufferContentsInWorkspace(actualWorkspace, resolvedConflictWorkspace) End If End If diff --git a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb index 397b10d83d23a..ad17bb6672737 100644 --- a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb +++ b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb @@ -111,7 +111,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.LineCommit Throw New NotImplementedException() End Sub - Public Function CommitAsync(previewChanges As Boolean, cancellationToken As CancellationToken) As Task(Of Boolean) Implements IInlineRenameSession.CommitAsync + Public Function CommitAsync(previewChanges As Boolean) As Task(Of Boolean) Implements IInlineRenameSession.CommitAsync Throw New NotImplementedException End Function End Class From a4b5f8955f11591d46e161113913fe14bd633c4b Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Tue, 20 Aug 2024 13:36:13 -0700 Subject: [PATCH 33/59] Fix errors after merge --- .../CommandHandlers/RenameCommandHandler.cs | 4 ++-- .../Core/InlineRename/InlineRenameSession.cs | 17 ++++++----------- .../LineCommit/CommitTestData.vb | 2 +- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs index 03e0c6fd140a1..c1da180825457 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs @@ -96,11 +96,11 @@ protected override void SetAdornmentFocusToPreviousElement(ITextView textView) } } - protected override async Task CommitAndSetFocusAsync(InlineRenameSession activeSession, ITextView textView, CancellationToken cancellationToken) + protected override async Task CommitAndSetFocusAsync(InlineRenameSession activeSession, ITextView textView) { try { - await base.CommitAndSetFocusAsync(activeSession, textView, cancellationToken).ConfigureAwait(false); + await base.CommitAndSetFocusAsync(activeSession, textView).ConfigureAwait(false); } catch (NotSupportedException ex) { diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index ab37da4e965fa..a7cc5592de88a 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -126,8 +126,6 @@ private set /// private CancellationTokenSource _conflictResolutionTaskCancellationSource = new(); - private CancellationTokenSource _commitCancellationTokenSource; - private Task _commitTask; public bool IsCommitInProgress => !_dismissed && _commitTask is not null && _commitTask is not { Status: TaskStatus.RanToCompletion or TaskStatus.Faulted or TaskStatus.Canceled }; @@ -684,7 +682,6 @@ private async Task DismissUIAndRollbackEditsAndEndRenameSessionAsync( // We're about to perform the final commit action. No need to do any of our BG work to find-refs or compute conflicts. _cancellationTokenSource.Cancel(); _conflictResolutionTaskCancellationSource.Cancel(); - _commitCancellationTokenSource?.Cancel(); // Close the keep alive session we have open with OOP, allowing it to release the solution it is holding onto. _keepAliveSession.Dispose(); @@ -750,15 +747,15 @@ private bool CommitSynchronously(bool previewChanges) return _threadingContext.JoinableTaskFactory.Run(() => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: false)); } - public async Task CommitAsync(bool previewChanges) + public async Task CommitAsync(bool previewChanges) { if (this.RenameService.GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameAsynchronously)) { - return await StartCommitAsync(previewChanges, canUseBackgroundWorkIndicator: true).ConfigureAwait(false); + await StartCommitAsync(previewChanges, canUseBackgroundWorkIndicator: true).ConfigureAwait(false); } else { - return CommitSynchronously(previewChanges); + CommitSynchronously(previewChanges); } } @@ -812,7 +809,7 @@ private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackg _triggerView, TriggerSpan, EditorFeaturesResources.Computing_Rename_information, cancelOnEdit: false, cancelOnFocusLost: false); - await CommitCoreAsync(context, previewChanges, cancellationToken).ConfigureAwait(true); + await CommitCoreAsync(context, previewChanges).ConfigureAwait(true); } else { @@ -825,7 +822,7 @@ private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackg // .ConfigureAwait(true); so we can return to the UI thread to dispose the operation context. It // has a non-JTF threading dependency on the main thread. So it can deadlock if you call it on a BG // thread when in a blocking JTF call. - await CommitCoreAsync(context, previewChanges, cancellationToken).ConfigureAwait(true); + await CommitCoreAsync(context, previewChanges).ConfigureAwait(true); } } catch (OperationCanceledException) @@ -839,14 +836,12 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( return true; } - private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, bool previewChanges, CancellationToken cancellationToken) + private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, bool previewChanges) { CommitStateChange?.Invoke(this, true); // Create a cancellationToken will be cancelled by either: // 1. Cancel() is called. // 2. IUIThreadOperationContext get cancelled. - using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(operationContext.UserCancellationToken, cancellationToken); - var linkedCancellationToken = operationContext.UserCancellationToken; var eventName = previewChanges ? FunctionId.Rename_CommitCoreWithPreview : FunctionId.Rename_CommitCore; using (Logger.LogBlock(eventName, KeyValueLogMessage.Create(LogType.UserAction), linkedCancellationToken)) diff --git a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb index ad17bb6672737..e35e6c2e97d32 100644 --- a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb +++ b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb @@ -111,7 +111,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.LineCommit Throw New NotImplementedException() End Sub - Public Function CommitAsync(previewChanges As Boolean) As Task(Of Boolean) Implements IInlineRenameSession.CommitAsync + Public Function CommitAsync(previewChanges As Boolean) As Task Implements IInlineRenameSession.CommitAsync Throw New NotImplementedException End Function End Class From 27e6efe2539b550a45dc2d80a709005353648b5b Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Tue, 20 Aug 2024 14:23:42 -0700 Subject: [PATCH 34/59] Add one more check --- .../Core/InlineRename/InlineRenameSession.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index a7cc5592de88a..fee9330ec8dfd 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -126,6 +126,9 @@ private set /// private CancellationTokenSource _conflictResolutionTaskCancellationSource = new(); + /// + /// Task to track the commit operation of the session. Null if commit operation has never started. + /// private Task _commitTask; public bool IsCommitInProgress => !_dismissed && _commitTask is not null && _commitTask is not { Status: TaskStatus.RanToCompletion or TaskStatus.Faulted or TaskStatus.Canceled }; @@ -761,12 +764,21 @@ public async Task CommitAsync(bool previewChanges) private async Task StartCommitAsync(bool previewChanges, bool canUseBackgroundWorkIndicator) { + // We are going to commit in async manner. + // 1. If the session is dismissed, stop and do not start another commit task + // 2. If the commit task is in progress, await the in progress task. + // _dismissed is only changed by thread, + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); if (_dismissed) { return false; } - _commitTask ??= CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator); + if (_commitTask is null || !IsCommitInProgress) + { + _commitTask = CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator); + } + return await _commitTask.ConfigureAwait(false); } From 9d029b9d4ccfb9d4af0d64ded68587865d9ff122 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Tue, 20 Aug 2024 17:42:21 -0700 Subject: [PATCH 35/59] Add commment --- .../InlineRename/UI/Adornment/RenameFlyoutViewModel.cs | 6 ++++-- .../Core/InlineRename/InlineRenameSession.cs | 7 ++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index 9a2748af8a7da..b0a3788728347 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -72,9 +72,11 @@ public RenameFlyoutViewModel( RegisterOleComponent(); } - private void SessionOnCommitStateChange(object sender, bool e) + private void SessionOnCommitStateChange(object sender, bool commitStarts) { - Visibility = e ? Visibility.Collapsed : Visibility.Visible; + // When commit in progress, we will use background indicator to show the progress. + // Rename flyout would hide the tooltip so we need to hide it. + Visibility = commitStarts ? Visibility.Collapsed : Visibility.Visible; } public SmartRenameViewModel? SmartRenameViewModel { get; } diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index fee9330ec8dfd..76078ade59e06 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -764,11 +764,9 @@ public async Task CommitAsync(bool previewChanges) private async Task StartCommitAsync(bool previewChanges, bool canUseBackgroundWorkIndicator) { + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); // We are going to commit in async manner. // 1. If the session is dismissed, stop and do not start another commit task - // 2. If the commit task is in progress, await the in progress task. - // _dismissed is only changed by thread, - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); if (_dismissed) { return false; @@ -776,7 +774,10 @@ private async Task StartCommitAsync(bool previewChanges, bool canUseBackgr if (_commitTask is null || !IsCommitInProgress) { + // 2. Either commit never starts in this session + // or the prev commit operation ends (like user don't like the preview result and click cancel button) _commitTask = CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator); + } return await _commitTask.ConfigureAwait(false); From 2cd8e81351ae5054d1821fe839ce77dfca5fc296 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Tue, 20 Aug 2024 17:52:57 -0700 Subject: [PATCH 36/59] Simplify --- .../AbstractRenameCommandHandler.cs | 3 ++- ...stractRenameCommandHandler_ReturnHandler.cs | 2 +- .../Core/InlineRename/InlineRenameSession.cs | 18 +++++++----------- .../LineCommit/CommitTestData.vb | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs index d98a8ca2534ae..e5045481e036c 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs @@ -65,6 +65,7 @@ private void HandlePossibleTypingCommand(TArgs args, Action nextHandler, return; } + // If commit in progress, don't do anything, as we don't want user change the text view if (_renameService.ActiveSession.IsCommitInProgress) { return; @@ -105,7 +106,7 @@ private void CommitIfActive(EditorCommandArgs args) { var selection = args.TextView.Selection.VirtualSelectedSpans.First(); - _ = _renameService.ActiveSession.CommitAsync(previewChanges: false); + _renameService.ActiveSession.Commit(); var translatedSelection = selection.TranslateTo(args.TextView.TextBuffer.CurrentSnapshot); args.TextView.Selection.Select(translatedSelection.Start, translatedSelection.End); diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs index abddebadd7847..de540e91a6dfc 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs @@ -21,7 +21,7 @@ public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext co if (_renameService.ActiveSession != null) { // Prevent Editor's typing responsiveness auto canceling the rename operation. - // InlineRenameSession will call IBackgroundWorkIndicator to sets up our own IUIThreadOperationContext + // InlineRenameSession will call IUIThreadOperationExecutor to sets up our own IUIThreadOperationContext context.OperationContext.TakeOwnership(); _ = CommitAndSetFocusAsync(_renameService.ActiveSession, args.TextView).ReportNonFatalErrorAsync(); return true; diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 76078ade59e06..e0f42b1c612ec 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -841,8 +841,7 @@ private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackg catch (OperationCanceledException) { await DismissUIAndRollbackEditsAndEndRenameSessionAsync( - RenameLogMessage.UserActionOutcome.Canceled | RenameLogMessage.UserActionOutcome.Committed, - previewChanges).ConfigureAwait(false); + RenameLogMessage.UserActionOutcome.Canceled | RenameLogMessage.UserActionOutcome.Committed, previewChanges).ConfigureAwait(false); return false; } @@ -852,14 +851,11 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, bool previewChanges) { CommitStateChange?.Invoke(this, true); - // Create a cancellationToken will be cancelled by either: - // 1. Cancel() is called. - // 2. IUIThreadOperationContext get cancelled. - var linkedCancellationToken = operationContext.UserCancellationToken; + var cancellationToken = operationContext.UserCancellationToken; var eventName = previewChanges ? FunctionId.Rename_CommitCoreWithPreview : FunctionId.Rename_CommitCore; - using (Logger.LogBlock(eventName, KeyValueLogMessage.Create(LogType.UserAction), linkedCancellationToken)) + using (Logger.LogBlock(eventName, KeyValueLogMessage.Create(LogType.UserAction), cancellationToken)) { - var info = await _conflictResolutionTask.JoinAsync(linkedCancellationToken).ConfigureAwait(true); + var info = await _conflictResolutionTask.JoinAsync(cancellationToken).ConfigureAwait(true); var newSolution = info.NewSolution; if (previewChanges) @@ -867,7 +863,7 @@ private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, b var previewService = Workspace.Services.GetService(); // The preview service needs to be called from the UI thread, since it's doing COM calls underneath. - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(linkedCancellationToken); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); newSolution = previewService.PreviewChanges( string.Format(EditorFeaturesResources.Preview_Changes_0, EditorFeaturesResources.Rename), "vs.csharp.refactoring.rename", @@ -892,10 +888,10 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( RenameLogMessage.UserActionOutcome.Committed, previewChanges, async () => { - var error = await TryApplyRenameAsync(newSolution, linkedCancellationToken).ConfigureAwait(false); + var error = await TryApplyRenameAsync(newSolution, cancellationToken).ConfigureAwait(false); if (error is not null) { - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(linkedCancellationToken); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var notificationService = Workspace.Services.GetService(); notificationService.SendNotification( error.Value.message, EditorFeaturesResources.Rename_Symbol, error.Value.severity); diff --git a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb index e35e6c2e97d32..a97faa06717eb 100644 --- a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb +++ b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb @@ -112,7 +112,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.LineCommit End Sub Public Function CommitAsync(previewChanges As Boolean) As Task Implements IInlineRenameSession.CommitAsync - Throw New NotImplementedException + Throw New NotImplementedException() End Function End Class End Class From 270b294b5812541dd46ea6a479afab69fc5c9434 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 21 Aug 2024 10:54:08 -0700 Subject: [PATCH 37/59] Fix test --- .../AbstractRenameCommandHandler_ReturnHandler.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs index de540e91a6dfc..2c49fdad2f460 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; @@ -20,10 +21,11 @@ public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext co { if (_renameService.ActiveSession != null) { + var token = _listener.BeginAsyncOperation(string.Concat(nameof(ExecuteCommand), ".", nameof(ReturnKeyCommandArgs))); // Prevent Editor's typing responsiveness auto canceling the rename operation. // InlineRenameSession will call IUIThreadOperationExecutor to sets up our own IUIThreadOperationContext context.OperationContext.TakeOwnership(); - _ = CommitAndSetFocusAsync(_renameService.ActiveSession, args.TextView).ReportNonFatalErrorAsync(); + _ = CommitAndSetFocusAsync(_renameService.ActiveSession, args.TextView).ReportNonFatalErrorAsync().CompletesAsyncOperation(token); return true; } From 22ada1558a3ddf7afc378f31a4d634cfe35b220e Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 21 Aug 2024 11:12:55 -0700 Subject: [PATCH 38/59] Add comment --- src/EditorFeatures/Core/IInlineRenameSession.cs | 1 + src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core/IInlineRenameSession.cs b/src/EditorFeatures/Core/IInlineRenameSession.cs index 431a1f6491f0d..8c0865052f40e 100644 --- a/src/EditorFeatures/Core/IInlineRenameSession.cs +++ b/src/EditorFeatures/Core/IInlineRenameSession.cs @@ -50,5 +50,6 @@ internal interface IInlineRenameSession /// /// Dismisses the rename session, completing the rename operation across all files. /// + /// The implementation would only be async when InlineRenameSessionOptionsStorage.RenameAsynchronously is set to true Task CommitAsync(bool previewChanges); } diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index e0f42b1c612ec..55be5ed82cd8e 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -777,7 +777,6 @@ private async Task StartCommitAsync(bool previewChanges, bool canUseBackgr // 2. Either commit never starts in this session // or the prev commit operation ends (like user don't like the preview result and click cancel button) _commitTask = CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator); - } return await _commitTask.ConfigureAwait(false); From 89eb553fae357f21db209cb206d029002e56ab87 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 21 Aug 2024 11:27:06 -0700 Subject: [PATCH 39/59] Also use async in legacy UI --- .../InlineRename/UI/Dashboard/RenameDashboard.xaml.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs index 482304aa00701..4dceb855de1b0 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using System.Windows; using System.Windows.Automation.Peers; using System.Windows.Controls; @@ -328,10 +329,15 @@ private void Apply_Click(object sender, RoutedEventArgs e) => Commit(); private void Commit() + { + _ = CommitAsync(); + } + + private async Task CommitAsync() { try { - _model.Session.Commit(); + await _model.Session.CommitAsync(previewChanges: false).ConfigureAwait(true); _textView.VisualElement.Focus(); } catch (NotSupportedException ex) From c676263087caa633d474d01ea5ddcd6486189d0f Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 21 Aug 2024 12:58:41 -0700 Subject: [PATCH 40/59] Bind to checkbox --- .../UI/Dashboard/RenameDashboard.xaml | 6 ++--- .../UI/Dashboard/RenameDashboardViewModel.cs | 26 +++++++++++++++++-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml index 6e78eb41115aa..16d67bfc6f47a 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml @@ -145,8 +145,8 @@ - - + + - + diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs index e75ed153380ac..7cf8e79b0d90c 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs @@ -20,6 +20,7 @@ internal class RenameDashboardViewModel : INotifyPropertyChanged, IDisposable private int _resolvableConflictCount; private int _unresolvableConflictCount; private bool _isReplacementTextValid; + private bool _commitNotStart; public RenameDashboardViewModel(InlineRenameSession session) { @@ -29,9 +30,11 @@ public RenameDashboardViewModel(InlineRenameSession session) Session.ReferenceLocationsChanged += OnReferenceLocationsChanged; Session.ReplacementsComputed += OnReplacementsComputed; Session.ReplacementTextChanged += OnReplacementTextChanged; + Session.CommitStateChange += CommitStateChange; // Set the flag to true by default if we're showing the option. _isReplacementTextValid = true; + _commitNotStart = true; } public event PropertyChangedEventHandler PropertyChanged; @@ -140,11 +143,29 @@ private void UpdateSeverity() } } + private void CommitStateChange(object sender, bool commitStart) + => CommitNotStart = !commitStart; + + public bool CommitNotStart + { + get => _commitNotStart; + set + { + if (_commitNotStart != value) + { + _commitNotStart = value; + NotifyPropertyChanged(); + NotifyPropertyChanged(nameof(IsRenameOverloadsEditable)); + NotifyPropertyChanged(nameof(AllowFileRename)); + } + } + } + public InlineRenameSession Session { get; } public RenameDashboardSeverity Severity => _severity; - public bool AllowFileRename => Session.FileRenameInfo == InlineRenameFileRenameInfo.Allowed && _isReplacementTextValid; + public bool AllowFileRename => Session.FileRenameInfo == InlineRenameFileRenameInfo.Allowed && _isReplacementTextValid && _commitNotStart; public bool ShowFileRename => Session.FileRenameInfo != InlineRenameFileRenameInfo.NotAllowed; public string FileRenameString => Session.FileRenameInfo switch { @@ -226,7 +247,7 @@ public Visibility RenameOverloadsVisibility => Session.HasRenameOverloads ? Visibility.Visible : Visibility.Collapsed; public bool IsRenameOverloadsEditable - => !Session.MustRenameOverloads; + => !Session.MustRenameOverloads && CommitNotStart; public bool DefaultRenameOverloadFlag { @@ -292,6 +313,7 @@ public void Dispose() Session.ReplacementTextChanged -= OnReplacementTextChanged; Session.ReferenceLocationsChanged -= OnReferenceLocationsChanged; Session.ReplacementsComputed -= OnReplacementsComputed; + Session.CommitStateChange -= CommitStateChange; } } } From 4360883edda8277e782ca6a35d34b8e16f5d0561 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 21 Aug 2024 14:26:32 -0700 Subject: [PATCH 41/59] Add comment --- .../Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs | 2 +- .../InlineRename/UI/Dashboard/RenameDashboardViewModel.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index b0a3788728347..6e59f6f454a36 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -75,7 +75,7 @@ public RenameFlyoutViewModel( private void SessionOnCommitStateChange(object sender, bool commitStarts) { // When commit in progress, we will use background indicator to show the progress. - // Rename flyout would hide the tooltip so we need to hide it. + // Rename flyout would hide the tooltip so we need to collapse it. Visibility = commitStarts ? Visibility.Collapsed : Visibility.Visible; } diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs index 7cf8e79b0d90c..b7a24a9952cda 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs @@ -154,6 +154,7 @@ public bool CommitNotStart if (_commitNotStart != value) { _commitNotStart = value; + // Disable/Enable these checkbox in UI based on if commit is in-progress or not NotifyPropertyChanged(); NotifyPropertyChanged(nameof(IsRenameOverloadsEditable)); NotifyPropertyChanged(nameof(AllowFileRename)); From 5ccde9327aacd5a73dcc0c46ca77c634b69ada76 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Thu, 22 Aug 2024 16:52:16 -0700 Subject: [PATCH 42/59] Directly report errors --- .../UI/Adornment/RenameFlyoutViewModel.cs | 28 +------------------ 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index 6e59f6f454a36..d9d03dfc7ae4a 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -250,36 +250,10 @@ public bool Submit() } SmartRenameViewModel?.Commit(IdentifierText); - _ = CommitAsync().ReportNonFatalErrorAsync(); + _ = Session.CommitAsync(previewChanges: false).ReportNonFatalErrorAsync(); return true; } - private async Task CommitAsync() - { - try - { - await Session.CommitAsync(previewChanges: false).ReportNonFatalErrorAsync().ConfigureAwait(false); - } - catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.Critical)) - { - // Show a nice error to the user via an info bar - var errorReportingService = Session.Workspace.Services.GetService(); - if (errorReportingService is null) - { - return; - } - - errorReportingService.ShowGlobalErrorInfo( - message: string.Format(EditorFeaturesWpfResources.Error_performing_rename_0, ex.Message), - TelemetryFeatureName.InlineRename, - ex, - new InfoBarUI( - WorkspacesResources.Show_Stack_Trace, - InfoBarUI.UIKind.HyperLink, - () => errorReportingService.ShowDetailedErrorInfo(ex), closeAfterAction: true)); - } - } - public void Cancel() { SmartRenameViewModel?.Cancel(); From ae55915568965d31200fa77324b21360fc0c098a Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Thu, 22 Aug 2024 17:01:25 -0700 Subject: [PATCH 43/59] Wrap try-catch --- .../Core/InlineRename/InlineRenameSession.cs | 86 +++++++++++-------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 55be5ed82cd8e..2af692a1fa143 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -849,54 +849,64 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, bool previewChanges) { + // Notify the UI commit is started. + // In legacy UI dashboard, it will disable all rename option buttons (like rename comment). + // In renameFlyout, it will collapse the UI because renameFlyout will hide the background indicator. CommitStateChange?.Invoke(this, true); var cancellationToken = operationContext.UserCancellationToken; var eventName = previewChanges ? FunctionId.Rename_CommitCoreWithPreview : FunctionId.Rename_CommitCore; - using (Logger.LogBlock(eventName, KeyValueLogMessage.Create(LogType.UserAction), cancellationToken)) + try { - var info = await _conflictResolutionTask.JoinAsync(cancellationToken).ConfigureAwait(true); - var newSolution = info.NewSolution; - - if (previewChanges) + using (Logger.LogBlock(eventName, KeyValueLogMessage.Create(LogType.UserAction), cancellationToken)) { - var previewService = Workspace.Services.GetService(); - - // The preview service needs to be called from the UI thread, since it's doing COM calls underneath. - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - newSolution = previewService.PreviewChanges( - string.Format(EditorFeaturesResources.Preview_Changes_0, EditorFeaturesResources.Rename), - "vs.csharp.refactoring.rename", - string.Format(EditorFeaturesResources.Rename_0_to_1_colon, this.OriginalSymbolName, this.ReplacementText), - RenameInfo.FullDisplayName, - RenameInfo.Glyph, - newSolution, - TriggerDocument.Project.Solution); - - if (newSolution == null) + var info = await _conflictResolutionTask.JoinAsync(cancellationToken).ConfigureAwait(true); + var newSolution = info.NewSolution; + + if (previewChanges) { - // User clicked cancel. - CommitStateChange?.Invoke(this, false); - return; + var previewService = Workspace.Services.GetService(); + + // The preview service needs to be called from the UI thread, since it's doing COM calls underneath. + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + newSolution = previewService.PreviewChanges( + string.Format(EditorFeaturesResources.Preview_Changes_0, EditorFeaturesResources.Rename), + "vs.csharp.refactoring.rename", + string.Format(EditorFeaturesResources.Rename_0_to_1_colon, this.OriginalSymbolName, this.ReplacementText), + RenameInfo.FullDisplayName, + RenameInfo.Glyph, + newSolution, + TriggerDocument.Project.Solution); + + if (newSolution == null) + { + // User clicked cancel. + return; + } } - } - // The user hasn't canceled by now, so we're done waiting for them. Off to rename! - using var _ = operationContext.AddScope(allowCancellation: false, EditorFeaturesResources.Updating_files); + // The user hasn't canceled by now, so we're done waiting for them. Off to rename! + using var _ = operationContext.AddScope(allowCancellation: false, EditorFeaturesResources.Updating_files); - await DismissUIAndRollbackEditsAndEndRenameSessionAsync( - RenameLogMessage.UserActionOutcome.Committed, previewChanges, - async () => - { - var error = await TryApplyRenameAsync(newSolution, cancellationToken).ConfigureAwait(false); - if (error is not null) + await DismissUIAndRollbackEditsAndEndRenameSessionAsync( + RenameLogMessage.UserActionOutcome.Committed, previewChanges, + async () => { - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - var notificationService = Workspace.Services.GetService(); - notificationService.SendNotification( - error.Value.message, EditorFeaturesResources.Rename_Symbol, error.Value.severity); - } - CommitStateChange?.Invoke(this, false); - }).ConfigureAwait(false); + var error = await TryApplyRenameAsync(newSolution, cancellationToken).ConfigureAwait(false); + if (error is not null) + { + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + var notificationService = Workspace.Services.GetService(); + notificationService.SendNotification( + error.Value.message, EditorFeaturesResources.Rename_Symbol, error.Value.severity); + } + }).ConfigureAwait(false); + } + } + finally + { + // Notify the rename UI the commit ends. + // User might just preview the change so UI needs to reset its state when commit finish. + CommitStateChange?.Invoke(this, false); } } From 91089e95d824fc852cd0374c04edeb123c22be13 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Thu, 22 Aug 2024 18:32:04 -0700 Subject: [PATCH 44/59] Add comment and threadingContext --- .../UI/Adornment/RenameFlyoutViewModel.cs | 13 +------------ .../UI/Dashboard/RenameDashboard.xaml.cs | 1 + .../UI/Dashboard/RenameDashboardViewModel.cs | 13 +++++++++++-- .../InlineRename/UI/InlineRenameAdornmentManager.cs | 2 +- .../Test2/Rename/RenameViewModelTests.vb | 4 ++-- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index d9d03dfc7ae4a..c581905ce9fac 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -9,20 +9,16 @@ using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; using System.Windows; using System.Windows.Interop; using Microsoft.CodeAnalysis.Editor.InlineRename; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.EditorFeatures.Lightup; -using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.InlineRename; using Microsoft.CodeAnalysis.InlineRename.UI.SmartRename; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.CodeAnalysis.Telemetry; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Imaging.Interop; @@ -229,14 +225,7 @@ public bool AllowUserInput public Visibility Visibility { get => _visibility; - set - { - if (value != _visibility) - { - Set(ref _visibility, value); - NotifyPropertyChanged(); - } - } + set => Set(ref _visibility, value); } public TextSpan StartingSelection { get; } diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs index 4dceb855de1b0..bfcd65dc44d56 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml.cs @@ -337,6 +337,7 @@ private async Task CommitAsync() { try { + // ConfigureAwait(true) because later need to set focus on UI element. await _model.Session.CommitAsync(previewChanges: false).ConfigureAwait(true); _textView.VisualElement.Focus(); } diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs index b7a24a9952cda..a2d68a64724ad 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs @@ -10,19 +10,22 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Windows; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.InlineRename; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename { internal class RenameDashboardViewModel : INotifyPropertyChanged, IDisposable { + private readonly IThreadingContext _threadingContext; private RenameDashboardSeverity _severity = RenameDashboardSeverity.None; private int _resolvableConflictCount; private int _unresolvableConflictCount; private bool _isReplacementTextValid; private bool _commitNotStart; - public RenameDashboardViewModel(InlineRenameSession session) + public RenameDashboardViewModel(InlineRenameSession session, IThreadingContext threadingContext) { Session = session; SearchText = EditorFeaturesResources.Searching; @@ -35,6 +38,7 @@ public RenameDashboardViewModel(InlineRenameSession session) // Set the flag to true by default if we're showing the option. _isReplacementTextValid = true; _commitNotStart = true; + _threadingContext = threadingContext; } public event PropertyChangedEventHandler PropertyChanged; @@ -148,9 +152,14 @@ private void CommitStateChange(object sender, bool commitStart) public bool CommitNotStart { - get => _commitNotStart; + get + { + _threadingContext.ThrowIfNotOnUIThread(); + return _commitNotStart; + } set { + _threadingContext.ThrowIfNotOnUIThread(); if (_commitNotStart != value) { _commitNotStart = value; diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameAdornmentManager.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameAdornmentManager.cs index b76bcf35f104a..16bd60a2ec95b 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameAdornmentManager.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameAdornmentManager.cs @@ -162,7 +162,7 @@ private void UpdateAdornments() else { var newAdornment = new RenameDashboard( - (RenameDashboardViewModel)s_createdViewModels.GetValue(_renameService.ActiveSession, session => new RenameDashboardViewModel(session)), + (RenameDashboardViewModel)s_createdViewModels.GetValue(_renameService.ActiveSession, session => new RenameDashboardViewModel(session, _threadingContext)), _editorFormatMapService, _textView); diff --git a/src/EditorFeatures/Test2/Rename/RenameViewModelTests.vb b/src/EditorFeatures/Test2/Rename/RenameViewModelTests.vb index 19ecabcdd2cd3..b6c9863caa1f8 100644 --- a/src/EditorFeatures/Test2/Rename/RenameViewModelTests.vb +++ b/src/EditorFeatures/Test2/Rename/RenameViewModelTests.vb @@ -585,8 +585,9 @@ class D : B edit.Apply() End Using + Dim threadingContext = workspace.ExportProvider.GetExport(Of IThreadingContext)().Value Using dashboard = New RenameDashboard( - New RenameDashboardViewModel(DirectCast(sessionInfo.Session, InlineRenameSession)), + New RenameDashboardViewModel(DirectCast(sessionInfo.Session, InlineRenameSession), threadingContext), editorFormatMapService:=Nothing, textView:=cursorDocument.GetTextView()) @@ -624,7 +625,6 @@ class D : B Dim TestQuickInfoBroker = New TestQuickInfoBroker() Dim listenerProvider = workspace.ExportProvider.GetExport(Of IAsynchronousOperationListenerProvider)().Value Dim editorFormatMapService = workspace.ExportProvider.GetExport(Of IEditorFormatMapService)().Value - Dim threadingContext = workspace.ExportProvider.GetExport(Of IThreadingContext)().Value Using flyout = New RenameFlyout( New RenameFlyoutViewModel(DirectCast(sessionInfo.Session, InlineRenameSession), selectionSpan:=Nothing, registerOleComponent:=False, globalOptions, threadingContext, listenerProvider, Nothing), ' Don't registerOleComponent in tests, it requires OleComponentManagers that don't exist in our host From 6256a96dfa07e50f7bb99a66fb3738752ff673a4 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Thu, 22 Aug 2024 20:48:09 -0700 Subject: [PATCH 45/59] Also forward commitSync to StartCommitAsync --- src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 2af692a1fa143..5ae78168b5fff 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -747,7 +747,7 @@ private bool CommitSynchronously(bool previewChanges) // which at least will allow the user to cancel the rename if they want. // // In the future we should remove this entrypoint and have all callers use CommitAsync instead. - return _threadingContext.JoinableTaskFactory.Run(() => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: false)); + return _threadingContext.JoinableTaskFactory.Run(() => StartCommitAsync(previewChanges, canUseBackgroundWorkIndicator: false)); } public async Task CommitAsync(bool previewChanges) From 66b289e49b8b13f0ae4e5d8c0fd27dd32e81ca2d Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Thu, 22 Aug 2024 22:18:24 -0700 Subject: [PATCH 46/59] Add comment --- .../Core/InlineRename/InlineRenameSession.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 5ae78168b5fff..c06a686ebb0a6 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -772,10 +772,15 @@ private async Task StartCommitAsync(bool previewChanges, bool canUseBackgr return false; } + // One session should only start one commit task. + // Start the task if + // 1. commit never starts in this session. (_commitTask is null) + // 2. There is no in-progress task. This would include + // a. Commit operation starts before, user previews the result, and cancel the commit + // b. In async commit operation while waiting the background task completed (user triggers the commit by enter key), then user's input might trigger Commit() again. Example: SaveCommandHandler. + // In this case we don't want to trigger commit again. if (_commitTask is null || !IsCommitInProgress) { - // 2. Either commit never starts in this session - // or the prev commit operation ends (like user don't like the preview result and click cancel button) _commitTask = CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator); } From 4b810d345cfc56cbf356a3d35344637e1b521571 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Thu, 22 Aug 2024 22:23:00 -0700 Subject: [PATCH 47/59] Clean up --- .../InlineRename/UI/Dashboard/RenameDashboardViewModel.cs | 2 +- src/EditorFeatures/Core/IInlineRenameSession.cs | 2 +- src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs index a2d68a64724ad..0259be9b35b96 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs @@ -175,7 +175,7 @@ public bool CommitNotStart public RenameDashboardSeverity Severity => _severity; - public bool AllowFileRename => Session.FileRenameInfo == InlineRenameFileRenameInfo.Allowed && _isReplacementTextValid && _commitNotStart; + public bool AllowFileRename => Session.FileRenameInfo == InlineRenameFileRenameInfo.Allowed && _isReplacementTextValid && CommitNotStart; public bool ShowFileRename => Session.FileRenameInfo != InlineRenameFileRenameInfo.NotAllowed; public string FileRenameString => Session.FileRenameInfo switch { diff --git a/src/EditorFeatures/Core/IInlineRenameSession.cs b/src/EditorFeatures/Core/IInlineRenameSession.cs index 8c0865052f40e..cf79125e50d8e 100644 --- a/src/EditorFeatures/Core/IInlineRenameSession.cs +++ b/src/EditorFeatures/Core/IInlineRenameSession.cs @@ -50,6 +50,6 @@ internal interface IInlineRenameSession /// /// Dismisses the rename session, completing the rename operation across all files. /// - /// The implementation would only be async when InlineRenameSessionOptionsStorage.RenameAsynchronously is set to true + /// It would only be async when InlineRenameSessionOptionsStorage.RenameAsynchronously is set to true Task CommitAsync(bool previewChanges); } diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index c06a686ebb0a6..4ab516b80006a 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -131,7 +131,7 @@ private set /// private Task _commitTask; - public bool IsCommitInProgress => !_dismissed && _commitTask is not null && _commitTask is not { Status: TaskStatus.RanToCompletion or TaskStatus.Faulted or TaskStatus.Canceled }; + public bool IsCommitInProgress => !_dismissed && _commitTask is not { IsCompleted: true }; /// /// The initial text being renamed. From 374f8e947e7f5c459eb278e8b3c76085b818c05b Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 23 Aug 2024 17:06:22 -0700 Subject: [PATCH 48/59] Fix test --- src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 4ab516b80006a..8f1e9a463961e 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -131,7 +131,7 @@ private set /// private Task _commitTask; - public bool IsCommitInProgress => !_dismissed && _commitTask is not { IsCompleted: true }; + public bool IsCommitInProgress => !_dismissed && _commitTask is { IsCompleted: false }; /// /// The initial text being renamed. From f4cf9a2ee8b82c40fd2f4a37bc028d46a0cdcf92 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 28 Aug 2024 15:55:15 -0700 Subject: [PATCH 49/59] Add comment --- .../InlineRename/CommandHandlers/RenameCommandHandler.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs index fb737df548b31..f038b8ed2e2e9 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs @@ -100,7 +100,8 @@ protected override async Task CommitAndSetFocusAsync(InlineRenameSession activeS { try { - await base.CommitAndSetFocusAsync(activeSession, textView, operationContext); + // ConfigureAwait(true) in case exception needs to be reported. + await base.CommitAndSetFocusAsync(activeSession, textView, operationContext).ConfigureAwait(true); } catch (NotSupportedException ex) { From 318eedd6957f3c7d91e31c80ea394633e3cedf0b Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 28 Aug 2024 19:10:08 -0700 Subject: [PATCH 50/59] Remove a duplicate TakeOwnerShip() --- .../InlineRename/CommandHandlers/RenameCommandHandler.cs | 1 + .../CommandHandlers/AbstractRenameCommandHandler.cs | 1 - .../AbstractRenameCommandHandler_ReturnHandler.cs | 3 --- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs index f038b8ed2e2e9..f17005cbe2637 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs @@ -16,6 +16,7 @@ using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Telemetry; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename { diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs index bb4f4567009a8..c3d16944dc411 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs @@ -93,7 +93,6 @@ private void HandlePossibleTypingCommand(TArgs args, Action nextHandler, { // It's in a read-only area that is open, so let's commit the rename // and then let the character go through - CommitIfActiveAndCallNextHandler(args, nextHandler, operationContext); } else diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs index fd99d0b07cf37..702d81cf4dc5a 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs @@ -23,9 +23,6 @@ public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext co if (_renameService.ActiveSession != null) { var token = _listener.BeginAsyncOperation(string.Concat(nameof(ExecuteCommand), ".", nameof(ReturnKeyCommandArgs))); - // Prevent Editor's typing responsiveness auto canceling the rename operation. - // InlineRenameSession will call IUIThreadOperationExecutor to sets up our own IUIThreadOperationContext - context.OperationContext.TakeOwnership(); _ = CommitAndSetFocusAsync(_renameService.ActiveSession, args.TextView, context.OperationContext).ReportNonFatalErrorAsync().CompletesAsyncOperation(token); return true; } From 5e4bb05c1e92bac4c3350b8cea08c102ae195b16 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 28 Aug 2024 22:26:00 -0700 Subject: [PATCH 51/59] Change the behavior back to origin --- .../CommandHandlers/AbstractRenameCommandHandler.cs | 11 ++++++++--- ...stractRenameCommandHandler_OpenLineAboveHandler.cs | 2 +- ...stractRenameCommandHandler_OpenLineBelowHandler.cs | 2 +- .../AbstractRenameCommandHandler_RenameHandler.cs | 2 +- .../AbstractRenameCommandHandler_ReturnHandler.cs | 9 ++++++--- .../AbstractRenameCommandHandler_SaveHandler.cs | 2 +- .../Core/InlineRename/InlineRenameSession.cs | 9 +++------ 7 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs index c3d16944dc411..1cad4b640506d 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs @@ -108,7 +108,7 @@ private void CommitIfActive(EditorCommandArgs args, IUIThreadOperationContext op { var selection = args.TextView.Selection.VirtualSelectedSpans.First(); - CommitAsync(operationContext); + Commit(operationContext); var translatedSelection = selection.TranslateTo(args.TextView.TextBuffer.CurrentSnapshot); args.TextView.Selection.Select(translatedSelection.Start, translatedSelection.End); @@ -122,9 +122,14 @@ private void CommitIfActiveAndCallNextHandler(EditorCommandArgs args, Action nex nextHandler(); } - private Task CommitAsync(IUIThreadOperationContext operationContext) + private void Commit(IUIThreadOperationContext operationContext) { RoslynDebug.AssertNotNull(_renameService.ActiveSession); - return _renameService.ActiveSession.CommitAsync(previewChanges: false, operationContext); + if (_renameService.ActiveSession.IsCommitInProgress) + { + return; + } + + _renameService.ActiveSession.Commit(previewChanges: false, operationContext); } } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs index 8521ce205fbdd..830552a35e14c 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs @@ -17,7 +17,7 @@ public void ExecuteCommand(OpenLineAboveCommandArgs args, Action nextHandler, Co { HandlePossibleTypingCommand(args, nextHandler, context.OperationContext, (activeSession, operationContext, span) => { - CommitAsync(operationContext); + Commit(operationContext); nextHandler(); }); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs index f6f1436e84094..5bb99425cdae2 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs @@ -17,7 +17,7 @@ public void ExecuteCommand(OpenLineBelowCommandArgs args, Action nextHandler, Co { HandlePossibleTypingCommand(args, nextHandler, context.OperationContext, (activeSession, operationContext, span) => { - CommitAsync(operationContext); + Commit(operationContext); nextHandler(); }); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs index f410ea1a24d92..c900796feae65 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs @@ -79,7 +79,7 @@ private async Task ExecuteCommandAsync(RenameCommandArgs args, IUIThreadOperatio { // Otherwise, commit the existing session and start a new one. // ConfigureAwait(true) because we need to create another IBackgroundWorkIndicatorContext later. - await CommitAsync(editorOperationContext).ConfigureAwait(true); + await _renameService.ActiveSession.CommitAsync(previewChanges: false, editorOperationContext).ConfigureAwait(true); } } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs index 702d81cf4dc5a..9b534a02cd179 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs @@ -32,8 +32,11 @@ public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext co protected virtual async Task CommitAndSetFocusAsync(InlineRenameSession activeSession, ITextView textView, IUIThreadOperationContext operationContext) { - // ConfigureAwait(true) because it needs to set focus in UI later. - await CommitAsync(operationContext).ConfigureAwait(true); - SetFocusToTextView(textView); + if (_renameService.ActiveSession is not null) + { + // ConfigureAwait(true) because it needs to set focus in UI later. + await _renameService.ActiveSession.CommitAsync(previewChanges: false, operationContext).ConfigureAwait(true); + SetFocusToTextView(textView); + } } } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs index 1ab1a224231f3..132c8d0f42a5d 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs @@ -16,7 +16,7 @@ public bool ExecuteCommand(SaveCommandArgs args, CommandExecutionContext context { if (_renameService.ActiveSession != null) { - CommitAsync(context.OperationContext); + Commit(context.OperationContext); SetFocusToTextView(args.TextView); } diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 97670a60ce42c..91ed80d93b1f9 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -757,7 +757,7 @@ private bool CommitSynchronously(bool previewChanges, IUIThreadOperationContext // which at least will allow the user to cancel the rename if they want. // // In the future we should remove this entrypoint and have all callers use CommitAsync instead. - return _threadingContext.JoinableTaskFactory.Run(() => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: false, editorOperationContext)); + return _threadingContext.JoinableTaskFactory.Run(() => StartCommitAsync(previewChanges, canUseBackgroundWorkIndicator: false, editorOperationContext)); } /// @@ -788,13 +788,10 @@ private async Task StartCommitAsync(bool previewChanges, bool canUseBackgr // One session should only start one commit task. // Start the task if // 1. commit never starts in this session. (_commitTask is null) - // 2. There is no in-progress task. This would include - // a. Commit operation starts before, user previews the result, and cancel the commit - // b. In async commit operation while waiting the background task completed (user triggers the commit by enter key), then user's input might trigger Commit() again. Example: SaveCommandHandler. - // In this case we don't want to trigger commit again. + // 2. User choose to preview & cancel the result. (_commitTask is completed) if (_commitTask is null || !IsCommitInProgress) { - _commitTask = CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator, editorOperationContext); + _commitTask ??= CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator, editorOperationContext); } return await _commitTask.ConfigureAwait(false); From 5d01d76764703559b90a8cc19b4064a9fb021a9f Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 28 Aug 2024 22:34:36 -0700 Subject: [PATCH 52/59] Add assert --- src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 91ed80d93b1f9..6c2d346123886 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -752,6 +752,7 @@ public void Commit(bool previewChanges = false, IUIThreadOperationContext editor /// langword="false"/> otherwise private bool CommitSynchronously(bool previewChanges, IUIThreadOperationContext editorOperationContext = null) { + _threadingContext.ThrowIfNotOnUIThread(); // We're going to synchronously block the UI thread here. So we can't use the background work indicator (as // it needs the UI thread to update itself. This will force us to go through the Threaded-Wait-Dialog path // which at least will allow the user to cancel the rename if they want. From 6117838c2ee161c02fd73206d7d2b7c9ffc8a776 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 28 Aug 2024 22:52:27 -0700 Subject: [PATCH 53/59] Add comment --- .../CommandHandlers/AbstractRenameCommandHandler.cs | 10 ++++++++-- ...bstractRenameCommandHandler_OpenLineAboveHandler.cs | 2 +- ...bstractRenameCommandHandler_OpenLineBelowHandler.cs | 2 +- .../AbstractRenameCommandHandler_SaveHandler.cs | 2 +- .../Core/InlineRename/InlineRenameSession.cs | 2 +- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs index 1cad4b640506d..909b4c19d9f32 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs @@ -108,7 +108,7 @@ private void CommitIfActive(EditorCommandArgs args, IUIThreadOperationContext op { var selection = args.TextView.Selection.VirtualSelectedSpans.First(); - Commit(operationContext); + CommitOnTextEditAndSaveCommand(operationContext); var translatedSelection = selection.TranslateTo(args.TextView.TextBuffer.CurrentSnapshot); args.TextView.Selection.Select(translatedSelection.Start, translatedSelection.End); @@ -122,14 +122,20 @@ private void CommitIfActiveAndCallNextHandler(EditorCommandArgs args, Action nex nextHandler(); } - private void Commit(IUIThreadOperationContext operationContext) + private void CommitOnTextEditAndSaveCommand(IUIThreadOperationContext operationContext) { RoslynDebug.AssertNotNull(_renameService.ActiveSession); if (_renameService.ActiveSession.IsCommitInProgress) { + // When the commit is in-progress, don't sync wait for the commit. + // This might happen when user async commit the rename using 'enter' key, then they invoke 'save command'. We don't want to block UI thread again. return; } + // We only async commit the rename session when it is invoked by 'enter' key or from the button in UI. (Which should cover most cases) + // For other command handler still commit the session because we don't want to regress the behavior. + // Example: When the rename session is committed by 'SaveCommand', we want to ensure rename is committed, then save the document. + // If it's async rename, the document would still be dirty after 'SaveCommand' is executed. _renameService.ActiveSession.Commit(previewChanges: false, operationContext); } } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs index 830552a35e14c..24d6cb81e67cf 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs @@ -17,7 +17,7 @@ public void ExecuteCommand(OpenLineAboveCommandArgs args, Action nextHandler, Co { HandlePossibleTypingCommand(args, nextHandler, context.OperationContext, (activeSession, operationContext, span) => { - Commit(operationContext); + CommitOnTextEditAndSaveCommand(operationContext); nextHandler(); }); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs index 5bb99425cdae2..c858c7551d9b7 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs @@ -17,7 +17,7 @@ public void ExecuteCommand(OpenLineBelowCommandArgs args, Action nextHandler, Co { HandlePossibleTypingCommand(args, nextHandler, context.OperationContext, (activeSession, operationContext, span) => { - Commit(operationContext); + CommitOnTextEditAndSaveCommand(operationContext); nextHandler(); }); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs index 132c8d0f42a5d..d31eee2177b23 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs @@ -16,7 +16,7 @@ public bool ExecuteCommand(SaveCommandArgs args, CommandExecutionContext context { if (_renameService.ActiveSession != null) { - Commit(context.OperationContext); + CommitOnTextEditAndSaveCommand(context.OperationContext); SetFocusToTextView(args.TextView); } diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 6c2d346123886..012f27de6ad32 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -789,7 +789,7 @@ private async Task StartCommitAsync(bool previewChanges, bool canUseBackgr // One session should only start one commit task. // Start the task if // 1. commit never starts in this session. (_commitTask is null) - // 2. User choose to preview & cancel the result. (_commitTask is completed) + // 2. User chooses to preview & cancel the result. (_commitTask is completed) if (_commitTask is null || !IsCommitInProgress) { _commitTask ??= CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator, editorOperationContext); From 37b496db53d39351a5e2089081dfa6ebb93296c6 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Thu, 19 Sep 2024 15:38:44 -0700 Subject: [PATCH 54/59] Fix missing code after merge --- .../Core/InlineRename/InlineRenameSession.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index f2a1ffb585305..4b1629446f410 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -882,6 +882,23 @@ private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, b if (previewChanges) { var previewService = Workspace.Services.GetService(); + + // The preview service needs to be called from the UI thread, since it's doing COM calls underneath. + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + newSolution = previewService.PreviewChanges( + string.Format(EditorFeaturesResources.Preview_Changes_0, EditorFeaturesResources.Rename), + "vs.csharp.refactoring.rename", + string.Format(EditorFeaturesResources.Rename_0_to_1_colon, this.OriginalSymbolName, this.ReplacementText), + RenameInfo.FullDisplayName, + RenameInfo.Glyph, + newSolution, + TriggerDocument.Project.Solution); + + if (newSolution == null) + { + // User clicked cancel. + return; + } } // The user hasn't canceled by now, so we're done waiting for them. Off to rename! From 82ae965f727ec6380ae63b4696587e986cdf456a Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Thu, 19 Sep 2024 15:40:08 -0700 Subject: [PATCH 55/59] Fix missing code after merge --- .../Core/InlineRename/InlineRenameSession.cs | 95 ++++++++++--------- 1 file changed, 51 insertions(+), 44 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 4b1629446f410..f25b3c7ac00c6 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -874,62 +874,69 @@ private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, b CommitStateChange?.Invoke(this, true); var cancellationToken = operationContext.UserCancellationToken; var eventName = previewChanges ? FunctionId.Rename_CommitCoreWithPreview : FunctionId.Rename_CommitCore; - using (Logger.LogBlock(eventName, KeyValueLogMessage.Create(LogType.UserAction), cancellationToken)) + try { - var info = await _conflictResolutionTask.JoinAsync(cancellationToken).ConfigureAwait(true); - var newSolution = info.NewSolution; - - if (previewChanges) + using (Logger.LogBlock(eventName, KeyValueLogMessage.Create(LogType.UserAction), cancellationToken)) { - var previewService = Workspace.Services.GetService(); + var info = await _conflictResolutionTask.JoinAsync(cancellationToken).ConfigureAwait(true); + var newSolution = info.NewSolution; - // The preview service needs to be called from the UI thread, since it's doing COM calls underneath. - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - newSolution = previewService.PreviewChanges( - string.Format(EditorFeaturesResources.Preview_Changes_0, EditorFeaturesResources.Rename), - "vs.csharp.refactoring.rename", - string.Format(EditorFeaturesResources.Rename_0_to_1_colon, this.OriginalSymbolName, this.ReplacementText), - RenameInfo.FullDisplayName, - RenameInfo.Glyph, - newSolution, - TriggerDocument.Project.Solution); - - if (newSolution == null) + if (previewChanges) { - // User clicked cancel. - return; + var previewService = Workspace.Services.GetService(); + + // The preview service needs to be called from the UI thread, since it's doing COM calls underneath. + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + newSolution = previewService.PreviewChanges( + string.Format(EditorFeaturesResources.Preview_Changes_0, EditorFeaturesResources.Rename), + "vs.csharp.refactoring.rename", + string.Format(EditorFeaturesResources.Rename_0_to_1_colon, this.OriginalSymbolName, this.ReplacementText), + RenameInfo.FullDisplayName, + RenameInfo.Glyph, + newSolution, + TriggerDocument.Project.Solution); + + if (newSolution == null) + { + // User clicked cancel. + return; + } } - } - // The user hasn't canceled by now, so we're done waiting for them. Off to rename! - using var _1 = operationContext.AddScope(allowCancellation: true, EditorFeaturesResources.Updating_files); + // The user hasn't canceled by now, so we're done waiting for them. Off to rename! + using var _1 = operationContext.AddScope(allowCancellation: true, EditorFeaturesResources.Updating_files); - await TaskScheduler.Default; + await TaskScheduler.Default; - // While on the background, attempt to figure out the actual changes to make to the workspace's current solution. - var documentChanges = await CalculateFinalDocumentChangesAsync(newSolution, cancellationToken).ConfigureAwait(false); + // While on the background, attempt to figure out the actual changes to make to the workspace's current solution. + var documentChanges = await CalculateFinalDocumentChangesAsync(newSolution, cancellationToken).ConfigureAwait(false); - // Now jump back to the UI thread to actually apply those changes. - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + // Now jump back to the UI thread to actually apply those changes. + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - // We're about to make irrevocable changes to the workspace and UI. We're no longer cancellable at this point. - using var _2 = operationContext.AddScope(allowCancellation: false, EditorFeaturesResources.Updating_files); - cancellationToken = CancellationToken.None; + // We're about to make irrevocable changes to the workspace and UI. We're no longer cancellable at this point. + using var _2 = operationContext.AddScope(allowCancellation: false, EditorFeaturesResources.Updating_files); + cancellationToken = CancellationToken.None; - // Dismiss the rename UI and rollback any linked edits made. - DismissUIAndRollbackEditsAndEndRenameSession_MustBeCalledOnUIThread( - RenameLogMessage.UserActionOutcome.Committed, previewChanges, - () => - { - // Now try to apply that change we computed to the workspace. - var error = TryApplyRename(documentChanges); - if (error is not null) + // Dismiss the rename UI and rollback any linked edits made. + DismissUIAndRollbackEditsAndEndRenameSession_MustBeCalledOnUIThread( + RenameLogMessage.UserActionOutcome.Committed, previewChanges, + () => { - var notificationService = Workspace.Services.GetService(); - notificationService.SendNotification( - error.Value.message, EditorFeaturesResources.Rename_Symbol, error.Value.severity); - } - }); + // Now try to apply that change we computed to the workspace. + var error = TryApplyRename(documentChanges); + if (error is not null) + { + var notificationService = Workspace.Services.GetService(); + notificationService.SendNotification( + error.Value.message, EditorFeaturesResources.Rename_Symbol, error.Value.severity); + } + }); + } + } + finally + { + CommitStateChange?.Invoke(this, false); } async Task> CalculateFinalDocumentChangesAsync( From 50c22364082cdba788ca9a9db70c131cc914b2f5 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 20 Sep 2024 14:01:35 -0700 Subject: [PATCH 56/59] Pass globalOptionService --- .../InlineRename/CommandHandlers/RenameCommandHandler.cs | 3 ++- .../CommandHandlers/AbstractRenameCommandHandler.cs | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs index f17005cbe2637..d57b89c501501 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs @@ -38,8 +38,9 @@ internal partial class RenameCommandHandler : AbstractRenameCommandHandler public RenameCommandHandler( IThreadingContext threadingContext, InlineRenameService renameService, + IGlobalOptionService globalOptionService, IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider) - : base(threadingContext, renameService, asynchronousOperationListenerProvider) + : base(threadingContext, renameService, globalOptionService, asynchronousOperationListenerProvider) { } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs index 909b4c19d9f32..dfb576a49b842 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text; @@ -22,15 +23,18 @@ internal abstract partial class AbstractRenameCommandHandler { private readonly IThreadingContext _threadingContext; private readonly InlineRenameService _renameService; + private readonly IGlobalOptionService _globalOptionService; private readonly IAsynchronousOperationListener _listener; protected AbstractRenameCommandHandler( IThreadingContext threadingContext, InlineRenameService renameService, + IGlobalOptionService globalOptionService, IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider) { _threadingContext = threadingContext; _renameService = renameService; + _globalOptionService = globalOptionService; _listener = asynchronousOperationListenerProvider.GetListener(FeatureAttribute.Rename); } From f089e3b454aa9800eef62d8f912f4edb7f59ed9f Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Fri, 20 Sep 2024 16:06:55 -0700 Subject: [PATCH 57/59] Reset --- .../CommandHandlers/AbstractRenameCommandHandler.cs | 4 ++-- .../AbstractRenameCommandHandler_OpenLineAboveHandler.cs | 2 +- .../AbstractRenameCommandHandler_OpenLineBelowHandler.cs | 2 +- .../AbstractRenameCommandHandler_SaveHandler.cs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs index dfb576a49b842..41dfad324d329 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs @@ -112,7 +112,7 @@ private void CommitIfActive(EditorCommandArgs args, IUIThreadOperationContext op { var selection = args.TextView.Selection.VirtualSelectedSpans.First(); - CommitOnTextEditAndSaveCommand(operationContext); + Commit(operationContext); var translatedSelection = selection.TranslateTo(args.TextView.TextBuffer.CurrentSnapshot); args.TextView.Selection.Select(translatedSelection.Start, translatedSelection.End); @@ -126,7 +126,7 @@ private void CommitIfActiveAndCallNextHandler(EditorCommandArgs args, Action nex nextHandler(); } - private void CommitOnTextEditAndSaveCommand(IUIThreadOperationContext operationContext) + private void Commit(IUIThreadOperationContext operationContext) { RoslynDebug.AssertNotNull(_renameService.ActiveSession); if (_renameService.ActiveSession.IsCommitInProgress) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs index 24d6cb81e67cf..830552a35e14c 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs @@ -17,7 +17,7 @@ public void ExecuteCommand(OpenLineAboveCommandArgs args, Action nextHandler, Co { HandlePossibleTypingCommand(args, nextHandler, context.OperationContext, (activeSession, operationContext, span) => { - CommitOnTextEditAndSaveCommand(operationContext); + Commit(operationContext); nextHandler(); }); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs index c858c7551d9b7..5bb99425cdae2 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs @@ -17,7 +17,7 @@ public void ExecuteCommand(OpenLineBelowCommandArgs args, Action nextHandler, Co { HandlePossibleTypingCommand(args, nextHandler, context.OperationContext, (activeSession, operationContext, span) => { - CommitOnTextEditAndSaveCommand(operationContext); + Commit(operationContext); nextHandler(); }); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs index d31eee2177b23..132c8d0f42a5d 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs @@ -16,7 +16,7 @@ public bool ExecuteCommand(SaveCommandArgs args, CommandExecutionContext context { if (_renameService.ActiveSession != null) { - CommitOnTextEditAndSaveCommand(context.OperationContext); + Commit(context.OperationContext); SetFocusToTextView(args.TextView); } From 68f14ef9d97a754d3a7795ba19fbd7d57486d651 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Mon, 23 Sep 2024 15:28:34 -0700 Subject: [PATCH 58/59] Add option --- .../Core/InlineRename/InlineRenameSessionOptionsStorage.cs | 1 + src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSessionOptionsStorage.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSessionOptionsStorage.cs index 7655b058f080c..facd70ae5c6d2 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSessionOptionsStorage.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSessionOptionsStorage.cs @@ -14,4 +14,5 @@ internal static class InlineRenameSessionOptionsStorage public static readonly Option2 RenameFile = new("dotnet_rename_file", defaultValue: true); public static readonly Option2 PreviewChanges = new("dotnet_preview_inline_rename_changes", defaultValue: false); public static readonly Option2 RenameAsynchronously = new("dotnet_rename_asynchronously", defaultValue: true); + public static readonly Option2 CommitRenameOnEnter = new("dotnet_commit_rename_on_enter", defaultValue: true); } diff --git a/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs b/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs index 8ceae9cd6694d..a0d433b46c826 100644 --- a/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs +++ b/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs @@ -114,6 +114,7 @@ public bool TryFetch(LocalUserRegistryOptionPersister persister, OptionKey2 opti {"dotnet_collapse_regions_when_collapsing_to_definitions", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.CollapseRegionsWhenCollapsingToDefinitions")}, {"dotnet_collapse_local_functions_when_collapsing_to_definitions", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.CollapseLocalFunctionsWhenCollapsingToDefinitions")}, {"dotnet_collapse_regions_when_first_opened", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.CollapseRegionsWhenFirstOpened")}, + {"dotnet_collapse_regions_when_first_opened", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.CollapseRegionsWhenFirstOpened")}, {"dotnet_maximum_block_banner_length", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.MaximumBannerLength")}, {"dotnet_show_block_structure_guides_for_code_level_constructs", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ShowBlockStructureGuidesForCodeLevelConstructs")}, {"dotnet_show_block_structure_guides_for_comments_and_preprocessor_regions", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ShowBlockStructureGuidesForCommentsAndPreprocessorRegions")}, @@ -344,8 +345,8 @@ public bool TryFetch(LocalUserRegistryOptionPersister persister, OptionKey2 opti {"dotnet_rename_use_inline_adornment", new RoamingProfileStorage("TextEditor.RenameUseInlineAdornment")}, {"dotnet_preview_inline_rename_changes", new RoamingProfileStorage("TextEditor.Specific.PreviewRename")}, {"dotnet_collapse_suggestions_in_inline_rename_ui", new RoamingProfileStorage("TextEditor.CollapseRenameSuggestionsUI")}, + {"dotnet_commit_rename_on_enter", new RoamingProfileStorage("TextEditor.Specific.CommitRenameOnEnter")}, {"dotnet_rename_get_suggestions_automatically", new FeatureFlagStorage(@"Editor.AutoSmartRenameSuggestions")}, - {"dotnet_rename_asynchronously", new RoamingProfileStorage("TextEditor.Specific.RenameAsynchronously")}, {"dotnet_rename_file", new RoamingProfileStorage("TextEditor.Specific.RenameFile")}, {"dotnet_rename_in_comments", new RoamingProfileStorage("TextEditor.Specific.RenameInComments")}, {"dotnet_rename_in_strings", new RoamingProfileStorage("TextEditor.Specific.RenameInStrings")}, From c540ddf876d20ee41d81f631470a529a5af6123b Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Mon, 23 Sep 2024 15:41:52 -0700 Subject: [PATCH 59/59] Reset --- .../AbstractRenameCommandHandler.cs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs index 41dfad324d329..6099d90937c15 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs @@ -72,12 +72,6 @@ private void HandlePossibleTypingCommand(TArgs args, Action nextHandler, return; } - // If commit in progress, don't do anything, as we don't want user change the text view - if (_renameService.ActiveSession.IsCommitInProgress) - { - return; - } - var selectedSpans = args.TextView.Selection.GetSnapshotSpansOnBuffer(args.SubjectBuffer); if (selectedSpans.Count > 1) { @@ -129,17 +123,6 @@ private void CommitIfActiveAndCallNextHandler(EditorCommandArgs args, Action nex private void Commit(IUIThreadOperationContext operationContext) { RoslynDebug.AssertNotNull(_renameService.ActiveSession); - if (_renameService.ActiveSession.IsCommitInProgress) - { - // When the commit is in-progress, don't sync wait for the commit. - // This might happen when user async commit the rename using 'enter' key, then they invoke 'save command'. We don't want to block UI thread again. - return; - } - - // We only async commit the rename session when it is invoked by 'enter' key or from the button in UI. (Which should cover most cases) - // For other command handler still commit the session because we don't want to regress the behavior. - // Example: When the rename session is committed by 'SaveCommand', we want to ensure rename is committed, then save the document. - // If it's async rename, the document would still be dirty after 'SaveCommand' is executed. _renameService.ActiveSession.Commit(previewChanges: false, operationContext); } }