65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (3投票s)

2012 年 5 月 8 日

CPOL

1分钟阅读

viewsIcon

17728

使用 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 嵌套,那将是一个很棒的第二种方法。

我需要解决的一个问题是保持高亮文本。

待办事项

  1. 嵌套区域
  2. 为颜色选择添加自定义的智能感知

历史

  • 第一次尝试:2012/5/8
  • 第二次尝试:2012/5/13
    • 改进颜色映射定义
    • 保持高亮文本
© . All rights reserved.