From fdd08ceab24be3cb990c48a146ae504bdd22c433 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Mon, 20 Mar 2017 08:21:28 -0700 Subject: [PATCH] Adding RazorSyntaxFactsService This is a code dump from tooling -> Razor This service will exist to answer questions about syntax trees for the editor. Right now I'm just moving in the code in the simplest way possible. Tests + cleanup to follow. --- .../ClassifiedSpan.cs | 29 +++++++ .../DefaultRazorSyntaxFactsService.cs | 84 +++++++++++++++++++ .../RazorSyntaxFactsService.cs | 13 +++ 3 files changed, 126 insertions(+) create mode 100644 src/Microsoft.VisualStudio.LanguageServices.Razor/ClassifiedSpan.cs create mode 100644 src/Microsoft.VisualStudio.LanguageServices.Razor/DefaultRazorSyntaxFactsService.cs create mode 100644 src/Microsoft.VisualStudio.LanguageServices.Razor/RazorSyntaxFactsService.cs diff --git a/src/Microsoft.VisualStudio.LanguageServices.Razor/ClassifiedSpan.cs b/src/Microsoft.VisualStudio.LanguageServices.Razor/ClassifiedSpan.cs new file mode 100644 index 0000000000..93ffb6a999 --- /dev/null +++ b/src/Microsoft.VisualStudio.LanguageServices.Razor/ClassifiedSpan.cs @@ -0,0 +1,29 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Razor.Evolution; + +namespace Microsoft.VisualStudio.LanguageServices.Razor +{ + public struct ClassifiedSpan + { + public ClassifiedSpan(SourceSpan span, SourceSpan blockSpan, SpanKind spanKind, BlockKind blockKind, AcceptedCharacters acceptedCharacters) + { + Span = span; + BlockSpan = blockSpan; + SpanKind = spanKind; + BlockKind = blockKind; + AcceptedCharacters = acceptedCharacters; + } + + public AcceptedCharacters AcceptedCharacters { get; } + + public BlockKind BlockKind { get; } + + public SourceSpan BlockSpan { get; } + + public SourceSpan Span { get; } + + public SpanKind SpanKind { get; } + } +} diff --git a/src/Microsoft.VisualStudio.LanguageServices.Razor/DefaultRazorSyntaxFactsService.cs b/src/Microsoft.VisualStudio.LanguageServices.Razor/DefaultRazorSyntaxFactsService.cs new file mode 100644 index 0000000000..1685ae10bf --- /dev/null +++ b/src/Microsoft.VisualStudio.LanguageServices.Razor/DefaultRazorSyntaxFactsService.cs @@ -0,0 +1,84 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using Microsoft.AspNetCore.Razor.Evolution; +using Microsoft.AspNetCore.Razor.Evolution.Legacy; + +namespace Microsoft.VisualStudio.LanguageServices.Razor +{ + [Export(typeof(RazorSyntaxFactsService))] + internal class DefaultRazorSyntaxFactsService : RazorSyntaxFactsService + { + public override IReadOnlyList GetClassifiedSpans(RazorSyntaxTree syntaxTree) + { + var spans = Flatten(syntaxTree); + + var result = new ClassifiedSpan[spans.Count]; + for (var i = 0; i < spans.Count; i++) + { + var span = spans[i]; + result[i] = new ClassifiedSpan( + new SourceSpan( + span.Start.FilePath ?? syntaxTree.Source.FileName, + span.Start.AbsoluteIndex, + span.Start.LineIndex, + span.Start.CharacterIndex, + span.Length), + new SourceSpan( + span.Parent.Start.FilePath ?? syntaxTree.Source.FileName, + span.Parent.Start.AbsoluteIndex, + span.Parent.Start.LineIndex, + span.Parent.Start.CharacterIndex, + span.Parent.Length), + span.Kind, + span.Parent.Type, + span.EditHandler.AcceptedCharacters); + } + + return result; + } + + private List Flatten(RazorSyntaxTree syntaxTree) + { + var result = new List(); + AppendFlattenedSpans(syntaxTree.Root, result); + return result; + + void AppendFlattenedSpans(SyntaxTreeNode node, List foundSpans) + { + Span spanNode = node as Span; + if (spanNode != null) + { + foundSpans.Add(spanNode); + } + else + { + TagHelperBlock tagHelperNode = node as TagHelperBlock; + if (tagHelperNode != null) + { + // These aren't in document order, sort them first and then dig in + List attributeNodes = tagHelperNode.Attributes.Select(kvp => kvp.Value).Where(att => att != null).ToList(); + attributeNodes.Sort((x, y) => x.Start.AbsoluteIndex.CompareTo(y.Start)); + + foreach (SyntaxTreeNode curNode in attributeNodes) + { + AppendFlattenedSpans(curNode, foundSpans); + } + } + + Block blockNode = node as Block; + if (blockNode != null) + { + foreach (SyntaxTreeNode curNode in blockNode.Children) + { + AppendFlattenedSpans(curNode, foundSpans); + } + } + } + } + } + } +} diff --git a/src/Microsoft.VisualStudio.LanguageServices.Razor/RazorSyntaxFactsService.cs b/src/Microsoft.VisualStudio.LanguageServices.Razor/RazorSyntaxFactsService.cs new file mode 100644 index 0000000000..4dbe40c580 --- /dev/null +++ b/src/Microsoft.VisualStudio.LanguageServices.Razor/RazorSyntaxFactsService.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.AspNetCore.Razor.Evolution; + +namespace Microsoft.VisualStudio.LanguageServices.Razor +{ + public abstract class RazorSyntaxFactsService + { + public abstract IReadOnlyList GetClassifiedSpans(RazorSyntaxTree syntaxTree); + } +}