// 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; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax; namespace Microsoft.AspNetCore.Razor.Language.Legacy { internal class SpanBuilder { private SourceLocation _start; private List _tokens; private SourceLocationTracker _tracker; public SpanBuilder(Span original) { Kind = original.Kind; EditHandler = original.EditHandler; _start = original.Start; ChunkGenerator = original.ChunkGenerator; _tokens = new List(original.Tokens.Select(t =>t.Green)); _tracker = new SourceLocationTracker(original.Start); } public SpanBuilder(SourceLocation location) { _tracker = new SourceLocationTracker(); Reset(); Start = location; } public Syntax.GreenNode SyntaxNode { get; private set; } public ISpanChunkGenerator ChunkGenerator { get; set; } public SourceLocation Start { get { return _start; } set { _start = value; _tracker.CurrentLocation = value; } } public SourceLocation End => _tracker.CurrentLocation; public SpanKindInternal Kind { get; set; } public IReadOnlyList Tokens { get { if (_tokens == null) { _tokens = new List(); } return _tokens; } } public SpanEditHandler EditHandler { get; set; } public void Reset() { // Need to potentially allocate a new list because Span.ReplaceWith takes ownership // of the original list. _tokens = null; _tokens = new List(); EditHandler = SpanEditHandler.CreateDefault((content) => Enumerable.Empty()); ChunkGenerator = SpanChunkGenerator.Null; Start = SourceLocation.Undefined; } public Span Build(SyntaxKind syntaxKind = SyntaxKind.Unknown) { SyntaxNode = GetSyntaxNode(syntaxKind); var span = new Span(this); return span; } public void ClearTokens() { _tokens?.Clear(); } public void Accept(SyntaxToken token) { if (token == null) { return; } if (Start.Equals(SourceLocation.Undefined)) { throw new InvalidOperationException("SpanBuilder must have a valid location"); } _tokens.Add(token); _tracker.UpdateLocation(token.Content); } private Syntax.GreenNode GetSyntaxNode(SyntaxKind syntaxKind) { if (syntaxKind == SyntaxKind.HtmlTextLiteral) { var textTokens = new SyntaxListBuilder(SyntaxListBuilder.Create()); foreach (var token in Tokens) { if (token.Kind == SyntaxKind.Unknown) { Debug.Assert(false, $"Unexpected token {token.Kind}"); continue; } textTokens.Add(token); } var textResult = textTokens.ToList(); return SyntaxFactory.HtmlTextLiteral(new SyntaxList(textResult.Node)); } return null; } } }