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;
        }
示例#5
0
        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;
        }
示例#6
0
        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);
                }
            }
        }