Pup*_*ppy 11 visual-studio-2012
我正在开发一个Visual Studio扩展,它为自定义语言提供了一些功能.我已经完成了简单的语法高亮,我希望继续学习语法错误突出显示,大括号匹配,大纲等等.我现在关注的主要问题是这些都需要不同的标签类型,(我可以看到)需要不同的标签.但是,我看不到任何直观的方式在标记器之间共享信息,因为所有这三件事都可以在内容的一个解析中完成.我的意思是,我可以解析它三次,但这听起来不是一个好的解决方案.
如何从标记器返回多个标记类型(可能使用ITag?)或在多个标记器之间共享信息?
我目前的结构是这样的:
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 { };
}
Run Code Online (Sandbox Code Playgroud)
我可能会做得更好,不要那么多,但这是另一个问题.
我最终不得不将这些问题分开.您可以使用ITextBuffer.Properties.GetOrCreateSingletonProperty将您选择的任意对象与文本缓冲区相关联.我最终创建了一个单独的lexer类,将它与文本缓冲区相关联,然后简单地执行除了标记之外的几乎所有逻辑.然后在每个标记器的实现中,我只是在lexer中查询结果,然后标记它们.这允许多个标记符依赖于相同的词法分析器实例.
考虑到大多数词法分析器和解析器会生成不止一种标签,我很惊讶VS会让你非常难以产生这种结果.
| 归档时间: |
|
| 查看次数: |
919 次 |
| 最近记录: |