Syntax Highlighting in RichTextBox Control - Part 2

Introduction

This article shows how to perform interactive syntax highlighting within the RichTextBox control. The source code is written in C#.

This text builds upon the previous article Syntax Highlighting within the RichTextBox Control - Part 1 that described how to highlight text as it is loaded into the RichTextBox.

Description

To perform interactive syntax highlighting within the RichTextBox, the events generated by the control need to be monitored. In this example I monitor the event TextChanged which is triggered each time text is modified within the control. Further to make life easy apply formatting to the entire line that the user is editing. Note, this implementation has some drawbacks in terms of screen flicker. More about that later.

We begin by attaching an event handler to the RichTextBox property TextChanged like so.

  1. RichTextBox m_rtb = null;  
  2. m_rtb = new RichTextBox();  
  3. ...  
  4. m_rtb.TextChanged += new EventHandler(this.TextChangedEvent)   
Next I define the TextChanged() method to handle the event and perform interactive text highlighting to the entire line being edited by the user. The method begins by locating the start and end offset for the current line being edited. Next I extract this line of text from the RichTextBox so it can be processed. Before processing the line of text, I must save the RichTextBox properties SelectionStart and SelectionLength since it is these properties that are used to set the individual text highlighting positions. Next I split the line of text into tokens and analyze each token to see whether it is a keyword that requires special highlighting or not and then apply the font and color. Finally, I return the original values of the RichTextBox properties SelectionStart and SelectionLength.

Note, I have removed the highlighting code for comments to make the example more readable. See the attached file for a more complete example.

  1. private void TextChangedEvent(object sender, EventArgs e)  
  2. {  
  3.     // Calculate the starting position of the current line.  
  4.     int start = 0, end = 0;  
  5.     for (start = m_rtb.SelectionStart - 1; start > 0; start--)  
  6.     {  
  7.         if (m_rtb.Text[start] == '\n') { start++; break; }  
  8.     }  
  9.     // Calculate the end position of the current line.  
  10.     for (end = m_rtb.SelectionStart; end < m_rtb.Text.Length; end++)  
  11.     {  
  12.         if (m_rtb.Text[end] == '\n'break;  
  13.     }  
  14.     // Extract the current line that is being edited.  
  15.     String line = m_rtb.Text.Substring(start, end - start);  
  16.     // Backup the users current selection point.  
  17.     int selectionStart = m_rtb.SelectionStart;  
  18.     int selectionLength = m_rtb.SelectionLength;  
  19.     // Split the line into tokens.  
  20.     Regex r = new Regex("([ \\t{}();])");  
  21.     string[] tokens = r.Split(line);  
  22.     int index = start;  
  23.     foreach (string token in tokens)  
  24.     {  
  25.         // Set the token's default color and font.  
  26.         m_rtb.SelectionStart = index;  
  27.         m_rtb.SelectionLength = token.Length;  
  28.         m_rtb.SelectionColor = Color.Black;  
  29.         m_rtb.SelectionFont = new Font("Courier New", 10,  
  30.         FontStyle.Regular);  
  31.         // Check whether the token is a keyword.   
  32.         String[] keywords = { "public""void""using""static""class" };  
  33.         for (int i = 0; i < keywords.Length; i++)  
  34.         {  
  35.             if (keywords[i] == token)  
  36.             {  
  37.                 // Apply alternative color and font to highlight keyword.   
  38.                 m_rtb.SelectionColor = Color.Blue;  
  39.                 m_rtb.SelectionFont = new Font("Courier New", 10,  
  40.                 FontStyle.Bold);  
  41.                 break;  
  42.             }  
  43.   
  44.             index += token.Length;  
  45.         }  
  46.         // Restore the users current selection point.   
  47.         m_rtb.SelectionStart = selectionStart;  
  48.         m_rtb.SelectionLength = selectionLength;  
  49.     }  
  50. }  
Note, updating a whole line of text produces some noticeable flicker on the line of text being entered by the user. A more thorough implementation of highlighting might use a data structure to store the formatting properties of all text characters within the control so that only necessary updates are performed in the control. Moreover, the KeyPressed event could be utilized to handle the insertion of individual characters into the control.

Conclusion

This article described a rudimentary example of how to perform syntax highlighting interactively within the RichTextBox control. A more thorough implementation is left to the reader.