65.9K
CodeProject is changing. Read more.
Home

Real Time SynTax Colorizing

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.22/5 (21 votes)

Apr 26, 2004

2 min read

viewsIcon

95891

downloadIcon

630

Aaron shows how to use the RichTextbox for Real Time Syntax Coloring painlessly.

Sample Image - syntaxcolorizing.jpg

Introduction

There seems to be three ways to do real time syntax coloring. Good, fast, and flicker-free. Pick any two. Matthew Hazlett did an article that covers "good and flicker-free", so I thought some people might find it useful to have simply "good and fast".

Background

Back in January, I worked on HTML syntax coloring. I was amazed by the lack of information on the subject in VB.NET. There was some in VB, but naturally, it didn't upgrade too well (nothing is ever easy). So, I had to make my own. Isn't that how things typically are? I've learned a lot from CodeProject, and would like to give back.

Using the code

The code is pretty much self-explanatory, but the idea behind it works something like this:

  1. Find the number of visible lines.
  2. For each visible line, color it.

Simple enough, eh?

Now, on to the actual code, the first subroutine that finds the number of visible lines is called ColorVisibleLines and it looks something like this:

    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ' Sub: ColorVisibleLines()
    ' It does what?: Colors the visible lines in the RichTextbox
    ' Notes: N/A
    Public Sub ColorVisibleLines(ByVal rtb As RichTextBox)
        Dim FirstLine As Integer = FirstVisibleLine()
        Dim LastLine As Integer = LastVisibleLine()
        Dim FirstVisibleChar As Integer
        Dim i As Integer = FirstLine

        If (FirstLine = 0) And (LastLine = 0) Then
            ' If there is no text in the control, it will run an error
            ' So, if there isn't any text, just exit
            Exit Sub
        Else
            While i < LastLine

                FirstVisibleChar = GetCharFromLineIndex(FirstLine)

                ColorLineNumber(rtb, FirstLine, FirstVisibleChar)

                FirstLine += 1
                i += 1
            End While
        End If
    End Sub

As you will notice, this sub calls another sub to do all the actual coloring for us.

    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ' Sub: ColorLineNumber()
    ' It does what?: Colors a single line in the control
    ' Notes: This should be fairly simple, it looks to see
    '  if there are any comments, colors them. Then, it loops
    '  through the keywords defined, and colors them
    Public Sub ColorLineNumber(ByVal rtb As RichTextBox, _
            ByVal LineIndex As Integer, ByVal lStart As Integer)
        Dim Line As String = rtb.Lines(LineIndex).ToLower
        Dim i As Integer = 0
        Dim Instance As Integer
        Dim SelectionAt As Integer = rtb.SelectionStart

        ' Lock the update
        LockWindowUpdate(rtb.Handle.ToInt32)

        ' Color the line black to remove any previous coloring
        rtb.SelectionStart = lStart
        rtb.SelectionLength = Line.Length
        rtb.SelectionColor = Color.Black

        ' Find any comments
        Instance = InStr(Line, "'")

        ' If there are comments, color them
        If Instance <> 0 Then
            rtb.SelectionStart = (lStart + Instance - 1)
            rtb.SelectionLength = (Line.Length - Instance + 1)
            rtb.SelectionColor = Color.Green
        End If

        ' There was a comment, so to aviod coloring over the comment
        '  we exit. Unfortunately, this can present a problem 'cuz
        '  what if the user comments at the end of a line with code on it.
        If Instance = 1 Then
            ' Unlock the update, restore the start and exit
            rtb.SelectionStart = SelectionAt
            rtb.SelectionLength = 0
            LockWindowUpdate(0)
            Exit Sub
        End If

        ' Loop through all the Keywords
        While i < Words.Length

            ' See if the word is in the Line
            Instance = InStr(Line, Words(i).Word)

            ' If the lines contains the word, color it
            If Instance <> 0 Then
                rtb.SelectionStart = (lStart + Instance - 1)
                rtb.SelectionLength = Words(i).Word.Length
                rtb.SelectionColor = Words(i).Color
            End If

            i += 1
        End While

        ' Restore the selectionstart
        rtb.SelectionStart = SelectionAt
        rtb.SelectionLength = 0

        ' Unlock the update
        LockWindowUpdate(0)
    End Sub

The keywords to be colored are stored in a structure called KeyWords which holds the string to color, and the color to color the string.

Closing

All in all, it's not the most efficient way to color things. For example, you may have noticed that the Instr function is used to locate the keywords. Regular Expressions (or RegEx) could be used in lieu of the method currently implemented.

Another downside to this method is flicker. This is a very difficult issue to overcome. Even with the LockWindowUpdate API function, it still flickers (go figure). I am currently attempting to make a non-inherited RichTextBox that will be a clone of Visual Studio's editor. However, it's still a long distance from completion. The control will be free and I'll post it on CodeProject, and it will contain a lot of features such as line numbering, breakpoints, brace-matching, expanding-collapsing regions, and best of all good, fast, and flicker-free real time syntax coloring.