private void CommitCore(IUIThreadOperationContext operationContext, bool previewChanges) { var eventName = previewChanges ? FunctionId.Rename_CommitCoreWithPreview : FunctionId.Rename_CommitCore; using (Logger.LogBlock(eventName, KeyValueLogMessage.Create(LogType.UserAction), operationContext.UserCancellationToken)) { var newSolution = _conflictResolutionTask.Join(operationContext.UserCancellationToken).NewSolution; if (previewChanges) { var previewService = _workspace.Services.GetService <IPreviewDialogService>(); operationContext.TakeOwnership(); 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 cancelled by now, so we're done waiting for them. Off to // rename! using var _ = operationContext.AddScope(allowCancellation: false, EditorFeaturesResources.Updating_files); Dismiss(rollbackTemporaryEdits: true); CancelAllOpenDocumentTrackingTasks(); _triggerView.Caret.PositionChanged += LogPositionChanged; ApplyRename(newSolution, operationContext); LogRenameSession(RenameLogMessage.UserActionOutcome.Committed, previewChanges); EndRenameSession(); _triggerView.Caret.PositionChanged -= LogPositionChanged; void LogPositionChanged(object sender, CaretPositionChangedEventArgs e) { try { throw new InvalidOperationException("Caret position changed during application of rename"); } catch (InvalidOperationException ex) when(FatalError.ReportAndCatch(ex)) { // Unreachable code due to ReportAndCatch Contract.ThrowIfTrue(true); } } } }
public void Invoke(IUIThreadOperationContext context) { // we're going to return immediately from Invoke and kick off our own async work to invoke the // code action. Once this returns, the editor will close the threaded wait dialog it created. // So we need to take ownership of it and start our own TWD instead to track this. context.TakeOwnership(); _ = InvokeAsync(); }
/// <returns> /// True: if a failure notification was displayed or the user did not want to proceed in a best effort scenario. /// Extract Method does not proceed further and is done. /// False: the user proceeded to a best effort scenario. /// </returns> private bool TryNotifyFailureToUser(Document document, ExtractMethodResult result, IUIThreadOperationContext waitContext) { // We are about to show a modal UI dialog so we should take over the command execution // wait context. That means the command system won't attempt to show its own wait dialog // and also will take it into consideration when measuring command handling duration. waitContext.TakeOwnership(); var project = document.Project; var solution = project.Solution; var notificationService = solution.Workspace.Services.GetService <INotificationService>(); // see whether we will allow best effort extraction and if it is possible. if (!solution.Options.GetOption(ExtractMethodOptions.AllowBestEffort, project.Language) || !result.Status.HasBestEffort() || result.Document == null) { if (notificationService != null) { notificationService.SendNotification( EditorFeaturesResources.Extract_method_encountered_the_following_issues + Environment.NewLine + string.Join("", result.Reasons.Select(r => Environment.NewLine + " " + r)), title: EditorFeaturesResources.Extract_Method, severity: NotificationSeverity.Error); } return(true); } // okay, best effort is turned on, let user know it is an best effort if (notificationService != null) { if (!notificationService.ConfirmMessageBox( EditorFeaturesResources.Extract_method_encountered_the_following_issues + Environment.NewLine + string.Join("", result.Reasons.Select(r => Environment.NewLine + " " + r)) + Environment.NewLine + Environment.NewLine + EditorFeaturesResources.Do_you_still_want_to_proceed_This_may_produce_broken_code, title: EditorFeaturesResources.Extract_Method, severity: NotificationSeverity.Warning)) { return(true); } } return(false); }
private void CommitCore(IUIThreadOperationContext operationContext, bool previewChanges) { var eventName = previewChanges ? FunctionId.Rename_CommitCoreWithPreview : FunctionId.Rename_CommitCore; using (Logger.LogBlock(eventName, KeyValueLogMessage.Create(LogType.UserAction), operationContext.UserCancellationToken)) { var newSolution = _conflictResolutionTask.Join(operationContext.UserCancellationToken).NewSolution; if (previewChanges) { var previewService = _workspace.Services.GetService <IPreviewDialogService>(); operationContext.TakeOwnership(); 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 cancelled by now, so we're done waiting for them. Off to // rename! using var _ = operationContext.AddScope(allowCancellation: false, EditorFeaturesResources.Updating_files); Dismiss(rollbackTemporaryEdits: true); CancelAllOpenDocumentTrackingTasks(); ApplyRename(newSolution, operationContext); LogRenameSession(RenameLogMessage.UserActionOutcome.Committed, previewChanges); EndRenameSession(); } }
private void ApplyRename(Solution newSolution, IUIThreadOperationContext operationContext) { var changes = _baseSolution.GetChanges(newSolution); var changedDocumentIDs = changes.GetProjectChanges().SelectMany(c => c.GetChangedDocuments()).ToList(); if (!_renameInfo.TryOnBeforeGlobalSymbolRenamed(_workspace, changedDocumentIDs, this.ReplacementText)) { var notificationService = _workspace.Services.GetService <INotificationService>(); notificationService.SendNotification( EditorFeaturesResources.Rename_operation_was_cancelled_or_is_not_valid, EditorFeaturesResources.Rename_Symbol, NotificationSeverity.Error); return; } using var undoTransaction = _workspace.OpenGlobalUndoTransaction(EditorFeaturesResources.Inline_Rename); var finalSolution = newSolution.Workspace.CurrentSolution; foreach (var id in changedDocumentIDs) { // If the document supports syntax tree, then create the new solution from the // updated syntax root. This should ensure that annotations are preserved, and // prevents the solution from having to reparse documents when we already have // the trees for them. If we don't support syntax, then just use the text of // the document. var newDocument = newSolution.GetDocument(id); if (newDocument.SupportsSyntaxTree) { // We pass CancellationToken.None here because we don't have a usable token to pass. The IUIThreadOperationContext // passed here as a cancellation token, but the caller in CommitCore has already turned off cancellation // because we're committed to the update at this point. If we ever want to pass cancellation here, we'd want to move this // part back out of this method and before the point where we've already opened a global transaction. var root = newDocument.GetSyntaxRootSynchronously(CancellationToken.None); finalSolution = finalSolution.WithDocumentSyntaxRoot(id, root); } else { var newText = newDocument.GetTextSynchronously(CancellationToken.None); finalSolution = finalSolution.WithDocumentText(id, newText); } // Make sure to include any document rename as well finalSolution = finalSolution.WithDocumentName(id, newDocument.Name); } if (_workspace.TryApplyChanges(finalSolution)) { // Since rename can apply file changes as well, and those file // changes can generate new document ids, include added documents // as well as changed documents. This also ensures that any document // that was removed is not included var finalChanges = _workspace.CurrentSolution.GetChanges(_baseSolution); var finalChangedIds = finalChanges .GetProjectChanges() .SelectMany(c => c.GetChangedDocuments().Concat(c.GetAddedDocuments())) .ToList(); if (!_renameInfo.TryOnAfterGlobalSymbolRenamed(_workspace, finalChangedIds, this.ReplacementText)) { var notificationService = _workspace.Services.GetService <INotificationService>(); operationContext.TakeOwnership(); notificationService.SendNotification( EditorFeaturesResources.Rename_operation_was_not_properly_completed_Some_file_might_not_have_been_updated, EditorFeaturesResources.Rename_Symbol, NotificationSeverity.Information); } undoTransaction.Commit(); } }
private bool Execute( ITextBuffer textBuffer, ITextView view, IUIThreadOperationContext waitContext) { var cancellationToken = waitContext.UserCancellationToken; var spans = view.Selection.GetSnapshotSpansOnBuffer(textBuffer); if (spans.Count(s => s.Length > 0) != 1) { return(false); } var document = textBuffer.CurrentSnapshot.GetFullyLoadedOpenDocumentInCurrentContextWithChangesAsync(waitContext).WaitAndGetResult(cancellationToken); if (document == null) { return(false); } var result = ExtractMethodService.ExtractMethodAsync( document, spans.Single().Span.ToTextSpan(), cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken); Contract.ThrowIfNull(result); if (!result.Succeeded && !result.SucceededWithSuggestion) { // if it failed due to out/ref parameter in async method, try it with different option var newResult = TryWithoutMakingValueTypesRef(document, spans, result, cancellationToken); if (newResult != null) { var notificationService = document.Project.Solution.Workspace.Services.GetService <INotificationService>(); if (notificationService != null) { // We are about to show a modal UI dialog so we should take over the command execution // wait context. That means the command system won't attempt to show its own wait dialog // and also will take it into consideration when measuring command handling duration. waitContext.TakeOwnership(); if (!notificationService.ConfirmMessageBox( EditorFeaturesResources.Extract_method_encountered_the_following_issues + Environment.NewLine + Environment.NewLine + string.Join(Environment.NewLine, result.Reasons) + Environment.NewLine + Environment.NewLine + EditorFeaturesResources.We_can_fix_the_error_by_not_making_struct_out_ref_parameter_s_Do_you_want_to_proceed, title: EditorFeaturesResources.Extract_Method, severity: NotificationSeverity.Error)) { // We handled the command, displayed a notification and did not produce code. return(true); } } // reset result result = newResult; } else if (TryNotifyFailureToUser(document, result, waitContext)) { // We handled the command, displayed a notification and did not produce code. return(true); } } // apply the change to buffer // get method name token ApplyChangesToBuffer(result, textBuffer, cancellationToken); // start inline rename var methodNameAtInvocation = result.InvocationNameToken; var snapshotAfterFormatting = textBuffer.CurrentSnapshot; var documentAfterFormatting = snapshotAfterFormatting.GetOpenDocumentInCurrentContextWithChanges(); _renameService.StartInlineSession(documentAfterFormatting, methodNameAtInvocation.Span, cancellationToken); // select invocation span view.TryMoveCaretToAndEnsureVisible(new SnapshotPoint(snapshotAfterFormatting, methodNameAtInvocation.Span.End)); view.SetSelection( methodNameAtInvocation.Span.ToSnapshotSpan(snapshotAfterFormatting)); return(true); }
static void ShowMessage(string errorMessage, NotificationSeverity severity, IUIThreadOperationContext operationContext, INotificationService notificationService) { operationContext.TakeOwnership(); notificationService.SendNotification(errorMessage, severity: severity); }
public void TakeOwnership() => _context.TakeOwnership();