public static async Task InsertMemberWithCursor(string operation, Projects.Project project, ITypeSymbol type, Location part, SyntaxNode newMember, CancellationToken cancellationToken = default(CancellationToken)) { if (operation == null) { throw new ArgumentNullException(nameof(operation)); } if (project == null) { throw new ArgumentNullException(nameof(project)); } if (type == null) { throw new ArgumentNullException(nameof(type)); } if (newMember == null) { throw new ArgumentNullException(nameof(newMember)); } var doc = await IdeApp.Workbench.OpenDocument(part.SourceTree.FilePath, project, true); var textView = await doc.GetContentWhenAvailable <ITextView> (cancellationToken); await doc.DocumentContext.UpdateParseDocument(); var document = doc.DocumentContext.AnalysisDocument; if (document == null) { LoggingService.LogError("Can't find document to insert member (fileName:" + part.SourceTree.FilePath + ")"); return; } var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var typeDecl = (ClassDeclarationSyntax)root.FindNode(part.SourceSpan); // for some reason the reducer doesn't reduce this var systemVoid = newMember.DescendantNodesAndSelf().OfType <QualifiedNameSyntax> ().FirstOrDefault(ma => ma.ToString() == "System.Void"); if (systemVoid != null) { newMember = newMember.ReplaceNode(systemVoid, SyntaxFactory.ParseTypeName("void")); } var newRoot = root.ReplaceNode(typeDecl, typeDecl.AddMembers((MemberDeclarationSyntax)newMember.WithAdditionalAnnotations(Simplifier.Annotation, Formatter.Annotation, insertedMemberAnnotation))); var projectOptions = await document.GetOptionsAsync(cancellationToken); document = document.WithSyntaxRoot(newRoot); document = await Formatter.FormatAsync(document, Formatter.Annotation, projectOptions, cancellationToken).ConfigureAwait(false); document = await Simplifier.ReduceAsync(document, Simplifier.Annotation, projectOptions, cancellationToken).ConfigureAwait(false); root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var node = root.GetAnnotatedNodes(insertedMemberAnnotation).Single(); var model = await doc.DocumentContext.AnalysisDocument.GetSemanticModelAsync(cancellationToken); Application.Invoke((o, args) => { var editor = doc.Editor; if (editor == null) { // bypass the insertion point selection UI for the new editor document.Project.Solution.Workspace.TryApplyChanges(document.Project.Solution); var editorOperationsFactoryService = CompositionManager.Instance.GetExportedValue <IEditorOperationsFactoryService> (); var editorOperations = editorOperationsFactoryService.GetEditorOperations(textView); var point = new Microsoft.VisualStudio.Text.VirtualSnapshotPoint(textView.TextSnapshot, node.SpanStart); editorOperations.SelectAndMoveCaret(point, point, TextSelectionMode.Stream, EnsureSpanVisibleOptions.AlwaysCenter); return; } var insertionPoints = InsertionPointService.GetInsertionPoints( editor, model, type, part.SourceSpan.Start ); var options = new InsertionModeOptions( operation, insertionPoints, point => { if (!point.Success) { return; } var text = node.ToString(); point.InsertionPoint.Insert(editor, doc.DocumentContext, text); } ); editor.StartInsertionMode(options); }); }
public static async Task InsertMemberWithCursor(string operation, Projects.Project project, ITypeSymbol type, Location part, SyntaxNode newMember, CancellationToken cancellationToken = default(CancellationToken)) { if (operation == null) { throw new ArgumentNullException(nameof(operation)); } if (project == null) { throw new ArgumentNullException(nameof(project)); } if (type == null) { throw new ArgumentNullException(nameof(type)); } if (newMember == null) { throw new ArgumentNullException(nameof(newMember)); } var doc = await IdeApp.Workbench.OpenDocument(part.SourceTree.FilePath, project, true); await doc.UpdateParseDocument(); var document = doc.AnalysisDocument; if (document == null) { LoggingService.LogError("Can't find document to insert member (fileName:" + part.SourceTree.FilePath + ")"); return; } var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var typeDecl = (ClassDeclarationSyntax)root.FindNode(part.SourceSpan); // for some reason the reducer doesn't reduce this var systemVoid = newMember.DescendantNodesAndSelf().OfType <QualifiedNameSyntax> ().FirstOrDefault(ma => ma.ToString() == "System.Void"); if (systemVoid != null) { newMember = newMember.ReplaceNode(systemVoid, SyntaxFactory.ParseTypeName("void")); } var newRoot = root.ReplaceNode(typeDecl, typeDecl.AddMembers((MemberDeclarationSyntax)newMember.WithAdditionalAnnotations(Simplifier.Annotation, Formatter.Annotation, insertedMemberAnnotation))); var policy = project.Policies.Get <CSharpFormattingPolicy> ("text/x-csharp"); var textPolicy = project.Policies.Get <TextStylePolicy> ("text/x-csharp"); var projectOptions = policy.CreateOptions(textPolicy); document = document.WithSyntaxRoot(newRoot); document = await Formatter.FormatAsync(document, Formatter.Annotation, projectOptions, cancellationToken).ConfigureAwait(false); document = await Simplifier.ReduceAsync(document, Simplifier.Annotation, projectOptions, cancellationToken).ConfigureAwait(false); root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var node = root.GetAnnotatedNodes(insertedMemberAnnotation).Single(); Application.Invoke(async(o, args) => { var insertionPoints = InsertionPointService.GetInsertionPoints( doc.Editor, await doc.UpdateParseDocument(), type, part.SourceSpan.Start ); var options = new InsertionModeOptions( operation, insertionPoints, point => { if (!point.Success) { return; } var text = node.ToString(); point.InsertionPoint.Insert(doc.Editor, doc, text); } ); doc.Editor.StartInsertionMode(options); }); }