配置语言语法突出显示Visual Studio的C#扩展

时间:2016-11-14 07:22:46

标签: c# .net visual-studio plugins add-in

我有一个Visual Studio for Java加载项,如配置文件。可以找到示例文件here

在特定行上插入 \ 字符时会出现问题。当使用向后斜杠时,下一行被解释为值(或作为键,或作为键和值)。一个简单的例子是:

1. part1_key\
2. part2_key\
3. part3_key = value

4. key = part1_value\
5.       part2_value

语法高亮显示器在加载文件时有效,但是当修改一行时,只评估那条行并突出显示。因此,例如,当第4行插入 \ 时,第4行会突出显示,但第5行更新。第5行仅在修改后更新(添加或删除字符或空格)。

我创建了一个 ITaggerProvider ,用于创建 ITagger ,其类型为 Key Value 注释 ITagger 类如下:

internal sealed class PropertiesTokenTagger : ITagger<PropertiesTokenTag> {
        private readonly Regex keyValuePattern = new Regex(@"(?<!^\s*|\\)([ \t]*[=:][ \t]*|[ \t]+)");
        private readonly Regex separatorPattern = new Regex(@"^([=:]|[ \t]+)");
        private readonly Regex commentPattern = new Regex(@"^\s*[#!]");
        private readonly Regex escapedLineEndPattern = new Regex(@"\\$");

        public event EventHandler<SnapshotSpanEventArgs> TagsChanged {
            add { }
            remove { }
        }

        public IEnumerable<ITagSpan<PropertiesTokenTag>> GetTags(NormalizedSnapshotSpanCollection spans) {
            // sadly `spans` gets one line at a time, so previouslyEscapedValue will not get the chance to be used
            foreach (var curSpan in spans) {
                var containingLine = curSpan.Start.GetContainingLine();
                var lineStartLoc = containingLine.Start.Position;
                var lineText = containingLine.GetText();
                var previousIsNotComment = false;

                var previousLine = curSpan.Snapshot.Lines.LastOrDefault(l => l.End <= curSpan.Start);
                if (previousLine != null && escapedLineEndPattern.IsMatch(previousLine.GetText())) {
                    var previousToken = GetTags(new NormalizedSnapshotSpanCollection(previousLine.Extent)).ToList();

                    if (previousToken.Count > 0) {
                        var propertiesTokenTypes = previousToken.Last().Tag.Type;
                        if (propertiesTokenTypes == PropertiesValue) {
                            var valueSpan = new SnapshotSpan(curSpan.Snapshot, new Span(lineStartLoc, lineText.Length));
                            yield return new TagSpan<PropertiesTokenTag>(valueSpan, new PropertiesTokenTag(PropertiesValue));
                            continue;
                        }

                        if (propertiesTokenTypes == PropertiesKey && separatorPattern.IsMatch(lineText)) {
                            var valueSpan = new SnapshotSpan(curSpan.Snapshot, new Span(lineStartLoc, lineText.Length));
                            yield return new TagSpan<PropertiesTokenTag>(valueSpan, new PropertiesTokenTag(PropertiesValue));
                            continue;
                        }

                        previousIsNotComment = propertiesTokenTypes != PropertiesComment;
                    }
                }

                if (commentPattern.IsMatch(lineText) && !previousIsNotComment) {
                    var commentSpan = new SnapshotSpan(curSpan.Snapshot, new Span(lineStartLoc, lineText.Length));
                    yield return new TagSpan<PropertiesTokenTag>(commentSpan, new PropertiesTokenTag(PropertiesComment));
                    continue;
                }

                if (keyValuePattern.IsMatch(lineText)) {
                    var splitPosition = keyValuePattern.Split(lineText)[0].Length;
                    var keySpan = new SnapshotSpan(curSpan.Snapshot, new Span(lineStartLoc, splitPosition));
                    yield return new TagSpan<PropertiesTokenTag>(keySpan, new PropertiesTokenTag(PropertiesKey));
                    var valueSpan = new SnapshotSpan(curSpan.Snapshot, new Span(lineStartLoc + splitPosition + 1, lineText.Length - splitPosition - 1));
                    yield return new TagSpan<PropertiesTokenTag>(valueSpan, new PropertiesTokenTag(PropertiesValue));
                } else {
                    var keySpan = new SnapshotSpan(curSpan.Snapshot, new Span(lineStartLoc, lineText.Length));
                    yield return new TagSpan<PropertiesTokenTag>(keySpan, new PropertiesTokenTag(PropertiesKey));
                }
            }
        }

从我看到的问题是,从外部源调用 GetTags 方法的事实,我无法手动调用此方法以更新其他行。此方法返回 TagSpans List ,其中 NormalizedSnapshotSpanCollection 参数相交,因此,如果我尝试返回标记除当前行之外的另一行,该标记不会被处理。

LE:我已经完成了,解决方案是从GetTags方法外部引发TagsChanged事件,也从 ITagger 中的聚合器引发。

0 个答案:

没有答案