public IFormattingRule CreateRule(Document document, int position) { var visualStudioWorkspace = document.Project.Solution.Workspace as VisualStudioWorkspaceImpl; if (visualStudioWorkspace == null) { return _noopRule; } var containedDocument = visualStudioWorkspace.GetHostDocument(document.Id) as ContainedDocument; if (containedDocument == null) { return _noopRule; } var textContainer = document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None).Container; var buffer = textContainer.TryGetTextBuffer() as IProjectionBuffer; if (buffer == null) { return _noopRule; } using (var pooledObject = SharedPools.Default<List<TextSpan>>().GetPooledObject()) { var spans = pooledObject.Object; var root = document.GetSyntaxRootSynchronously(CancellationToken.None); var text = root.SyntaxTree.GetText(CancellationToken.None); spans.AddRange(containedDocument.GetEditorVisibleSpans()); for (var i = 0; i < spans.Count; i++) { var visibleSpan = spans[i]; if (visibleSpan.IntersectsWith(position) || visibleSpan.End == position) { return containedDocument.GetBaseIndentationRule(root, text, spans, i); } } // in razor (especially in @helper tag), it is possible for us to be asked for next line of visible span var line = text.Lines.GetLineFromPosition(position); if (line.LineNumber > 0) { line = text.Lines[line.LineNumber - 1]; // find one that intersects with previous line for (var i = 0; i < spans.Count; i++) { var visibleSpan = spans[i]; if (visibleSpan.IntersectsWith(line.Span)) { return containedDocument.GetBaseIndentationRule(root, text, spans, i); } } } throw new InvalidOperationException(); } }
protected override bool TryGetSimplifiedTypeName(Document documentWithFullyQualifiedTypeName, TextSpan updatedTextSpan, CancellationToken cancellationToken, out string simplifiedTypeName) { simplifiedTypeName = string.Empty; var typeAnnotation = new SyntaxAnnotation(); var syntaxRoot = documentWithFullyQualifiedTypeName.GetSyntaxRootSynchronously(cancellationToken); var nodeToReplace = syntaxRoot.DescendantNodes().FirstOrDefault(n => n.Span == updatedTextSpan); if (nodeToReplace == null) { return false; } var updatedRoot = syntaxRoot.ReplaceNode(nodeToReplace, nodeToReplace.WithAdditionalAnnotations(typeAnnotation, Simplifier.Annotation)); var documentWithAnnotations = documentWithFullyQualifiedTypeName.WithSyntaxRoot(updatedRoot); var simplifiedDocument = Simplifier.ReduceAsync(documentWithAnnotations, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken); simplifiedTypeName = simplifiedDocument.GetSyntaxRootSynchronously(cancellationToken).GetAnnotatedNodesAndTokens(typeAnnotation).Single().ToString(); return true; }
public IndentationResult? GetDesiredIndentation(Document document, int lineNumber, CancellationToken cancellationToken) { var root = document.GetSyntaxRootSynchronously(cancellationToken); var sourceText = root.SyntaxTree.GetText(cancellationToken); var documentOptions = document.GetOptionsAsync(cancellationToken).WaitAndGetResult(cancellationToken); var lineToBeIndented = sourceText.Lines[lineNumber]; var formattingRules = GetFormattingRules(document, lineToBeIndented.Start); // enter on a token case. if (ShouldUseSmartTokenFormatterInsteadOfIndenter(formattingRules, root, lineToBeIndented, documentOptions, cancellationToken)) { return null; } var indenter = GetIndenter( document.GetLanguageService<ISyntaxFactsService>(), root.SyntaxTree, lineToBeIndented, formattingRules, documentOptions, cancellationToken); return indenter.GetDesiredIndentation(); }
internal override Document AddImports( Document document, int position, XElement snippetNode, bool placeSystemNamespaceFirst, CancellationToken cancellationToken) { var importsNode = snippetNode.Element(XName.Get("Imports", snippetNode.Name.NamespaceName)); if (importsNode == null || !importsNode.HasElements) { return document; } var root = document.GetSyntaxRootSynchronously(cancellationToken); var contextLocation = root.FindToken(position).Parent; var newUsingDirectives = GetUsingDirectivesToAdd(contextLocation, snippetNode, importsNode, cancellationToken); if (!newUsingDirectives.Any()) { return document; } // In Venus/Razor, inserting imports statements into the subject buffer does not work. // Instead, we add the imports through the contained language host. if (TryAddImportsToContainedDocument(document, newUsingDirectives.Where(u => u.Alias == null).Select(u => u.Name.ToString()))) { return document; } var addImportService = document.GetLanguageService<IAddImportsService>(); var compilation = document.Project.GetCompilationAsync(cancellationToken).WaitAndGetResult(cancellationToken); var newRoot = addImportService.AddImports(compilation, root, contextLocation, newUsingDirectives, placeSystemNamespaceFirst); var newDocument = document.WithSyntaxRoot(newRoot); var formattedDocument = Formatter.FormatAsync(newDocument, Formatter.Annotation, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken); document.Project.Solution.Workspace.ApplyDocumentChanges(formattedDocument, cancellationToken); return formattedDocument; }
private static IList<UsingDirectiveSyntax> GetUsingDirectivesToAdd(Document document, XElement snippetNode, XElement importsNode, CancellationToken cancellationToken) { var namespaceXmlName = XName.Get("Namespace", snippetNode.Name.NamespaceName); var root = document.GetSyntaxRootSynchronously(cancellationToken); var existingUsings = ((CompilationUnitSyntax)root).Usings; var newUsings = new List<UsingDirectiveSyntax>(); foreach (var import in importsNode.Elements(XName.Get("Import", snippetNode.Name.NamespaceName))) { var namespaceElement = import.Element(namespaceXmlName); if (namespaceElement == null) { continue; } var namespaceToImport = namespaceElement.Value.Trim(); if (string.IsNullOrEmpty(namespaceToImport)) { continue; } var candidateUsing = SyntaxFactory.ParseCompilationUnit("using " + namespaceToImport + ";").DescendantNodes().OfType<UsingDirectiveSyntax>().FirstOrDefault(); if (candidateUsing == null) { continue; } if (!existingUsings.Any(u => UsingsMatch(u, candidateUsing))) { newUsings.Add(candidateUsing.WithAdditionalAnnotations(Formatter.Annotation).WithAppendedTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed)); } } return newUsings; }
private void AdjustIndentationForSpan( Document document, ITextEdit edit, TextSpan visibleSpan, IFormattingRule baseIndentationRule, OptionSet options) { var root = document.GetSyntaxRootSynchronously(CancellationToken.None); using (var rulePool = SharedPools.Default<List<IFormattingRule>>().GetPooledObject()) using (var spanPool = SharedPools.Default<List<TextSpan>>().GetPooledObject()) { var venusFormattingRules = rulePool.Object; var visibleSpans = spanPool.Object; venusFormattingRules.Add(baseIndentationRule); venusFormattingRules.Add(ContainedDocumentPreserveFormattingRule.Instance); var formattingRules = venusFormattingRules.Concat(Formatter.GetDefaultFormattingRules(document)); var workspace = document.Project.Solution.Workspace; var changes = Formatter.GetFormattedTextChanges( root, new TextSpan[] { CommonFormattingHelpers.GetFormattingSpan(root, visibleSpan) }, workspace, options, formattingRules, CancellationToken.None); visibleSpans.Add(visibleSpan); var newChanges = FilterTextChanges(document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None), visibleSpans, changes.ToReadOnlyCollection()).Where(t => visibleSpan.Contains(t.Span)); foreach (var change in newChanges) { edit.Replace(change.Span.ToSpan(), change.NewText); } } }