VB.NET: RegEx Syntax Highlighting RichTextBox

3. July 2006

RegEx Syntax HighlighterHere is a version of my code for syntax highlighting in a RichTextBox that incorporates regular expressions.

 

Download RegEx Syntax Highlighting RichTextBox Source Code

Source Code Listed:

Public Class SyntaxRTB

Inherits System.Windows.Forms.RichTextBox

Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _ (ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, _

ByVal lParam As Integer) As Integer

Private Declare Function LockWindowUpdate Lib "user32" _

(ByVal hWnd As Integer) As Integer

Private _SyntaxHighlight_CaseSensitive As Boolean = False

Friend Words As New DataTable

'Contains Windows Messages for the SendMessage API call

Private Enum EditMessages

LineIndex = 187

LineFromChar = 201

GetFirstVisibleLine = 206

CharFromPos = 215

PosFromChar = 1062

End Enum

Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)MyBase.OnTextChanged(e)

ColorVisibleLines()

End Sub

Public Sub New()

Me.AcceptsTab = True

AddSQLSyntax()

End Sub

Function AddSQLSyntax()

ClearSyntaxWords()

AddSyntaxWord(
"\b(select|text|ntext|date|datetime|order by|" & _

"group by|smalldatetime|cursor|on|as|for|filename|" & _

"database|drop|function|delete|insert|update|int|" & _

"varchar|nvarchar|bit|binary|table|inner|where|from|" & _

"out|procedure|view|trigger|set)\b", Color.Blue)

AddSyntaxWord("\b@@identity\b", Color.Pink)AddSyntaxWord(

"\b(in|join|outer|and|or)\b", Color.Gray) AddSyntaxWord("\bsp_refreshview\b", Color.Red)

Return True

End Function

Public Function ClearSyntaxWords() Words = New DataTable

''Load all the keywords and the colors to make them

Words.Columns.Add("Word")

Words.PrimaryKey = New DataColumn() {Words.Columns(0)}Words.Columns.Add(

"Color")

Return True

End Function

Public Function AddSyntaxWord(ByVal strWord As String, ByVal clrColor As Color)Dim MyRow As DataRow

MyRow = Words.NewRow()

MyRow("Word") = strWordMyRow(

"Color") = clrColor.Name

Words.Rows.Add(MyRow)

Return True

End Function

Public Sub ColorRtb()

Dim FirstVisibleChar As Integer

Dim i As Integer = 0While i < Me.Lines.Length

FirstVisibleChar = GetCharFromLineIndex(i)

ColorLineNumber(i, FirstVisibleChar)

i += 1

End While

End Sub

Public Sub ColorVisibleLines()

Dim FirstLine As Integer = FirstVisibleLine()

Dim LastLine As Integer = LastVisibleLine()

Dim FirstVisibleChar As Integer

If (FirstLine = 0) And (LastLine = 0) Then

'If there is no text it will error, so exit the sub

Exit Sub

Else

While FirstLine < LastLine

FirstVisibleChar = GetCharFromLineIndex(FirstLine)

ColorLineNumber(FirstLine, FirstVisibleChar)

FirstLine += 1

End While

End If

End Sub

Public Sub ColorLineNumber(ByVal LineIndex As Integer, ByVal lStart As Integer)

Dim i As Integer = 0

Dim SelectionAt As Integer = Me.SelectionStart Dim MyRow As DataRow

Dim MyI As Integer

' Lock the update

LockWindowUpdate(Me.Handle.ToInt32)

MyI = lStart

''Turn the whole link black before applying RegEx Syntax matching.

Me.SelectionStart = MyI

Me.SelectionLength = Lines(LineIndex).Length

Me.SelectionColor = Color.Black

''Check for matches in a particular line number

Dim rm As System.Text.RegularExpressions.MatchCollection

Dim m As System.Text.RegularExpressions.Match

For Each MyRow In Words.Rows

'"( |^)1.*2( |$)"

rm = System.Text.RegularExpressions.Regex.Matches(Me.Text, MyRow("Word"))

For Each m In rm

Me.SelectionStart = m.Index

Me.SelectionLength = m.Length

Me.SelectionColor = Color.FromName(MyRow("color"))

Next

Next

' Restore the selectionstart

Me.SelectionStart = SelectionAt

Me.SelectionLength = 0

Me.SelectionColor = Color.Black

' Unlock the update

LockWindowUpdate(0)

End Sub

Public Function GetCharFromLineIndex(ByVal LineIndex As Integer) As Integer

Return SendMessage(Me.Handle, EditMessages.LineIndex, LineIndex, 0)

End Function

Public Function FirstVisibleLine() As Integer

Return SendMessage(Me.Handle, EditMessages.GetFirstVisibleLine, 0, 0)

End Function

Public Function LastVisibleLine() As Integer

Dim LastLine As Integer = FirstVisibleLine() + (Me.Height / Me.Font.Height)

If LastLine > Me.Lines.Length Or LastLine = 0 Then

LastLine = Me.Lines.Length

End If

Return LastLine

End Function

Public Property CaseSensitive() As Boolean

Get

Return _SyntaxHighlight_CaseSensitive

End Get

Set(ByVal Value As Boolean)

_SyntaxHighlight_CaseSensitive = Value

End Set

End Property

End Class

vb.net

Comments

Matanel Sindilevich
Matanel Sindilevich
7/24/2006 2:13:00 AM #
Hi! I would like to know why you add '\b' to the start and end of every Syntax Word, used then as a pattern for Regular Expression Matches? I don't know how it goes in VB.NET, but C# won't work well with "\\b@@identity\\b" (C# equialence of VB.NET "\b@@identity\b") Syntax Word. Means, C# won't find any match unless you specify just "@@identity", without '\\b'. If so. why do you need to add '\b' at all? Thank you in advance for your reply.
7/26/2006 12:07:00 PM #
I am by no means an expert with RegEx. At the moment I don’t remember my reasoning for doing what I did, but do know for a simple example it just works. If you have a better suggestion, feel free to post it.
TC Conway
TC Conway
8/20/2006 11:08:00 PM #
This looks like great code, but have a sec to help a Noob out? Ok. So you just paste this into Form1.vb, after the "Public Class Form1" class? Any guidance on adding this to an existing project would be extremely helpful!
nilam
nilam
9/25/2006 8:23:00 PM #
code is nice but not flicker free
how to make it flicker free
tom
tom
12/8/2006 1:25:00 PM #
Nice one, but in c# vs2005 something goes wrong with calculating         public int FirstVisibleLine()
        {
            return SendMessageA(this.Handle, (int) RichTextMessages.GetFirstVisibleLine, 0, 0);
        }

        public int LastVisibleLine()
        {
            int LastVisibleLine = FirstVisibleLine() + (this.Height / this.Font.Height);
            if (LastVisibleLine > this.Lines.Length || LastVisibleLine == 0)
                LastVisibleLine = FirstVisibleLine();
            return LastVisibleLine;
        }

after inserting one, very long line
Larry
Larry
12/9/2006 8:06:00 AM #
  The \b tell the regular expression engine that the entire word must be found in order to match.

example: With expression \bWordToFind\b

this would match
  here is a WordToFind in a string

this would not match
  here is aWordToFind in a string
Boirss
Boirss
2/13/2007 7:47:00 AM #
Very nice code. Especially like the API call.
However, the performance of the text box becomes extremely slow as the line numbers and line lenghts grow.
Randy
Randy
4/13/2007 11:48:00 PM #
Thank you so much, works great for my application.