Pracuję nad rozszerzeniem Visual Studio, które udostępnia niektóre funkcje dla niestandardowego języka. Zrobiłem proste podświetlanie składni i zamierzam przejść do takich kwestii jak podświetlanie składni, dopasowywanie klamr, tworzenie konturów i podobne. Podstawowym problemem, który teraz szukam, jest to, że wszystkie te wymagają różnych typów tagów, które (o ile widzę) wymagałyby różnych taggerów. Nie widzę jednak intuicyjnego sposobu dzielenia się informacjami między taggerami, ponieważ wszystkie te trzy rzeczy można wykonać w jednej analizie zawartości. Chodzi mi o to, że mógłbym przetworzyć go trzy razy, ale to nie brzmi jak dobre rozwiązanie.Tworzenie taggera, który ma więcej niż jeden typ tagu dla rozszerzenia VS
Jak mogę zwrócić więcej niż jeden typ znacznika z taggera (może użyć ITag?) Lub udostępnić informacje między więcej niż jednym taggerem?
Moja obecna struktura jest jako takie:
internal class HighlightWordTagger : ITagger<ClassificationTag>
{
ITextBuffer TextBuffer;
IClassificationType Keyword;
IClassificationType Comment;
IClassificationType Literal;
// Probably a giant memory leak
Dictionary<ITextSnapshot, List<TagSpan<ClassificationTag>>> SnapshotResults = new Dictionary<ITextSnapshot, List<TagSpan<ClassificationTag>>>();
public HighlightWordTagger(ITextBuffer sourceBuffer, IClassificationTypeRegistryService typeService)
{
TextBuffer = sourceBuffer;
TextBuffer.Changed += (sender, args) =>
{
LexSnapshot(args.After);
TagsChanged(this, new SnapshotSpanEventArgs(new SnapshotSpan(args.After, new Span(0, args.After.Length))));
};
Keyword = typeService.GetClassificationType("WideKeyword");
Comment = typeService.GetClassificationType("WideComment");
Literal = typeService.GetClassificationType("WideLiteral");
}
public IEnumerable<ITagSpan<ClassificationTag>> GetTags(NormalizedSnapshotSpanCollection spans)
{
LexSnapshot(spans[0].Snapshot);
foreach (var snapshotspan in SnapshotResults[spans[0].Snapshot])
{
foreach (var span in spans)
{
if (snapshotspan.Span.IntersectsWith(span))
{
yield return snapshotspan;
}
}
}
}
Span SpanFromLexer(Lexer.Range range)
{
return new Span((int)range.begin.offset, (int)(range.end.offset - range.begin.offset));
}
void LexSnapshot(ITextSnapshot shot)
{
if (SnapshotResults.ContainsKey(shot))
return;
var lexer = new Lexer();
var list = new List<TagSpan<ClassificationTag>>();
SnapshotResults[shot] = list;
lexer.Read(
shot.GetText(),
(where, what) =>
{
if (what == Lexer.Failure.UnlexableCharacter)
return false;
var loc = new Span(
(int)where.offset,
(int)shot.Length - (int)where.offset
);
if (what == Lexer.Failure.UnterminatedComment)
list.Add(new TagSpan<ClassificationTag>(new SnapshotSpan(shot, loc), new ClassificationTag(Comment)));
if (what == Lexer.Failure.UnterminatedStringLiteral)
list.Add(new TagSpan<ClassificationTag>(new SnapshotSpan(shot, loc), new ClassificationTag(Literal)));
return false;
},
where =>
{
// Clamp this so it doesn't go over the end when we add \n in the lexer.
where.end.offset = where.end.offset > shot.Length ? (uint)(shot.Length) : where.end.offset;
var loc = SpanFromLexer(where);
list.Add(new TagSpan<ClassificationTag>(new SnapshotSpan(shot, loc), new ClassificationTag(Comment)));
},
token => {
var location = SpanFromLexer(token.location);
if (token.type == Lexer.TokenType.String || token.type == Lexer.TokenType.Integer)
{
list.Add(new TagSpan<ClassificationTag>(new SnapshotSpan(shot, location), new ClassificationTag(Literal)));
}
if (lexer.IsKeyword(token.type))
{
list.Add(new TagSpan<ClassificationTag>(new SnapshotSpan(shot, location), new ClassificationTag(Keyword)));
}
return false;
}
);
}
public event EventHandler<SnapshotSpanEventArgs> TagsChanged = delegate { };
}
prawdopodobnie mógłbym zrobić lepszą pracę wolno ponownie Lexing tyle, ale to na innym pytaniem.
@Witaj: Używam tylko leksykonu z jednym znacznikiem. Wzywam do niezarządzanego kodu do lex i parsowania, i to działa jednocześnie. – Puppy
@ Yvette: Tak ... mój komentarz nie był bardzo pomocny. Pozwól, że opublikuję swoją strukturę. – Puppy
To uderzyło mnie, że możesz być w stanie uzyskać ponowne użycie, jeśli zaimplementujesz 'ITagger' wiele razy w obrębie tej samej klasy (dla różnych 'T's). W ten sposób istnieje przynajmniej oczywisty sposób "dzielenia się informacjami" pomiędzy taggerami - ponieważ jest to ta sama klasa. –