私は最終的に、少なくともVS2010の解決策を思いつきました。#region
これを' 'および' 'タグの色付けに使用しまし#endregion
たが、同様のソリューションをVisualStudioウィンドウのすべてのテキストコンテンツに適用できるはずです。
この種の問題IViewTaggerProvider
は、ソースコードの一部に「分類」のタグを付けることで解決できるようです。Visual Studioは、その分類でタグ付けされたテキストのスタイルを提供します。これは、ユーザーが[ツール]>[オプション...]>[環境]>[フォントと色]を使用して目的のスタイルに変更できます。
Taggerプロバイダーは次のようになります。
[Export(typeof(IViewTaggerProvider))]
[ContentType("any")]
[TagType(typeof(ClassificationTag))]
public sealed class RegionTaggerProvider : IViewTaggerProvider
{
[Import]
public IClassificationTypeRegistryService Registry;
[Import]
internal ITextSearchService TextSearchService { get; set; }
public ITagger<T> CreateTagger<T>(ITextView textView, ITextBuffer buffer) where T : ITag
{
if (buffer != textView.TextBuffer)
return null;
var classType = Registry.GetClassificationType("region-foreground");
return new RegionTagger(textView, TextSearchService, classType) as ITagger<T>;
}
}
これにより、ITagger
オブジェクトが作成されます。このオブジェクトは、Visual Studioのテキストビューを指定すると、指定された分類タイプでテキストの一部にタグを付けます。これはすべてのテキストビュー(つまり、ソースコードエディタ、「結果の検索」ウィンドウなど)で機能することに注意してください。ContentType
属性を編集することでこれを変更できる場合があります( C#
?だけに)。
分類タイプ(この場合は「region-foreground」)は次のように定義されます。
public static class TypeExports
{
[Export(typeof(ClassificationTypeDefinition))]
[Name("region-foreground")]
public static ClassificationTypeDefinition OrdinaryClassificationType;
}
[Export(typeof(EditorFormatDefinition))]
[ClassificationType(ClassificationTypeNames = "region-foreground")]
[Name("region-foreground")]
[UserVisible(true)]
[Order(After = Priority.High)]
public sealed class RegionForeground : ClassificationFormatDefinition
{
public RegionForeground()
{
DisplayName = "Region Foreground";
ForegroundColor = Colors.Gray;
}
}
このOrder
属性は、テキストのスパンにも適用される可能性のある他の分類と比較して、分類がいつ適用されるかを決定します。は、[ツール]>[オプション... ]ダイアログDisplayName
で使用されます。
分類が定義されると、ITagger
クラスはビューのテキストを検索し、見つかったテキストの該当するセクションの分類を提供できます。
ViewLayoutChanged
簡単に言えば、その仕事は、提供されたテキストビューのコンテンツが変更されたときに発生するテキストビューのイベントをリッスンすることです(たとえば、ユーザーが何かを入力したため)。
次に、テキストを検索して、関心のあるテキストの領域(「スパン」と呼ばれる)を探す必要があります。#region
ここでは、またはのいずれかを含む行のスパンを返します#endregion
。これは単純にしていますが、TextSearchService
一致を見つけるために使用されるものは、正規表現を使用して検索することもできます。
最後に、Visual Studioが検出したテキストのタグを取得するための、と呼ばれるメソッドが提供されますGetTags()
。特定のスパンコレクションに対して、これは分類タグ付きのテキストスパン、つまり特定の方法で分類する必要があるスパンの領域を返します。
そのコードは次のとおりです。
public sealed class RegionTagger : ITagger<ClassificationTag>
{
private readonly ITextView m_View;
private readonly ITextSearchService m_SearchService;
private readonly IClassificationType m_Type;
private NormalizedSnapshotSpanCollection m_CurrentSpans;
public event EventHandler<SnapshotSpanEventArgs> TagsChanged = delegate { };
public RegionTagger(ITextView view, ITextSearchService searchService, IClassificationType type)
{
m_View = view;
m_SearchService = searchService;
m_Type = type;
m_CurrentSpans = GetWordSpans(m_View.TextSnapshot);
m_View.GotAggregateFocus += SetupSelectionChangedListener;
}
private void SetupSelectionChangedListener(object sender, EventArgs e)
{
if (m_View != null)
{
m_View.LayoutChanged += ViewLayoutChanged;
m_View.GotAggregateFocus -= SetupSelectionChangedListener;
}
}
private void ViewLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
{
if (e.OldSnapshot != e.NewSnapshot)
{
m_CurrentSpans = GetWordSpans(e.NewSnapshot);
TagsChanged(this, new SnapshotSpanEventArgs(new SnapshotSpan(e.NewSnapshot, 0, e.NewSnapshot.Length)));
}
}
private NormalizedSnapshotSpanCollection GetWordSpans(ITextSnapshot snapshot)
{
var wordSpans = new List<SnapshotSpan>();
wordSpans.AddRange(FindAll(@"#region", snapshot).Select(regionLine => regionLine.Start.GetContainingLine().Extent));
wordSpans.AddRange(FindAll(@"#endregion", snapshot).Select(regionLine => regionLine.Start.GetContainingLine().Extent));
return new NormalizedSnapshotSpanCollection(wordSpans);
}
private IEnumerable<SnapshotSpan> FindAll(String searchPattern, ITextSnapshot textSnapshot)
{
if (textSnapshot == null)
return null;
return m_SearchService.FindAll(
new FindData(searchPattern, textSnapshot) {
FindOptions = FindOptions.WholeWord | FindOptions.MatchCase
});
}
public IEnumerable<ITagSpan<ClassificationTag>> GetTags(NormalizedSnapshotSpanCollection spans)
{
if (spans == null || spans.Count == 0 || m_CurrentSpans.Count == 0)
yield break;
ITextSnapshot snapshot = m_CurrentSpans[0].Snapshot;
spans = new NormalizedSnapshotSpanCollection(spans.Select(s => s.TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive)));
foreach (var span in NormalizedSnapshotSpanCollection.Intersection(m_CurrentSpans, spans))
{
yield return new TagSpan<ClassificationTag>(span, new ClassificationTag(m_Type));
}
}
}
簡潔にするために、名前空間とusingステートメントは省略しました。これらは通常、の形式Microsoft.VisualStudio.Text.*
です。これらを使用できるようにするには、最初にVisual Studio2010SDKをダウンロードする必要があります。
私はこのソリューションを過去数か月間問題なく使用しています。
私が気付いた制限の1つは、色が「ブレンド」されていないため、不透明度が100%未満の色は、スパン内の既存の色を「フェードアウト」しないことです。これは、構文の強調表示を維持するのに役立つ場合があります。
また、キーを押すたびにドキュメントが繰り返し検索されるように見えるため、その効率についてもほとんどわかりません。VisualStudioがこれを何らかの形で最適化するかどうかを確認するための調査は行っていません。大きなファイル(>〜1000行)でVisual Studioの速度が低下していることに気付きましたが、Resharperも使用しているため、これをこのプラグインだけに帰することはできません。
これは主に当て推量を使用してコーディングされているため、物事を明確化または簡素化したり、コードのパフォーマンスを向上させたりする可能性のあるコメントやコード変更を歓迎します。