Как установить «текстовые» теги или классификаторы в редакторе исходного кода Visual Studio - PullRequest
0 голосов
/ 03 октября 2019

Я занимаюсь разработкой расширения Visual Studio, и мне нужно разместить теги, классификаторы или украшения в окне исходного кода. Я получил некоторую информацию о строках / столбцах, полученную в результате анализа исходного кода. Для первого шага я мог бы разместить их успешно. Проблема возникает, когда пользователь продолжает изменять исходный код: мои «маркеры» быстро перестают синхронизироваться.

Я обнаружил следующую загрузочную документацию: https://docs.microsoft.com/en-us/visualstudio/extensibility/walkthrough-creating-a-margin-glyph?view=vs-2017 и другие подобные страницы. Насколько я понимаю, подход по умолчанию заключается в том, что основная процедура размещения (например, " IEnumerable> ITagger.GetTags (NormalizedSnapshotSpanCollection spans) ") будет вызываться каждый раз, когда код изменяется или прокручивается на экране. Это хорошо, когда анализ исходного кода прост и быстр. Вы можете обновить очень часто.

Однако я не могу этого сделать. Мой анализ намного сложнее и дольше. Я не могу все время обновляться. Я понимаю, что мне нужно, чтобы «маркеры» в окне исходного кода были «относительными к тексту», то есть я хочу, чтобы они были привязаны к какому-либо тексту (изначально расположенному в этой строке / столбце) и перемещались вместе с ним, когда пользователь продолжал изменять исходный кодкод вокруг.

  • Есть ли какой-нибудь способ указать эти "маркеры" (глифы, теги окраски синтаксиса, графические теги в тексте и, кстати, все остальные, такие как всплывающие подсказки, подсказки с лампочками, выделенный текст и т. Д. ) можно установить как «относительный к тексту», чтобы они автоматически обновлялись как пользовательские типы? Есть ли примеры?

  • Или мне нужно обновлять расположение маркеров самостоятельно, когда пользователь изменяет код? Как я могу получить информацию о модификации (исходное местоположение курсора, количество добавленных / удаленных символов / строк)? Кажется, я не могу найти это с заданными объектами SnapshotSpan.

Терминология: когда я говорю «относительный текст», я имею в виду, что маркеры «привязаны» к некоторой строке. Расположение столбца, чтобы соответствовать некоторому тексту при его создании, и они перемещаются вместе с текстом, когда пользователь обновляет код. Другие IDE предоставляют это по умолчанию: вы создали «маркеры» один раз, и они перемещались вместе с текстом, пока вы не удалите их и не создадите другие.

1 Ответ

1 голос
/ 09 октября 2019

Не уверен, что если вы попробовали приведенную ниже ссылку, она должна соответствовать вашему требованию о тегах "text-относительный"

https://docs.microsoft.com/en-us/visualstudio/extensibility/creating-an-extension-with-an-editor-item-template?view=vs-2017

Создать расширение для текстового обозначения

Шаблон редактирования текста в редакторе создает относительное к тексту украшение, которое украшает все экземпляры текстового символа «а» с помощью прямоугольника с красным контуром и синим фоном. Он относится к тексту, поскольку в поле всегда накладываются символы 'a' , даже если они перемещены или переформатированы.

Добавить примеры кодов:

public TextAdornment1(IWpfTextView view)
    {
        if (view == null)
        {
            throw new ArgumentNullException("view");
        }

        this.layer = view.GetAdornmentLayer("TextAdornment1");

        this.view = view;
        this.view.LayoutChanged += this.OnLayoutChanged;

        // Create the pen and brush to color the box behind the a's
        this.brush = new SolidColorBrush(Color.FromArgb(0x20, 0x00, 0x00, 0xff));
        this.brush.Freeze();

        var penBrush = new SolidColorBrush(Colors.Red);
        penBrush.Freeze();
        this.pen = new Pen(penBrush, 0.5);
        this.pen.Freeze();
    }

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

 private void CreateVisuals(ITextViewLine line)
    {
        IWpfTextViewLineCollection textViewLines = this.view.TextViewLines;

        // Loop through each character, and place a box around any 'a'
        for (int charIndex = line.Start; charIndex < line.End; charIndex++)
        {
            if (this.view.TextSnapshot[charIndex] == 'a')
            {
                SnapshotSpan span = new SnapshotSpan(this.view.TextSnapshot, Span.FromBounds(charIndex, charIndex + 1));
                Geometry geometry = textViewLines.GetMarkerGeometry(span);
                if (geometry != null)
                {
                    var drawing = new GeometryDrawing(this.brush, this.pen, geometry);
                    drawing.Freeze();

                    var drawingImage = new DrawingImage(drawing);
                    drawingImage.Freeze();

                    var image = new Image
                    {
                        Source = drawingImage,
                    };

                    // Align the image with the top of the bounds of the text geometry
                    Canvas.SetLeft(image, geometry.Bounds.Left);
                    Canvas.SetTop(image, geometry.Bounds.Top);

                    this.layer.AddAdornment(AdornmentPositioningBehavior.TextRelative, span, null, image, null);
                }
            }
        }
    }
...