运行 ITextViewLine 上的正则表达式(Visual Studio 扩展)

Running a RegEx on an ITextViewLine (Visual Studio Extension)

我正在寻找 运行 正则表达式搜索,以在编辑器中查找所有出现的特定关键字 Window,然后绘制一些装饰物并向它们添加一些标签。

有什么方法可以在 ITextViewLine.

上 运行 正则表达式

这是我的调用函数的样子:

private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
{
    foreach (ITextViewLine line in e.NewOrReformattedLines)
    {
        this.CreateVisuals(line);
    }
}

private void CreateVisuals(ITextViewLine line)
{
    IWpfTextViewLineCollection textViewLines = _wpfTextView.TextViewLines;
    // Run RegEx match here and do some stuff for all matches
}

根据 @stribizhev 的建议,我尝试使用 FormattedSpan 如下:

private void CreateVisuals(ITextViewLine line)
{
    var textViewLines = _wpfTextView.TextViewLines;
    var snapshot = textViewLines.FormattedSpan;
    var text = snapshot.ToString();
    var todoRegex = new Regex(@"\/\/\s*TODO\b");
    var match = todoRegex.Match(text);
    if (match.Success)
    {
        int matchStart = line.Start.Position + match.Index;
        var span = new SnapshotSpan(_wpfTextView.TextSnapshot, Span.FromBounds(matchStart, matchStart + match.Length));
        DrawAdornment(textViewLines, span);
    }
}

但这会在调用 DrawAdornment 时导致 NullReference 告诉我 span 未设置。 此外,通过在 CreateVisuals 函数的所有行上放置断点,我看到只有当包含 TODO 的行滚出视图或成为视口中的第一行时,突出显示才会开始。

我试过的输入是:

using System;
public class Class1
{
    public Class1()
    {
        // TODO: It's a good thing to have todos
    }
}

代码有时可以放置装饰,但它们会稍微向右移动并出现在三个不同的行上。

我终于让它工作了。有两种方法。

我的方式(更简单):

private void CreateVisuals()
    {
        var textViewLines = _wpfTextView.TextViewLines;
        var text = textViewLines.FormattedSpan.Snapshot.GetText();
        var todoRegex = new Regex(@"\/\/\s*TODO\b");
        var match = todoRegex.Match(text);
        while (match.Success)
        {
            var matchStart = match.Index;
            var span = new SnapshotSpan(_wpfTextView.TextSnapshot, Span.FromBounds(matchStart, matchStart + match.Length));
            DrawAdornment(textViewLines, span);
            match = match.NextMatch();
        }

艰难的(呃)方式:(来自 this article

/// <summary>
/// This will get the text of the ITextView line as it appears in the actual user editable 
/// document. 
/// jared parson: https://gist.github.com/4320643
/// </summary>
public static bool TryGetText(IWpfTextView textView, ITextViewLine textViewLine, out string text)
{
    var extent = textViewLine.Extent;
    var bufferGraph = textView.BufferGraph;
    try
    {
        var collection = bufferGraph.MapDownToSnapshot(extent, SpanTrackingMode.EdgeInclusive, textView.TextSnapshot);
        var span = new SnapshotSpan(collection[0].Start, collection[collection.Count - 1].End);
        //text = span.ToString();
        text = span.GetText();
        return true;
    }
    catch
    {
        text = null;
        return false;
    }
}

Regex todoLineRegex = new Regex(@"\/\/\s*TODO\b");

private void CreateVisuals(ITextViewLine line)
{
    IWpfTextViewLineCollection textViewLines = _view.TextViewLines;
    string text = null;
    if (TryGetText(_view, line, out text))
    {
        var match = todoLineRegex.Match(text);
        if (match.Success)
        {
            int matchStart = line.Start.Position + span.Index;
            var span = new SnapshotSpan(_view.TextSnapshot, Span.FromBounds(matchStart, matchStart + match.Length));
            DrawAdornment(textViewLines, span);
        }
    }
}