コード例 #1
0
        public void SyntaxTreeRequest_Complete_CanBeCalledMultipleTimes()
        {
            // Arrange
            var syntaxTree = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create());
            var request    = new DefaultVisualStudioRazorParser.SyntaxTreeRequest(StringTextSnapshot.Empty, CancellationToken.None);

            // Act & Assert
            request.Complete(syntaxTree);
            request.Complete(syntaxTree);
            request.Complete(syntaxTree);
        }
コード例 #2
0
        public override IReadOnlyList <ClassifiedSpan> GetClassifiedSpans(RazorSyntaxTree syntaxTree)
        {
            var result = syntaxTree.GetClassifiedSpans();

            return(result.Select(item => new ClassifiedSpan(
                                     item.Span,
                                     item.BlockSpan,
                                     (SpanKind)item.SpanKind,
                                     (BlockKind)item.BlockKind,
                                     (AcceptedCharacters)item.AcceptedCharacters)).ToArray());
        }
        private static TextBufferCodeDocumentProvider CreateCodeDocumentProvider(string content)
        {
            var sourceDocument = TestRazorSourceDocument.Create(content);
            var syntaxTree     = RazorSyntaxTree.Parse(sourceDocument, RazorParserOptions.Create(opt => opt.Directives.Add(FunctionsDirective.Directive)));
            var codeDocument   = TestRazorCodeDocument.Create(content);

            codeDocument.SetSyntaxTree(syntaxTree);
            var codeDocumentProvider = Mock.Of <TextBufferCodeDocumentProvider>(provider => provider.TryGetFromBuffer(It.IsAny <ITextBuffer>(), out codeDocument), MockBehavior.Strict);

            return(codeDocumentProvider);
        }
コード例 #4
0
        private void TextBuffer_OnChanged(object sender, TextContentChangedEventArgs args)
        {
            _dispatcher.AssertForegroundThread();

            if (args.Changes.Count > 0)
            {
                // Idle timers are used to track provisional changes. Provisional changes only last for a single text change. After that normal
                // partial parsing rules apply (stop the timer).
                StopIdleTimer();
            }

            var snapshot = args.After;
            if (!args.TextChangeOccurred(out var changeInformation))
            {
                // Ensure we get a parse for latest snapshot.
                QueueChange(null, snapshot);
                return;
            }

            var change = new SourceChange(changeInformation.firstChange.OldPosition, changeInformation.oldText.Length, changeInformation.newText);
            var result = PartialParseResultInternal.Rejected;
            RazorSyntaxTree partialParseSyntaxTree = null;
            using (_parser.SynchronizeMainThreadState())
            {
                // Check if we can partial-parse
                if (_partialParser != null && _parser.IsIdle)
                {
                    (result, partialParseSyntaxTree) = _partialParser.Parse(change);
                }
            }

            // If partial parsing failed or there were outstanding parser tasks, start a full reparse
            if ((result & PartialParseResultInternal.Rejected) == PartialParseResultInternal.Rejected)
            {
                QueueChange(change, snapshot);
            }
            else
            {
                var currentCodeDocument = CodeDocument;
                var codeDocument = RazorCodeDocument.Create(currentCodeDocument.Source, currentCodeDocument.Imports);

                foreach (var item in currentCodeDocument.Items)
                {
                    codeDocument.Items[item.Key] = item.Value;
                }
                codeDocument.SetSyntaxTree(partialParseSyntaxTree);
                TryUpdateLatestParsedSyntaxTreeSnapshot(codeDocument, snapshot);
            }

            if ((result & PartialParseResultInternal.Provisional) == PartialParseResultInternal.Provisional)
            {
                StartIdleTimer();
            }
        }
コード例 #5
0
        internal static IReadOnlyList <TagHelperSpanInternal> GetTagHelperSpans(Block root, string filePath)
        {
            // We don't care about the options and diagnostic here.
            var syntaxTree = RazorSyntaxTree.Create(
                root,
                TestRazorSourceDocument.Create(filePath: filePath),
                Array.Empty <RazorDiagnostic>(),
                RazorParserOptions.CreateDefault());

            return(syntaxTree.GetTagHelperSpans());
        }
コード例 #6
0
        private static RazorSyntaxTree GetSyntaxTree(string content)
        {
            var syntaxTree = RazorSyntaxTree.Parse(
                TestRazorSourceDocument.Create(content),
                RazorParserOptions.Create(options =>
            {
                options.Directives.Add(FunctionsDirective.Directive);
                options.Directives.Add(SectionDirective.Directive);
            }));

            return(syntaxTree);
        }
コード例 #7
0
    public RazorSyntaxTree Execute(RazorCodeDocument codeDocument, RazorSyntaxTree syntaxTree)
    {
        if (FileKinds.IsComponent(codeDocument.GetFileKind()))
        {
            // Nothing to do here.
            return(syntaxTree);
        }

        var sectionVerifier = new NestedSectionVerifier(syntaxTree);

        return(sectionVerifier.Verify());
    }
コード例 #8
0
        public static IReadOnlyList <CSharpStatementSyntax> GetCSharpStatements(this RazorSyntaxTree syntaxTree)
        {
            if (syntaxTree is null)
            {
                throw new ArgumentNullException(nameof(syntaxTree));
            }

            // We want all nodes that represent Razor C# statements, @{ ... }.
            var statements = syntaxTree.Root.DescendantNodes().OfType <CSharpStatementSyntax>().ToList();

            return(statements);
        }
コード例 #9
0
        public override IReadOnlyList <RazorCompletionItem> GetCompletionItems(RazorSyntaxTree syntaxTree, SourceSpan location)
        {
            var completionItems = new List <RazorCompletionItem>();

            if (AtDirectiveCompletionPoint(syntaxTree, location))
            {
                var directiveCompletions = GetDirectiveCompletionItems(syntaxTree);
                completionItems.AddRange(directiveCompletions);
            }

            return(completionItems);
        }
        private CompletionList GenerateCompletionList(string documentContent, int queryIndex, TagHelperCompletionProvider componentCompletionProvider)
        {
            var sourceDocument           = RazorSourceDocument.Create(documentContent, RazorSourceDocumentProperties.Default);
            var syntaxTree               = RazorSyntaxTree.Parse(sourceDocument);
            var tagHelperDocumentContext = TagHelperDocumentContext.Create(prefix: string.Empty, DefaultTagHelpers);

            var completionQueryLocation = new SourceSpan(queryIndex, length: 0);
            var razorCompletionItems    = componentCompletionProvider.GetCompletionItems(syntaxTree, tagHelperDocumentContext, completionQueryLocation);
            var completionList          = RazorCompletionEndpoint.CreateLSPCompletionList(razorCompletionItems, new CompletionListCache(), new[] { ExtendedCompletionItemKinds.TagHelper });

            return(completionList);
        }
コード例 #11
0
        private static RazorCodeDocument CreateCodeDocument(string text)
        {
            var codeDocument   = TestRazorCodeDocument.CreateEmpty();
            var sourceDocument = TestRazorSourceDocument.Create(text);
            var syntaxTree     = RazorSyntaxTree.Parse(sourceDocument);

            codeDocument.SetSyntaxTree(syntaxTree);
            var tagHelperDocumentContext = TagHelperDocumentContext.Create(prefix: string.Empty, Enumerable.Empty <TagHelperDescriptor>());

            codeDocument.SetTagHelperContext(tagHelperDocumentContext);
            return(codeDocument);
        }
コード例 #12
0
        public void AtValidContentKind_ReturnsFalseAtMarkup()
        {
            // Arrange
            var syntaxTree     = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create("<p></p>"));
            var changePosition = 2;

            // Act
            var result = BraceSmartIndenter.AtValidContentKind(changePosition, syntaxTree);

            // Assert
            Assert.False(result);
        }
コード例 #13
0
        public void AtApplicableRazorBlock_AtExplicitCodeBlocksCode_ReturnsTrue()
        {
            // Arrange
            var syntaxTree     = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create("@{}"));
            var changePosition = 2;

            // Act
            var result = BraceSmartIndenter.AtApplicableRazorBlock(changePosition, syntaxTree);

            // Assert
            Assert.True(result);
        }
コード例 #14
0
        public void AtApplicableRazorBlock_WhenNoOwner_ReturnsFalse()
        {
            // Arrange
            var syntaxTree     = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create("@DateTime.Now"));
            var changePosition = 14; // 1 after the end of the content

            // Act
            var result = BraceSmartIndenter.AtApplicableRazorBlock(changePosition, syntaxTree);

            // Assert
            Assert.False(result);
        }
コード例 #15
0
        public void AtApplicableRazorBlock_AtMarkup_ReturnsFalse()
        {
            // Arrange
            var syntaxTree     = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create("<p></p>"));
            var changePosition = 2;

            // Act
            var result = BraceSmartIndenter.AtApplicableRazorBlock(changePosition, syntaxTree);

            // Assert
            Assert.False(result);
        }
コード例 #16
0
        public void AtValidContentKind_ReturnsTrueAtCode()
        {
            // Arrange
            var syntaxTree     = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create("@{}"));
            var changePosition = 2;

            // Act
            var result = BraceSmartIndenter.AtValidContentKind(changePosition, syntaxTree);

            // Assert
            Assert.True(result);
        }
コード例 #17
0
        public void Parse_CanParseEmptyDocument()
        {
            // Arrange
            var source = TestRazorSourceDocument.Create(string.Empty);

            // Act
            var syntaxTree = RazorSyntaxTree.Parse(source);

            // Assert
            Assert.NotNull(syntaxTree);
            Assert.Empty(syntaxTree.Diagnostics);
        }
コード例 #18
0
    public static void Verify(RazorSyntaxTree syntaxTree, bool ensureFullFidelity = true)
    {
        var verifier = new Verifier(syntaxTree.Source);

        verifier.Visit(syntaxTree.Root);

        if (ensureFullFidelity)
        {
            var syntaxTreeString = syntaxTree.Root.ToFullString();
            var builder          = new StringBuilder(syntaxTree.Source.Length);
            for (var i = 0; i < syntaxTree.Source.Length; i++)
            {
                builder.Append(syntaxTree.Source[i]);
            }
            var sourceString = builder.ToString();

            // Make sure the syntax tree contains all of the text in the document.
            Assert.Equal(sourceString, syntaxTreeString);

            // Ensure all source is locatable
            for (var i = 0; i < syntaxTree.Source.Length; i++)
            {
                var span     = new SourceSpan(i, 0);
                var location = new SourceChange(span, string.Empty);
                var owner    = syntaxTree.Root.LocateOwner(location);

                if (owner == null)
                {
                    var snippetStartIndex  = Math.Max(0, i - 10);
                    var snippetStartLength = i - snippetStartIndex;
                    var snippetStart       = new char[snippetStartLength];
                    syntaxTree.Source.CopyTo(snippetStartIndex, snippetStart, 0, snippetStartLength);

                    var snippetEndIndex  = Math.Min(syntaxTree.Source.Length - 1, i + 10);
                    var snippetEndLength = snippetEndIndex - i;
                    var snippetEnd       = new char[snippetEndLength];
                    syntaxTree.Source.CopyTo(i, snippetEnd, 0, snippetEndLength);

                    var snippet = new char[snippetStart.Length + snippetEnd.Length + 1];
                    snippetStart.CopyTo(snippet, 0);
                    snippet[snippetStart.Length] = '|';
                    snippetEnd.CopyTo(snippet, snippetStart.Length + 1);

                    var snippetString = new string(snippet);

                    throw new XunitException(
                              $@"Could not locate Syntax Node owner at position '{i}':
{snippetString}");
                }
            }
        }
    }
コード例 #19
0
        public static IReadOnlyList <TagHelperSpanInternal> GetTagHelperSpans(this RazorSyntaxTree syntaxTree)
        {
            if (syntaxTree == null)
            {
                throw new ArgumentNullException(nameof(syntaxTree));
            }

            var visitor = new TagHelperSpanVisitor(syntaxTree.Source);

            visitor.Visit(syntaxTree.Root);

            return(visitor.TagHelperSpans);
        }
コード例 #20
0
        public static IReadOnlyList <FormattingSpan> GetFormattingSpans(this RazorSyntaxTree syntaxTree)
        {
            if (syntaxTree == null)
            {
                throw new ArgumentNullException(nameof(syntaxTree));
            }

            var visitor = new FormattingVisitor(syntaxTree.Source);

            visitor.Visit(syntaxTree.Root);

            return(visitor.FormattingSpans);
        }
コード例 #21
0
        public void AtApplicableRazorBlock_AtMetacode_ReturnsTrue()
        {
            // Arrange
            var parseOptions   = RazorParserOptions.Create(options => options.Directives.Add(FunctionsDirective.Directive));
            var syntaxTree     = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create("@functions {}"), parseOptions);
            var changePosition = 12;

            // Act
            var result = BraceSmartIndenter.AtApplicableRazorBlock(changePosition, syntaxTree);

            // Assert
            Assert.True(result);
        }
コード例 #22
0
    public void SetRazorSyntaxTree_SetsSyntaxTree()
    {
        // Arrange
        var codeDocument = TestRazorCodeDocument.CreateEmpty();

        var expected = RazorSyntaxTree.Parse(codeDocument.Source);

        // Act
        codeDocument.SetSyntaxTree(expected);

        // Assert
        Assert.Same(expected, codeDocument.Items[typeof(RazorSyntaxTree)]);
    }
        private static RazorSyntaxTree CreateSyntaxTree(string text, params DirectiveDescriptor[] directives)
        {
            var sourceDocument = TestRazorSourceDocument.Create(text);
            var options        = RazorParserOptions.Create(builder =>
            {
                foreach (var directive in directives)
                {
                    builder.Directives.Add(directive);
                }
            });
            var syntaxTree = RazorSyntaxTree.Parse(sourceDocument, options);

            return(syntaxTree);
        }
コード例 #24
0
        private void VerifyPartialParseTree(TestParserManager manager, string content, string expectedCode = null)
        {
            if (expectedCode != null)
            {
                // Verify if the syntax tree represents the expected input.
                var syntaxTreeContent = manager.PartialParsingSyntaxTreeRoot.ToFullString();
                Assert.Contains(expectedCode, syntaxTreeContent, StringComparison.Ordinal);
            }

            var sourceDocument = TestRazorSourceDocument.Create(content);
            var syntaxTree     = RazorSyntaxTree.Create(manager.PartialParsingSyntaxTreeRoot, sourceDocument, manager.CurrentSyntaxTree.Diagnostics, manager.CurrentSyntaxTree.Options);

            BaselineTest(syntaxTree);
        }
コード例 #25
0
        public override IReadOnlyList <RazorCompletionItem> GetCompletionItems(RazorSyntaxTree syntaxTree, TagHelperDocumentContext tagHelperDocumentContext, SourceSpan location)
        {
            if (syntaxTree is null)
            {
                throw new ArgumentNullException(nameof(syntaxTree));
            }

            if (tagHelperDocumentContext is null)
            {
                throw new ArgumentNullException(nameof(tagHelperDocumentContext));
            }

            var change = new SourceChange(location, string.Empty);
            var owner  = syntaxTree.Root.LocateOwner(change);

            if (owner == null)
            {
                Debug.Fail("Owner should never be null.");
                return(Array.Empty <RazorCompletionItem>());
            }

            var parent = owner.Parent;

            if (_htmlFactsService.TryGetElementInfo(parent, out var containingTagNameToken, out var attributes) &&
                containingTagNameToken.Span.IntersectsWith(location.AbsoluteIndex))
            {
                var stringifiedAttributes = _tagHelperFactsService.StringifyAttributes(attributes);
                var elementCompletions    = GetElementCompletions(parent, containingTagNameToken.Content, stringifiedAttributes, tagHelperDocumentContext);
                return(elementCompletions);
            }

            if (_htmlFactsService.TryGetAttributeInfo(
                    parent,
                    out containingTagNameToken,
                    out var prefixLocation,
                    out var selectedAttributeName,
                    out var selectedAttributeNameLocation,
                    out attributes) &&
                (selectedAttributeName == null ||
                 selectedAttributeNameLocation?.IntersectsWith(location.AbsoluteIndex) == true ||
                 (prefixLocation?.IntersectsWith(location.AbsoluteIndex) ?? false)))
            {
                var stringifiedAttributes = _tagHelperFactsService.StringifyAttributes(attributes);
                var attributeCompletions  = GetAttributeCompletions(parent, containingTagNameToken.Content, selectedAttributeName, stringifiedAttributes, tagHelperDocumentContext);
                return(attributeCompletions);
            }

            // Invalid location for TagHelper completions.
            return(Array.Empty <RazorCompletionItem>());
        }
        public override IReadOnlyList <RazorCompletionItem> GetCompletionItems(RazorSyntaxTree syntaxTree, TagHelperDocumentContext tagHelperDocumentContext, SourceSpan location)
        {
            if (syntaxTree is null)
            {
                throw new ArgumentNullException(nameof(syntaxTree));
            }

            if (tagHelperDocumentContext is null)
            {
                throw new ArgumentNullException(nameof(tagHelperDocumentContext));
            }

            if (!FileKinds.IsComponent(syntaxTree.Options.FileKind))
            {
                // Directive attributes are only supported in components
                return(Array.Empty <RazorCompletionItem>());
            }

            var change = new SourceChange(location, string.Empty);
            var owner  = syntaxTree.Root.LocateOwner(change);

            if (owner == null)
            {
                return(Array.Empty <RazorCompletionItem>());
            }

            if (!TryGetAttributeInfo(owner, out var attributeName, out var attributeNameLocation, out _, out _))
            {
                // Either we're not in an attribute or the attribute is so malformed that we can't provide proper completions.
                return(Array.Empty <RazorCompletionItem>());
            }

            if (!attributeNameLocation.IntersectsWith(location.AbsoluteIndex))
            {
                // We're trying to retrieve completions on a portion of the name that is not supported (such as a parameter).
                return(Array.Empty <RazorCompletionItem>());
            }

            if (!TryGetElementInfo(owner.Parent.Parent, out var containingTagName, out var attributes))
            {
                // This should never be the case, it means that we're operating on an attribute that doesn't have a tag.
                return(Array.Empty <RazorCompletionItem>());
            }

            // At this point we've determined that completions have been requested for the name portion of the selected attribute.

            var completionItems = GetAttributeCompletions(attributeName, containingTagName, attributes, tagHelperDocumentContext);

            return(completionItems);
        }
コード例 #27
0
        public override IReadOnlyList <TagHelperSpan> GetTagHelperSpans(RazorSyntaxTree syntaxTree)
        {
            if (syntaxTree == null)
            {
                throw new ArgumentNullException(nameof(syntaxTree));
            }

            var results = new List <TagHelperSpan>();

            List <Block> toProcess     = new List <Block>();
            List <Block> blockChildren = new List <Block>();

            toProcess.Add(syntaxTree.Root);

            for (var i = 0; i < toProcess.Count; i++)
            {
                var            blockNode     = toProcess[i];
                TagHelperBlock tagHelperNode = blockNode as TagHelperBlock;
                if (tagHelperNode != null)
                {
                    results.Add(new TagHelperSpan(
                                    new SourceSpan(
                                        tagHelperNode.Start.FilePath ?? syntaxTree.Source.FilePath,
                                        tagHelperNode.Start.AbsoluteIndex,
                                        tagHelperNode.Start.LineIndex,
                                        tagHelperNode.Start.CharacterIndex,
                                        tagHelperNode.Length),
                                    tagHelperNode.Binding));
                }

                // collect all child blocks and inject into toProcess as a single InsertRange
                foreach (SyntaxTreeNode curNode in blockNode.Children)
                {
                    Block curBlock = curNode as Block;
                    if (curBlock != null)
                    {
                        blockChildren.Add(curBlock);
                    }
                }

                if (blockChildren.Count > 0)
                {
                    toProcess.InsertRange(i + 1, blockChildren);
                    blockChildren.Clear();
                }
            }

            return(results);
        }
コード例 #28
0
        private IEnumerable <TextEdit> FormatRazor(FormattingContext context, RazorSyntaxTree syntaxTree)
        {
            var edits  = new List <TextEdit>();
            var source = syntaxTree.Source;

            foreach (var node in syntaxTree.Root.DescendantNodes())
            {
                // Disclaimer: CSharpCodeBlockSyntax is used a _lot_ in razor so these methods are probably
                // being overly careful to only try to format syntax forms they care about.
                TryFormatCSharpCodeBlock(context, edits, source, node);
                TryFormatSingleLineDirective(context, edits, source, node);
            }

            return(edits);
        }
コード例 #29
0
        protected override void ExecuteCore(RazorCodeDocument codeDocument)
        {
            var options    = codeDocument.GetParserOptions() ?? _optionsFeature.GetOptions();
            var syntaxTree = RazorSyntaxTree.Parse(codeDocument.Source, options);

            codeDocument.SetSyntaxTree(syntaxTree);

            var importSyntaxTrees = new RazorSyntaxTree[codeDocument.Imports.Count];

            for (var i = 0; i < codeDocument.Imports.Count; i++)
            {
                importSyntaxTrees[i] = RazorSyntaxTree.Parse(codeDocument.Imports[i], options);
            }
            codeDocument.SetImportSyntaxTrees(importSyntaxTrees);
        }
コード例 #30
0
    public void GetAndSetImportSyntaxTrees_ReturnsSyntaxTrees()
    {
        // Arrange
        var codeDocument = TestRazorCodeDocument.CreateEmpty();

        var expected = new[] { RazorSyntaxTree.Parse(codeDocument.Source), };

        codeDocument.SetImportSyntaxTrees(expected);

        // Act
        var actual = codeDocument.GetImportSyntaxTrees();

        // Assert
        Assert.Same(expected, actual);
    }