408 lines
14 KiB
C#
408 lines
14 KiB
C#
|
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|||
|
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Web.Razor.Editor;
|
|||
|
using System.Web.Razor.Generator;
|
|||
|
using System.Web.Razor.Parser;
|
|||
|
using System.Web.Razor.Parser.SyntaxTree;
|
|||
|
using System.Web.Razor.Text;
|
|||
|
using System.Web.Razor.Tokenizer;
|
|||
|
using System.Web.Razor.Tokenizer.Symbols;
|
|||
|
|
|||
|
namespace System.Web.Razor.Test.Framework
|
|||
|
{
|
|||
|
public static class SpanFactoryExtensions
|
|||
|
{
|
|||
|
public static UnclassifiedCodeSpanConstructor EmptyCSharp(this SpanFactory self)
|
|||
|
{
|
|||
|
return new UnclassifiedCodeSpanConstructor(
|
|||
|
self.Span(SpanKind.Code, new CSharpSymbol(self.LocationTracker.CurrentLocation, String.Empty, CSharpSymbolType.Unknown)));
|
|||
|
}
|
|||
|
|
|||
|
public static UnclassifiedCodeSpanConstructor EmptyVB(this SpanFactory self)
|
|||
|
{
|
|||
|
return new UnclassifiedCodeSpanConstructor(
|
|||
|
self.Span(SpanKind.Code, new VBSymbol(self.LocationTracker.CurrentLocation, String.Empty, VBSymbolType.Unknown)));
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor EmptyHtml(this SpanFactory self)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.Markup, new HtmlSymbol(self.LocationTracker.CurrentLocation, String.Empty, HtmlSymbolType.Unknown))
|
|||
|
.With(new MarkupCodeGenerator());
|
|||
|
}
|
|||
|
|
|||
|
public static UnclassifiedCodeSpanConstructor Code(this SpanFactory self, string content)
|
|||
|
{
|
|||
|
return new UnclassifiedCodeSpanConstructor(
|
|||
|
self.Span(SpanKind.Code, content, markup: false));
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor CodeTransition(this SpanFactory self)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.Transition, SyntaxConstants.TransitionString, markup: false).Accepts(AcceptedCharacters.None);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor CodeTransition(this SpanFactory self, string content)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.Transition, content, markup: false).Accepts(AcceptedCharacters.None);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor CodeTransition(this SpanFactory self, CSharpSymbolType type)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.Transition, SyntaxConstants.TransitionString, type).Accepts(AcceptedCharacters.None);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor CodeTransition(this SpanFactory self, string content, CSharpSymbolType type)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.Transition, content, type).Accepts(AcceptedCharacters.None);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor CodeTransition(this SpanFactory self, VBSymbolType type)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.Transition, SyntaxConstants.TransitionString, type).Accepts(AcceptedCharacters.None);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor CodeTransition(this SpanFactory self, string content, VBSymbolType type)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.Transition, content, type).Accepts(AcceptedCharacters.None);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor MarkupTransition(this SpanFactory self)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.Transition, SyntaxConstants.TransitionString, markup: true).Accepts(AcceptedCharacters.None);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor MarkupTransition(this SpanFactory self, string content)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.Transition, content, markup: true).Accepts(AcceptedCharacters.None);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor MarkupTransition(this SpanFactory self, HtmlSymbolType type)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.Transition, SyntaxConstants.TransitionString, type).Accepts(AcceptedCharacters.None);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor MarkupTransition(this SpanFactory self, string content, HtmlSymbolType type)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.Transition, content, type).Accepts(AcceptedCharacters.None);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor MetaCode(this SpanFactory self, string content)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.MetaCode, content, markup: false);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor MetaCode(this SpanFactory self, string content, CSharpSymbolType type)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.MetaCode, content, type);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor MetaCode(this SpanFactory self, string content, VBSymbolType type)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.MetaCode, content, type);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor MetaMarkup(this SpanFactory self, string content)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.MetaCode, content, markup: true);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor MetaMarkup(this SpanFactory self, string content, HtmlSymbolType type)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.MetaCode, content, type);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor Comment(this SpanFactory self, string content, CSharpSymbolType type)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.Comment, content, type);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor Comment(this SpanFactory self, string content, VBSymbolType type)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.Comment, content, type);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor Comment(this SpanFactory self, string content, HtmlSymbolType type)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.Comment, content, type);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor Markup(this SpanFactory self, string content)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.Markup, content, markup: true).With(new MarkupCodeGenerator());
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor Markup(this SpanFactory self, params string[] content)
|
|||
|
{
|
|||
|
return self.Span(SpanKind.Markup, content, markup: true).With(new MarkupCodeGenerator());
|
|||
|
}
|
|||
|
|
|||
|
public static SourceLocation GetLocationAndAdvance(this SourceLocationTracker self, string content)
|
|||
|
{
|
|||
|
SourceLocation ret = self.CurrentLocation;
|
|||
|
self.UpdateLocation(content);
|
|||
|
return ret;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public class SpanFactory
|
|||
|
{
|
|||
|
public Func<ITextDocument, ITokenizer> MarkupTokenizerFactory { get; set; }
|
|||
|
public Func<ITextDocument, ITokenizer> CodeTokenizerFactory { get; set; }
|
|||
|
public SourceLocationTracker LocationTracker { get; private set; }
|
|||
|
|
|||
|
public static SpanFactory CreateCsHtml()
|
|||
|
{
|
|||
|
return new SpanFactory()
|
|||
|
{
|
|||
|
MarkupTokenizerFactory = doc => new HtmlTokenizer(doc),
|
|||
|
CodeTokenizerFactory = doc => new CSharpTokenizer(doc)
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
public static SpanFactory CreateVbHtml()
|
|||
|
{
|
|||
|
return new SpanFactory()
|
|||
|
{
|
|||
|
MarkupTokenizerFactory = doc => new HtmlTokenizer(doc),
|
|||
|
CodeTokenizerFactory = doc => new VBTokenizer(doc)
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
public SpanFactory()
|
|||
|
{
|
|||
|
LocationTracker = new SourceLocationTracker();
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor Span(SpanKind kind, string content, CSharpSymbolType type)
|
|||
|
{
|
|||
|
return CreateSymbolSpan(kind, content, st => new CSharpSymbol(st, content, type));
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor Span(SpanKind kind, string content, VBSymbolType type)
|
|||
|
{
|
|||
|
return CreateSymbolSpan(kind, content, st => new VBSymbol(st, content, type));
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor Span(SpanKind kind, string content, HtmlSymbolType type)
|
|||
|
{
|
|||
|
return CreateSymbolSpan(kind, content, st => new HtmlSymbol(st, content, type));
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor Span(SpanKind kind, string content, bool markup)
|
|||
|
{
|
|||
|
return new SpanConstructor(kind, Tokenize(new[] { content }, markup));
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor Span(SpanKind kind, string[] content, bool markup)
|
|||
|
{
|
|||
|
return new SpanConstructor(kind, Tokenize(content, markup));
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor Span(SpanKind kind, params ISymbol[] symbols)
|
|||
|
{
|
|||
|
return new SpanConstructor(kind, symbols);
|
|||
|
}
|
|||
|
|
|||
|
private SpanConstructor CreateSymbolSpan(SpanKind kind, string content, Func<SourceLocation, ISymbol> ctor)
|
|||
|
{
|
|||
|
SourceLocation start = LocationTracker.CurrentLocation;
|
|||
|
LocationTracker.UpdateLocation(content);
|
|||
|
return new SpanConstructor(kind, new[] { ctor(start) });
|
|||
|
}
|
|||
|
|
|||
|
public void Reset()
|
|||
|
{
|
|||
|
LocationTracker.CurrentLocation = SourceLocation.Zero;
|
|||
|
}
|
|||
|
|
|||
|
private IEnumerable<ISymbol> Tokenize(IEnumerable<string> contentFragments, bool markup)
|
|||
|
{
|
|||
|
return contentFragments.SelectMany(fragment => Tokenize(fragment, markup));
|
|||
|
}
|
|||
|
|
|||
|
private IEnumerable<ISymbol> Tokenize(string content, bool markup)
|
|||
|
{
|
|||
|
ITokenizer tok = MakeTokenizer(markup, new SeekableTextReader(content));
|
|||
|
ISymbol sym;
|
|||
|
ISymbol last = null;
|
|||
|
while ((sym = tok.NextSymbol()) != null)
|
|||
|
{
|
|||
|
OffsetStart(sym, LocationTracker.CurrentLocation);
|
|||
|
last = sym;
|
|||
|
yield return sym;
|
|||
|
}
|
|||
|
LocationTracker.UpdateLocation(content);
|
|||
|
}
|
|||
|
|
|||
|
private ITokenizer MakeTokenizer(bool markup, SeekableTextReader seekableTextReader)
|
|||
|
{
|
|||
|
if (markup)
|
|||
|
{
|
|||
|
return MarkupTokenizerFactory(seekableTextReader);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return CodeTokenizerFactory(seekableTextReader);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void OffsetStart(ISymbol sym, SourceLocation sourceLocation)
|
|||
|
{
|
|||
|
sym.OffsetStart(sourceLocation);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static class SpanConstructorExtensions
|
|||
|
{
|
|||
|
public static SpanConstructor Accepts(this SpanConstructor self, AcceptedCharacters accepted)
|
|||
|
{
|
|||
|
return self.With(eh => eh.AcceptedCharacters = accepted);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor AutoCompleteWith(this SpanConstructor self, string autoCompleteString)
|
|||
|
{
|
|||
|
return AutoCompleteWith(self, autoCompleteString, atEndOfSpan: false);
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor AutoCompleteWith(this SpanConstructor self, string autoCompleteString, bool atEndOfSpan)
|
|||
|
{
|
|||
|
return self.With(new AutoCompleteEditHandler(SpanConstructor.TestTokenizer) { AutoCompleteString = autoCompleteString, AutoCompleteAtEndOfSpan = atEndOfSpan });
|
|||
|
}
|
|||
|
|
|||
|
public static SpanConstructor WithEditorHints(this SpanConstructor self, EditorHints hints)
|
|||
|
{
|
|||
|
return self.With(eh => eh.EditorHints = hints);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public class UnclassifiedCodeSpanConstructor
|
|||
|
{
|
|||
|
SpanConstructor _self;
|
|||
|
|
|||
|
public UnclassifiedCodeSpanConstructor(SpanConstructor self)
|
|||
|
{
|
|||
|
_self = self;
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor AsMetaCode()
|
|||
|
{
|
|||
|
_self.Builder.Kind = SpanKind.MetaCode;
|
|||
|
return _self;
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor AsStatement()
|
|||
|
{
|
|||
|
return _self.With(new StatementCodeGenerator());
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor AsExpression()
|
|||
|
{
|
|||
|
return _self.With(new ExpressionCodeGenerator());
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor AsImplicitExpression(ISet<string> keywords)
|
|||
|
{
|
|||
|
return AsImplicitExpression(keywords, acceptTrailingDot: false);
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor AsImplicitExpression(ISet<string> keywords, bool acceptTrailingDot)
|
|||
|
{
|
|||
|
return _self.With(new ImplicitExpressionEditHandler(SpanConstructor.TestTokenizer, keywords, acceptTrailingDot))
|
|||
|
.With(new ExpressionCodeGenerator());
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor AsFunctionsBody()
|
|||
|
{
|
|||
|
return _self.With(new TypeMemberCodeGenerator());
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor AsNamespaceImport(string ns, int namespaceKeywordLength)
|
|||
|
{
|
|||
|
return _self.With(new AddImportCodeGenerator(ns, namespaceKeywordLength));
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor Hidden()
|
|||
|
{
|
|||
|
return _self.With(SpanCodeGenerator.Null);
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor AsBaseType(string baseType)
|
|||
|
{
|
|||
|
return _self.With(new SetBaseTypeCodeGenerator(baseType));
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor AsRazorDirectiveAttribute(string key, string value)
|
|||
|
{
|
|||
|
return _self.With(new RazorDirectiveAttributeCodeGenerator(key, value));
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor As(ISpanCodeGenerator codeGenerator)
|
|||
|
{
|
|||
|
return _self.With(codeGenerator);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public class SpanConstructor
|
|||
|
{
|
|||
|
public SpanBuilder Builder { get; private set; }
|
|||
|
|
|||
|
internal static IEnumerable<ISymbol> TestTokenizer(string str)
|
|||
|
{
|
|||
|
yield return new RawTextSymbol(SourceLocation.Zero, str);
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor(SpanKind kind, IEnumerable<ISymbol> symbols)
|
|||
|
{
|
|||
|
Builder = new SpanBuilder();
|
|||
|
Builder.Kind = kind;
|
|||
|
Builder.EditHandler = SpanEditHandler.CreateDefault(TestTokenizer);
|
|||
|
foreach (ISymbol sym in symbols)
|
|||
|
{
|
|||
|
Builder.Accept(sym);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private Span Build()
|
|||
|
{
|
|||
|
return Builder.Build();
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor With(ISpanCodeGenerator generator)
|
|||
|
{
|
|||
|
Builder.CodeGenerator = generator;
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor With(SpanEditHandler handler)
|
|||
|
{
|
|||
|
Builder.EditHandler = handler;
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor With(Action<ISpanCodeGenerator> generatorConfigurer)
|
|||
|
{
|
|||
|
generatorConfigurer(Builder.CodeGenerator);
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor With(Action<SpanEditHandler> handlerConfigurer)
|
|||
|
{
|
|||
|
handlerConfigurer(Builder.EditHandler);
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
public static implicit operator Span(SpanConstructor self)
|
|||
|
{
|
|||
|
return self.Build();
|
|||
|
}
|
|||
|
|
|||
|
public SpanConstructor Hidden()
|
|||
|
{
|
|||
|
Builder.CodeGenerator = SpanCodeGenerator.Null;
|
|||
|
return this;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|