Voici ma solution pas la plus simple. TL; DR: vous pouvez passer au code https://github.com/jimmylewis/GetVSTextViewFormattedTextSample.
L'éditeur VS utilise des "classifications" pour afficher des segments de texte ayant une signification particulière. Ces classifications peuvent ensuite être formatées différemment en fonction de la langue et des paramètres utilisateur.
Il existe une API pour obtenir les classifications dans un document, mais cela n'a pas fonctionné pour moi. Ou other people, apparemment. Mais nous pouvons encore obtenir les classifications par un ITagAggregator<IClassificationTag>
, comme décrit dans le lien précédent, ou ici:
[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);
Armé de ceux-ci, nous pouvons reconstruire le document. Il est important de noter que certains textes sont et non classés, donc vous devez tout assembler en morceaux. Il est également notable qu'à ce stade, nous n'avons aucune idée de la façon dont l'une de ces étiquettes est formatée, c'est-à-dire les couleurs utilisées pendant le rendu. Si vous le souhaitez, vous pouvez définir votre propre correspondance de IClassificationType
à la couleur de votre choix. Ou, nous pouvons demander à VS pour ce qu'il ferait en utilisant un IClassificationFormatMap
. Encore une fois, rappelez-vous, cela est affectée par les paramètres utilisateur, la lumière par rapport à thème sombre, etc.
De toute façon, il pourrait ressembler à ceci:
// 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();
Hope this helps avec tout ce que vous faites. L'exemple de repo vous demandera si vous voulez que le texte mis en forme dans le presse-papiers après chaque édition, mais c'était juste une manière sale que je pourrais tester et voir que cela a fonctionné. C'est agaçant, mais c'était juste un PoC.
Pouvez-vous donner des détails plus précis sur ce que vous essayez de faire avec le texte? Il pourrait y avoir quelque chose d'autre qui fonctionnerait mieux que les couleurs ... – Jimmy
@Jimmy Je dois simplement stocker le texte. avec le formatage. sur chaque touche tapée ou chaque changement (par exemple, refactoring) effectué. Je suis d'accord avec les données * diff *, si c'est possible. –
@DmitryNesteruk Pour le dire autrement, est-ce que * color * est important, ou est-ce qu'une autre indication des limites de formatage fonctionnerait pour vous? – Jimmy