![](/img/trans.png)
[英]Is there a setting or good add-in for Visual Studio to color lines (like Throw) in the editor?
[英]How to write an add-in to change text color in Visual Studio editor?
在搜索了很长一段时间以便在Visual Studio中更改#region
指令的文本颜色之后,我得出结论,没有简单的方法可以做到这一点。
我知道如何更改#region
语句颜色,以及如何更改折叠区域颜色,但我想用区域描述更改文本的颜色。 所以:
#region Some text <--- all this text should be in a different color
public void Test()
{
}
#endregion <--- this too
似乎很多人都在寻找这样的东西 - 请参阅如何在VS2008中更改扩展区域标题的颜色? 。
所以我一直在寻找一个简单的Visual Studio加载项来改变颜色。 然而,它比我想象的要复杂得多,比如Snapshot
, Tagger
, Classifier
, WpfTextViewCreationListener
, AdornmentLayer
等。
简单地说,我不知道从哪里开始! 我在MSDN网站上关注了几个教程 ,但它们看起来太复杂了我想要做的事情。
有人能指出我最简单的方法吗? IE浏览器。 我应该使用VS SDK中的哪些类/方法/事件。 我不介意颜色是否也不能通过UI等进行自定义。 我正在使用VS2010。
编辑:刚推荐给我的mztools网站; 我也会看看那里。 还注意到StackOverflow对region
s的语法突出显示正是我想要的!
我最终想出了一个解决方案,至少对于VS2010来说。 虽然我使用它来着色' #region
'和' #endregion
'标签,但类似的解决方案应该适用于Visual Studio窗口中的任何文本内容。
看来这种问题可以通过创建一个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
将在Tools> Options ...对话框中使用。
定义分类后, ITagger
类可以搜索视图的文本,并为其找到的文本的适用部分提供分类。
简单地说,它的工作是监听文本视图的ViewLayoutChanged
事件,当提供的文本视图的内容发生变化时触发(例如因为用户输入了某些内容)。
然后,它必须在文本中搜索它感兴趣的文本区域(称为“span”)。 在这里,它返回包含#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 Studio 2010 SDK 。
过去几个月我一直在使用这个解决方案而没有问题。
我注意到的一个限制是颜色不是“混合”,因此不透明度小于100%的颜色不会“淡出”跨度中的现有颜色 - 这可能有助于保留语法高亮。
我也不知道它的效率,因为看起来它会在每个按键上反复搜索文档。 我还没有做过研究,看看Visual Studio是否以某种方式优化了这一点。 我注意到Visual Studio在大文件(> ~1000行)上的速度减慢,但我也使用Resharper,所以我不能单独将它归因于这个插件。
由于这主要是通过猜测来编码的,因此我欢迎任何可以澄清或简化内容或改进代码性能的注释或代码更改。
我想你可以从Visual Studio加载项开始,它将使用EnvDTE,它被认为是Visual Studio对象模型,请在这里找到MSDN文档: http : //msdn.microsoft.com/en-us/vstudio/ bb968855您可以通过EnvDTE控制Visual Studio的行为,如调试器,代码编辑器等。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.