C# Syntax Highlighter Class

A place to discuss development on the Microsoft .NET framework platform utilizing languages such as C#, Visual Basic, J# and Managed C++

Moderators: IRC Operators, Support Team

hixxy
User
User
Posts: 153
Joined: Tue Jan 15, 2008 11:31 am
Location: England

C# Syntax Highlighter Class

Postby hixxy » Thu Feb 17, 2011 11:27 pm

Code: Select all

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

   public class SyntaxHighlighter
    {
        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
        private const int WM_USER = 0x400;
        private const int EM_SETEVENTMASK = (WM_USER + 69);
        private const int WM_SETREDRAW = 0x0b;

        RichTextBox RTBControlToHighlight;
        public List<Rule> SyntaxRules = new List<Rule> { };
        private IntPtr OldEventMask;

        public SyntaxHighlighter(RichTextBox ControlToHighlight)
        {
            RTBControlToHighlight = ControlToHighlight;
        }
        private void Highlight(int Start, int End)
        {
            int CursorStartPosition = RTBControlToHighlight.SelectionStart,
                CursorStartLength = RTBControlToHighlight.SelectionLength;
            Font CursorFont = RTBControlToHighlight.SelectionFont;
            Color CursorForegroundColour = RTBControlToHighlight.SelectionColor,
                CursorBackgroundColour = RTBControlToHighlight.SelectionBackColor;
            foreach (Rule SyntaxRule in SyntaxRules)
            {
                foreach (Match SyntaxMatch in SyntaxRule.SyntaxRegexToMatch.Matches(RTBControlToHighlight.Text.Substring(Start, End - Start)))
                {
                    RTBControlToHighlight.Select(SyntaxMatch.Index, SyntaxMatch.Length);
                    RTBControlToHighlight.SelectionFont = SyntaxRule.SyntaxFont;
                    RTBControlToHighlight.SelectionColor = SyntaxRule.SyntaxForegroundColour;
                    RTBControlToHighlight.SelectionBackColor = SyntaxRule.SyntaxBackgroundColour;
                }
            }
            RTBControlToHighlight.Select(CursorStartPosition, CursorStartLength);
            RTBControlToHighlight.SelectionFont = CursorFont;
            RTBControlToHighlight.SelectionColor = CursorForegroundColour;
            RTBControlToHighlight.SelectionBackColor = CursorBackgroundColour;
        }

        public void BeginUpdate()
        {
            SendMessage(RTBControlToHighlight.Handle, WM_SETREDRAW, IntPtr.Zero, IntPtr.Zero);
            OldEventMask = (IntPtr)SendMessage(RTBControlToHighlight.Handle, EM_SETEVENTMASK, IntPtr.Zero, IntPtr.Zero);
        }
        public void EndUpdate()
        {
            SendMessage(RTBControlToHighlight.Handle, WM_SETREDRAW, (IntPtr)1, IntPtr.Zero);
            SendMessage(RTBControlToHighlight.Handle, EM_SETEVENTMASK, IntPtr.Zero, OldEventMask);
        }
        public void HighlightAll()
        {
            Highlight(0, RTBControlToHighlight.Text.Length);
        }
        public void HighlightLine(int LineToHighlight)
        {
            int LineStart = RTBControlToHighlight.GetFirstCharIndexFromLine(LineToHighlight),
                LineEnd = ((LineEnd = RTBControlToHighlight.GetFirstCharIndexFromLine(++LineToHighlight)) > -1 ? LineEnd - 1 : RTBControlToHighlight.Text.Length);
            if (LineStart < 0)
            {
                LineStart = 0;
            }
            Highlight(LineStart, LineEnd);
        }
        public void HighlightVisible()
        {
            int Start = RTBControlToHighlight.GetCharIndexFromPosition(new Point(0,0)),
                End = RTBControlToHighlight.GetCharIndexFromPosition(new Point(RTBControlToHighlight.ClientSize.Width,RTBControlToHighlight.ClientSize.Height));
            Highlight(Start, End);
        }

        public class Rule
        {
            public Rule(Regex RegexToMatch, Font Font, Color ForegroundColour, Color BackgroundColour)
            {
                SyntaxRegexToMatch = RegexToMatch;
                SyntaxFont = Font;
                SyntaxForegroundColour = ForegroundColour;
                SyntaxBackgroundColour = BackgroundColour;
            }

            public Regex SyntaxRegexToMatch;
            public Font SyntaxFont;
            public Color SyntaxForegroundColour;
            public Color SyntaxBackgroundColour;
        }
    }
}


Yes I use incredibly long variable names, I find that more descriptive names make the code much easier to edit when you have intellisense at your disposal :)

Here's how to use the code:

Code: Select all

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        SyntaxHighlighter MSLSyntaxHighlighter;

        private void richTextBox1_TextChanged(object sender, EventArgs e)
        {
            // You should always call BeginUpdate() before highlighting and EndUpdate() when you're finished. This prevents flickering while the control is being updated.
            MSLSyntaxHighlighter.BeginUpdate();
            // As well as HighlightVisible() there is also HighlightLine(line number) and HighlightAll(), which are self-explanatory. HighlightVisible() highlights only the text that is visible in the control at the time.
            MSLSyntaxHighlighter.HighlightVisible();
            MSLSyntaxHighlighter.EndUpdate();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // The SyntaxHighlighter class constructor takes one parameter: the richtextbox control to highlight.
            MSLSyntaxHighlighter = new SyntaxHighlighter(richTextBox1);
            string[] Keywords = new string[] { "alias", "if", "elseif", "else", "menu", "while", "dialog" };
            richTextBox1.Font = new Font("Consolas", 11);
            // Let's add a syntax highlighting rule.
            // The Rule class constructor takes four parameters: the regex to match, the font you wish to use to style the matched text, the foreground colour to style the matched text and the background colour to style the matched text.
            // Let's add a rule for keywords (if/elseif/while/etc).
            MSLSyntaxHighlighter.SyntaxRules.Add(
                new SyntaxHighlighter.Rule(
                    new Regex(@"(?<=^ *|\| *|\{ *)/*!?(?:" + string.Join("|", Keywords) + ")", RegexOptions.Multiline),
                    new Font("Consolas", 11,FontStyle.Bold),
                    Color.Black,
                    Color.White
                    )
                );
            // Let's add a rule for $identifiers.
            MSLSyntaxHighlighter.SyntaxRules.Add(
                new SyntaxHighlighter.Rule(
                    new Regex(@"(?<=[ ,(])\$[^(), \n]+", RegexOptions.Multiline),
                    new Font("Consolas", 11),
                    Color.Blue,
                    Color.White
                    )
                );
            // Let's add a rule for ; comments.
            MSLSyntaxHighlighter.SyntaxRules.Add(
                new SyntaxHighlighter.Rule(new Regex(@"^;.+?$", RegexOptions.Multiline),
                    new Font("Consolas", 11),
                    Color.DarkGreen,
                    Color.LightGray
                    )
                );
            // Let's add a rule for brackets.
            MSLSyntaxHighlighter.SyntaxRules.Add(
                new SyntaxHighlighter.Rule(
                    new Regex(@"[(){}\[\]<>]+", RegexOptions.Multiline),
                    new Font("Consolas", 11),
                    Color.Red,
                    Color.White
                    )
                );
            // Finally, let's add a rule for numbers.
            MSLSyntaxHighlighter.SyntaxRules.Add(
                new SyntaxHighlighter.Rule(
                    new Regex(@"-?(?>\d+)(?:\.(?>\d+))?", RegexOptions.Multiline),
                    new Font("Consolas", 11),
                    Color.Pink,
                    Color.White
                    )
                );
        }
    }


You should always call BeginUpdate() before highlighting and EndUpdate() after highlighting as it prevents flickering and makes the control update faster.

Return to “.NET”

Who is online

Users browsing this forum: No registered users and 1 guest