Почему возвращение доходности не работает при изменении локальных данных? - PullRequest
2 голосов
/ 12 июня 2019

Я пишу расширение Visual Studio и в настоящее время добавляю глифы полей в редактор.Я начал с пошагового примера из документации MS: https://docs.microsoft.com/en-us/visualstudio/extensibility/walkthrough-creating-a-margin-glyph?view=vs-2017.

Моя логика немного отличается от примера, так как я не анализирую содержимое файла, заданное параметром spans: я уже получаюнабор результатов с местоположениями дефектов из процесса анализа ранее.И обоснование состоит в том, чтобы просто сгенерировать тег, если и только если он еще не отображен.

Действительно, я хочу избежать ложного отображения нового глифа, если пользователь добавляет новую строку на строку передсуществующий флаг.Пример: если в строке 42 есть глиф, а курсор находится в строке 41, и пользователь вводит новую строку, то в строке 42 создается новый глиф (потому что метод GetTags вызывается снова), а предыдущий глиф перемещается в строку43.

Мой код:

internal class MyDefectTagger : ITagger<MyDefectTag>
{
    private IClassifier m_classifier;
    private ITextBuffer m_buffer;

    internal MyDefectTagger(IClassifier classifier, ITextBuffer buffer)
    {
        m_classifier = classifier;
        m_buffer = buffer;
    }

    IEnumerable<ITagSpan<MyDefectTag>>
        ITagger<MyDefectTag>.GetTags(NormalizedSnapshotSpanCollection spans)
    {
        var filename = GetFileName(m_buffer);

        if (MyModel.Instance == null || 
            MyModel.Instance.defectsLocation == null || 
            !MyModel.Instance.defectsLocation.ContainsKey(filename))
        {
            yield break;
        }

        foreach (SnapshotSpan span in spans)
        {
            ITextSnapshot textSnapshot = span.Snapshot;

            foreach (ITextSnapshotLine textSnapshotLine in textSnapshot.Lines)
            {
                var line = textSnapshotLine.LineNumber + 1; // Lines start at 1 in VS Editor

                if (MyModel.Instance.defectsLocation[filename].ContainsKey(line) &&
                    !MyModel.Instance.defectsLocation[filename][line].rendered)
                {
                    MyModel.Instance.defectsLocation[filename][line].rendered = true; // YIELD WORKS IF THIS LINE IS COMMENTED OUT
                    yield return new TagSpan<MyDefectTag>(new SnapshotSpan(textSnapshotLine.Start, 0), new MyDefectTag());
                }
            }
        }
    }
}

        public event EventHandler<SnapshotSpanEventArgs> TagsChanged;

        private string GetFileName(ITextBuffer buffer)
        {
            buffer.Properties.TryGetProperty(typeof(ITextDocument), out ITextDocument document);

            return document?.FilePath;
        }
    }

Странно то, что yield возвращается нормально, когда строка "rendered = true" закомментирована (хотя я получаю ложные новые глифы).В то время как выходы, кажется, заблокированы, когда строка render = true запущена (в то время как отладчик все еще выполняет команду yield).

Что-то пропущено?Запрещено ли изменять локальные данные при использовании yield return?Есть ли какая-то скрытая проблема параллелизма?Спасибо за вашу помощь!

1 Ответ

0 голосов
/ 21 июня 2019

Наконец я обнаружил, что неправильно сканировал строки, заданные интервалами NormalizedSnapshotSpanCollection. Я ошибочно повторял все строки для каждого диапазона с foreach (ITextSnapshotLine textSnapshotLine in textSnapshot.Lines). Фактически мне нужно было получить номер строки, связанный с данным диапазоном, и теперь он работает:

  • Я получаю соответствующие символы на каждой строке, мой анализ дает мне дефект.
  • Я не получаю больше дубликатов при добавлении новых строк непосредственно перед строкой, имеющей глиф поля.

Следовательно, мое решение:

        foreach (SnapshotSpan span in spans)
        {
            var lineNumber= span.Snapshot.GetLineNumberFromPosition(span.Start.Position) + 1;

            if (MyModel.Instance.defectsLocation[filename].ContainsKey(lineNumber) &&
                !MyModel.Instance.defectsLocation[filename][lineNumber].rendered)
            {
                //MyModel.Instance.defectsLocation[filename][lineNumber].rendered = true;//Strangely no getting any MyDefectTag displayed when I uncomment this line...
                yield return new TagSpan<MyDefectTag>(new SnapshotSpan(span.Start, 0), new MyDefectTag());
            }
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...