在ITextViewLine上运行RegEx(Visual Studio扩展)

时间:2016-01-09 11:31:56

标签: c# regex visual-studio visual-studio-extensions

我希望运行一个RegEx搜索,在编辑器窗口中找到所有出现的某些关键字,然后绘制一些装饰品并为它们添加一些标签。

有没有办法在ITextViewLine上运行RegEx。

这就是我的调用函数的外观:

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
    }
}

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

1 个答案:

答案 0 :(得分:3)

我终于开始工作了。有两种方法可以做到。

我的方式(更简单)

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);
        }
    }
}