Click here to Skip to main content
15,885,216 members
Articles / Regions
Tip/Trick

Colorify regions in VS Code Editor

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
13 May 2012CPOL1 min read 16.9K   5   2
Colorify regions using VS SDK

Introduction

Many times, you create plenty of regions inside a class, but when you search the different parts to analyze, you easily get lost. Of course, you can split it in different parts, but I prefer to colorify it a bit.

Image 1

Background

I have looked in many sites and am testing add-ins for VS 2010 but none could do what I wanted. So finally, I decided to make the first approach by myself.

Understand the Code

The idea is that you define in some place the color mapping <color,keyword> in a comment with the prefix region like the following:

C#
//region lightgreen Properties;
//region lightcyan Actions; 

Then, in any region you want to have that background color, include that keyword like in the introduction screenshot.

Using the Code

First of all, you have to install the VS 2010 SDK SP1. Then create a new project selecting Editor Text Adornment.

Image 2

In this case, I create a rectangle for the regions choosing a color from the Colors class. And here is my second approach:

C#
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);
                        }
                    }
                }
            }
        }
    }
}

Points of Interest

I think it is an interesting and easy way to customize the code well. Now if anyone can implement #region nesting, it will be a great second approach.

An issue I have to solve is to keep the highlighted text.

To Do

  1. Nesting regions
  2. Adding custom intellisense for color selection

History

  • First approach: 8/5/2012
  • Second approach: 13/05/2012:
    • Improved color mapping definition
    • Keeps the highlighted text

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Expediteapps
Spain Spain
I'm Electronic Engineer, I did my end degree project at Astrophysical Institute and Tech Institute. I'm HP Procurve AIS and ASE ,Microsoft 3.5 MCTS
I live in Canary Islands ,developing customized solutions

Deeply involved in Xamarin Forms LOB (including Azure Cloud with offline support, custom controls, dependencies) projects, WP8.1 & W10 projects, WPF modern styled projects. Portable libraries like portablePDF, portableOneDrive, portableReports and portablePrinting (using Google Printing API).


Web and apps showcase at:
Expediteapps


Take a look to my blog
Blog

Comments and Discussions

 
Questionfew things was missing Pin
Tridip Bhattacharjee8-May-12 20:36
professionalTridip Bhattacharjee8-May-12 20:36 
you come with nice article but you did not say what type of project need to create. u just gave the code which is not sufficient. do i need to create addins. after creating project then how feature will be imported into IDE. please discuss all the possible things closely. thanks
tbhattacharjee

AnswerRe: few things was missing Pin
Juan Pablo G.C.8-May-12 21:17
Juan Pablo G.C.8-May-12 21:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.