Как получить весь активный документ Visual Studio... с форматированием
Я знаю, как использовать VS Extensibility, чтобы получить весь текст активного документа. К сожалению, это только дает мне текст и не дает мне форматирование, и я тоже этого хочу.
Я могу, например, получить IWpfTextView
но как только я получу это, я не уверен, что делать с этим. Есть ли примеры того, как можно получить все форматирование? Меня интересует только цвет текста и фона, вот и все.
Примечание: мне нужен форматированный текст при каждом редактировании, поэтому, к сожалению, выполнять вырезание и вставку с использованием буфера обмена невозможно.
2 ответа
Возможно, самый простой способ - выделить весь текст и скопировать его в буфер обмена. VS помещает форматированный текст в буфер обмена, поэтому при вставке в другое место вы получите цвета (при условии, что вы обрабатываете форматированный текст в месте назначения).
Вот мое не самое простое решение. TL;DR: вы можете перейти к коду по адресу https://github.com/jimmylewis/GetVSTextViewFormattedTextSample.
Редактор VS использует "классификации", чтобы показать фрагменты текста, которые имеют особое значение. Эти классификации могут быть отформатированы по-разному в зависимости от языка и пользовательских настроек.
Есть API для получения классификаций в документе, но он не работает для меня. Или другие люди, по-видимому. Но мы все еще можем получить классификации через ITagAggregator<IClassificationTag>
, как описано в предыдущей ссылке, или прямо здесь:
[Import]
IViewTagAggregatorFactoryService tagAggregatorFactory = null;
// in some method...
var classificationAggregator = tagAggregatorFactory.CreateTagAggregator<IClassificationTag>(textView);
var wholeBufferSpan = new SnapshotSpan(textBuffer.CurrentSnapshot, 0, textBuffer.CurrentSnapshot.Length);
var tags = classificationAggregator.GetTags(wholeBufferSpan);
Вооружившись этим, мы можем перестроить документ. Важно отметить, что некоторый текст не засекречен, поэтому вы должны собрать все воедино.
Также примечательно, что на данный момент мы не имеем представления о том, как форматируются какие-либо из этих тегов - то есть цвета, используемые во время рендеринга. Если вы хотите, вы можете определить свое собственное отображение из IClassificationType
цвет по вашему выбору. Или мы можем спросить VS, что бы он сделал, используя IClassificationFormatMap
, Опять же, помните, на это влияют пользовательские настройки, тема Light vs. Dark и т. Д.
В любом случае, это может выглядеть примерно так:
// Magic sauce pt1: See the example repo for an RTFStringBuilder I threw together.
RTFStringBuilder sb = new RTFStringBuilder();
var wholeBufferSpan = new SnapshotSpan(textBuffer.CurrentSnapshot, 0, textBuffer.CurrentSnapshot.Length);
// Magic sauce pt2: see the example repo, but it's basically just
// mapping the spans from the snippet above with the formatting settings
// from the IClassificationFormatMap.
var textSpans = GetTextSpansWithFormatting(textBuffer);
int currentPos = 0;
var formattedSpanEnumerator = textSpans.GetEnumerator();
while (currentPos < wholeBufferSpan.Length && formattedSpanEnumerator.MoveNext())
{
var spanToFormat = formattedSpanEnumerator.Current;
if (currentPos < spanToFormat.Span.Start)
{
int unformattedLength = spanToFormat.Span.Start - currentPos;
SnapshotSpan unformattedSpan = new SnapshotSpan(textBuffer.CurrentSnapshot, currentPos, unformattedLength);
sb.AppendText(unformattedSpan.GetText(), System.Drawing.Color.Black);
}
System.Drawing.Color textColor = GetTextColor(spanToFormat.Formatting.ForegroundBrush);
sb.AppendText(spanToFormat.Span.GetText(), textColor);
currentPos = spanToFormat.Span.End;
}
if (currentPos < wholeBufferSpan.Length)
{
// append any remaining unformatted text
SnapshotSpan unformattedSpan = new SnapshotSpan(textBuffer.CurrentSnapshot, currentPos, wholeBufferSpan.Length - currentPos);
sb.AppendText(unformattedSpan.GetText(), System.Drawing.Color.Black);
}
return sb.ToString();
Надеюсь, это поможет с тем, что вы делаете. Пример репозитория спросит, хотите ли вы отформатированный текст в буфере обмена после каждого редактирования, но это был просто грязный способ, который я мог проверить и убедиться, что он работает. Это раздражает, но это был просто PoC.