在 VS Code 编辑器中颜色化区域






4.82/5 (3投票s)
使用 VS SDK 颜色化区域
引言
很多时候,你在一个类中创建大量的区域,但在分析不同部分时,很容易迷失方向。当然,你可以将其分成不同的部分,但我更喜欢稍微颜色化一下。
背景
我已经在很多网站上查找过,并测试了 VS 2010 的插件,但没有一个能做到我想要的功能。所以最后,我决定自己尝试一下。
理解代码
想法是在某个地方定义颜色映射 <color,keyword>
,以 `region` 前缀的形式在注释中,如下所示
//region lightgreen Properties;
//region lightcyan Actions;
然后,在任何你想要具有该背景颜色的区域中,包含该关键字,就像介绍截图中的那样。
Using the Code
首先,你需要安装 VS 2010 SDK SP1。然后创建一个新项目,选择“编辑器文本装饰”。
在这种情况下,我为区域选择一个来自 Colors
类的颜色,创建一个矩形。这是我的第二个方法
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Formatting;
using System.Reflection;
using System.Windows.Shapes;
using System.Collections;
using System.Collections.ObjectModel;
namespace TextAdornment1
{
public class PairedRegion
{
public int start;
public int end;
public Color RegionColor;
}
public class ColorRegionAdornment
{
public string Definition; //Text definition of the region
public Color RegionColor; //Background Color of the region
#region ColorHelper
private static Hashtable colortable = null;
public static Color ParseColor(string text)
{
Color cl = Colors.Transparent;
if (colortable == null)
{
colortable = new Hashtable();
foreach (PropertyInfo pi in typeof(Colors).GetProperties())
colortable.Add(pi.Name.ToLower().ToString(), (pi.GetValue(null, null)));
}
if (text != string.Empty && colortable[text] != null)
cl = (Color)colortable[text];
return cl;
}
#endregion
#region DefinitionHelper
public static Hashtable ColorDefinitions = null;
private static string[] SplittedText;
private static Color parsedcolor;
private static string parseddefinition;
public static bool CreateDefinitionColor(int line, string linetext)
{
if (ColorDefinitions == null)
ColorDefinitions = new Hashtable();
SplittedText = linetext.Split(' ');
if (SplittedText.Length ==3)
{
parsedcolor = ParseColor(SplittedText[1]);
if (parsedcolor != Colors.Transparent)
{
parseddefinition = linetext.Substring(linetext.IndexOf(SplittedText[2]));
parseddefinition =
parseddefinition.Substring(0, parseddefinition.LastIndexOf(';'));
ColorRegionAdornment cra = new ColorRegionAdornment()
{ Definition = parseddefinition, RegionColor = parsedcolor };
if (!ColorDefinitions.ContainsKey(line))
ColorDefinitions.Add(line, cra);
else
ColorDefinitions[line] = cra;
return true;
}
}
return false;
}
#endregion
}
public class TextAdornment1
{
IAdornmentLayer _layer;
IWpfTextView _view;
Brush _brush;
Geometry g;
public TextAdornment1(IWpfTextView view)
{
_view = view;
_layer = view.GetAdornmentLayer("TextAdornment1");
_view.LayoutChanged += OnLayoutChanged;
}
/// <summary>
/// On layout change add the adornment to any reformatted lines
/// </summary>
private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
{
CheckDefinitionColor();
if (MatchedRegions()) //regions are all created
{
CreateVisuals();
}
}
/// <summary>
/// We use the pattern //region color DEFINITION;
/// </summary>
private string LineText;
private string definecolorkeyword = "//region";
private int nline = 0;
private void CheckDefinitionColor()
{
nline = 0;
foreach (ITextViewLine line in _view.TextViewLines)
{
LineText = line.Extent.GetText();
int count = LineText.Length -
LineText.Replace(definecolorkeyword, "").Length;
if (LineText.Contains(definecolorkeyword) &&
LineText.EndsWith(";") && count==definecolorkeyword.Length)
{
ColorRegionAdornment.CreateDefinitionColor(++nline, LineText);
}
}
}
string Text = string.Empty;
string[] TextSplitted;
string startkeyword = "#region";
string endkeyword = "#endregion";
Color currentcolor;
private bool MatchedRegions()
{
int startregions = 0;
int endregions = 0;
foreach (ITextViewLine line in this._view.TextViewLines)
{
Text = line.Extent.GetText();
if (Text.Contains(startkeyword))
startregions++;
if (Text.Contains(endkeyword))
endregions++;
}
return (startregions>0 && startregions == endregions );
}
SnapshotPoint top, bottom;
SnapshotSpan span;
int regionstart = -1;
int regionend = -1;
private void CreateVisuals()
{
if (ColorRegionAdornment.ColorDefinitions == null)
return;
_layer.RemoveAdornmentsByTag("colorify");
foreach (ITextViewLine line in _view.TextViewLines)
{
Text = line.Extent.GetText();
regionstart = Text.IndexOf(startkeyword, 0); //First we look for the #region
if (regionstart > -1)
{
//We found #region, now we have to find the keyword of the region
TextSplitted = Text.Split(' ');
foreach (ColorRegionAdornment cra in ColorRegionAdornment.ColorDefinitions.Values)
{
if (Text.Contains(cra.Definition))
{
currentcolor = cra.RegionColor;
top = line.Extent.Start;
}
}
}
regionend = Text.IndexOf(endkeyword, 0);//We check now the #endregion
if (regionend > -1)
{
bottom = line.Extent.End;
if (top.Position != 0 &&
bottom.Position != 0 && top.Position < bottom.Position)
{
g = _view.TextViewLines.GetMarkerGeometry(span =
new SnapshotSpan(_view.TextSnapshot,
Span.FromBounds(top.Position, bottom.Position)));
if (g != null)
{
_brush = new SolidColorBrush(currentcolor);
GeometryDrawing drawing = new GeometryDrawing(_brush, null, g);
drawing.Freeze();
Rectangle r = new Rectangle() { Fill = _brush,
Width = drawing.Bounds.Width, Height = drawing.Bounds.Height };
Canvas.SetLeft(r, g.Bounds.Left);
Canvas.SetTop(r, g.Bounds.Top);
_layer.AddAdornment(AdornmentPositioningBehavior.TextRelative,
span, "colorify", r, null);
}
}
}
}
}
}
}
关注点
我认为这是一种有趣且易于自定义代码的好方法。现在,如果有人可以实现 #region
嵌套,那将是一个很棒的第二种方法。
我需要解决的一个问题是保持高亮文本。
待办事项
- 嵌套区域
- 为颜色选择添加自定义的智能感知
历史
- 第一次尝试:2012/5/8
- 第二次尝试:2012/5/13
- 改进颜色映射定义
- 保持高亮文本