Creating Code Completion In C#

In this article we will create a code completion window using C# that automatically pops up the list of syntax or keywords and inserts those keywords into a RichTextBox and removes that list once the action is completed.

  

   

   
 
Introduction 
 
In this article we will create a Code Completion window in C#.

Intelligent code completion is a context-aware code completion feature in some programming environments that speeds up the process of coding applications by reducing typos and other common mistakes. Attempts to do this are usually done through auto completion popups when typing, querying parameters of functions, query hints related to syntax errors, etc. Intelligent code completion and related tools serve as documentation and disambiguation for variable names, functions and methods using reflection.

Intelligent code completion appears in many program environments, an example implementation being Visual Studio's IntelliSense. The term was originally popularized as "picklist" and some implementations still refer to it as such.

So how hard it is to build a code completion in C#?

I searched on the internet, I found no code instead of developed editors.

I knew that it is the list that can be shown while typing the code, but how to display that list onto the RichTextBox?

Before working on this code I thought it is so difficult to develop this, it needs so much professionalism, but I was wrong, it depends on your idea.

How is it so easy?

Just create a ListBox object and add it to RichTextBox and get selected item from list box and insert it to the RichTextBox and then remove that ListBox.

You just need to Add or Remove items from list box.

You can customize your code completion window (ListBox) on your own (as shown in above image 3).

We will also complete the brackets automatically further (see AutoCompleteBrackets function)

In this article we will create simple code completion in C#. Download the code to see the code completion using XML.

It is nothing but the adding or removing ListBox.
 
See next algorithm for better understanding.
 
For understanding, read all comments carefully in the code (CCRichTextBox).

Algorithm 
  1. Create the ListBox object.(I am using CodeCompleteBox object name).
  2. Read X-Y coordinates from RichTextBox.
  3. Declare the Boolean variable to identify whether the CodeCompleteBox is added or not.(I am using isCodeCompleteBoxAdded variable) & String variable to identify the complete string(i am using EnteredKey variable).
  4. Declare array list of keywords.(I am using keywordslist).
  5. Add following events to RichTextBox
(i) Key Press:
  1. Identify pressed key is alphabet or not.
  2. Remove all items from CodeCompleteBox.
  3. Read each item from keywordslist.
  4. If each item from keywordslist is starts with pressed key character then add that item into the CodeCompleteBox.
  5. Read each item from keywordslist.
  6. If each item from keywordslist is starts with pressed key then set that item to selected.
  7. Set Default cursor to CodeCompleteBox.
  8. Set Size to CodeCompleteBox.
  9. Set Location to CodeCompleteBox by reading (x,y) coordinates from Step-2.
  10. Add CodeCompleteBox to RichTextBox.
  11. Set isCodeCompleteBoxAdded to true.
(ii) Text Changed: 

If RichTextBox Text is null then remove CodeCompleteBox from RichTextBox.Before removing first check if isCodeCompleteBoxAdded is true.

(iii) Key Down:
  1. Check if Space,Enter,Escape & Back key is down then go to next;
  2. If isCodeCompleteBoxAdded is true then remove CodeCompleteBox from RichTextBox.
(iv) Mouse Click:

If isCodeCompleteBoxAdded is true then remove CodeCompleteBox from RichTextBox.

(v) VScroll:

If isCodeCompleteBoxAdded is true then remove CodeCompleteBox from RichTextBox.
 
6: Add the following events to CodeCompleteBox,

(i) Key Down:
  1. Check if isCodeCompleteBoxAdded is true then go to next.
  2. If Enter or Space key is down then go to next.
  3. Read Selected item from CodeCompleteBox and insert that item in RichTextBox at SelectionStart position.
  4. Remove CodeCompleteBox from RichTextBox.
(ii) Key Press:

It is used to insert a pressed character into RichTextBox and also select item in CodeCompleteBox.

(iii) Mouse Click: Same as above Key Down event Step-3.

7:  Stop

Tool Tip:

Here, to display a tooltip or to display information about selected item of CodeCompleteBox we will use label to display information and will add this label to a Panel and this panel will be added to RichTextBox at specific location or next location to CodeCompleteBox. In this article we will not create a tooltip but download the source it contain the whole code with tooltips. All operations are same as CodeCompleteBox only adding Key Up event to CodeCompleteBox.

Coding:


I am creating a class CCRichTextBox with super class RichTextBox.

Firstly, lets see some important functions.

I used a function ProcessCodeCompletionAction(String key) to call whenever the key press event is generated in the program. I am reading the getWidth() & getHeight() function to set Width & Height to CodeCompleteBox but you can set them as default. Concat the pressed character with EnteredKey, perform all steps defined in Key Press in above algorithm.

Here we will not see adding of tooltip to CodeCompleteBox, so if you get errors then remove all components of tooltips.
  1. public void ProcessCodeCompletionAction(String key)  
  2. {  
  3.     EnteredKey = "";  
  4.   
  5.     // concat the key & EnteredKey postfix  
  6.     EnteredKey = EnteredKey + key;  
  7.   
  8.     char ch;  
  9.   
  10.     //check pressed key on CCRichTextBox is lower case alphabet or not  
  11.     for (ch = 'a'; ch <= 'z'; ch++)  
  12.     {  
  13.         if (key == ch.ToString())  
  14.         {  
  15.             // Clear the CodeCompleteBox Items   
  16.             CodeCompleteBox.Items.Clear();  
  17.             //add each item to CodeCompleteBox  
  18.             foreach (String item in keywordslist)  
  19.             {  
  20.                 //check item is starts with EnteredKey or not  
  21.                 if (item.StartsWith(EnteredKey))  
  22.                 {  
  23.                     CodeCompleteBox.Items.Add(item);  
  24.                 }  
  25.             }  
  26.   
  27.               
  28.             //  read each item from CodeCompleteBox to set SelectedItem  
  29.             foreach (String item in keywordslist)  
  30.             {  
  31.                 if (item.StartsWith(EnteredKey))  
  32.                 {  
  33.                     CodeCompleteBox.SelectedItem = item;  
  34.   
  35.                     //  set Default cursor to CodeCompleteBox  
  36.                     CodeCompleteBox.Cursor = Cursors.Default;  
  37.   
  38.                     //  set Size to CodeCompleteBox  
  39.                     // width=this.getWidth() & height=this.getHeight()+(int)this.Font.Size  
  40.                     CodeCompleteBox.Size = new System.Drawing.Size(this.getWidth(), this.getHeight() + (int)this.Font.Size);  
  41.   
  42.                     //  set Location to CodeCompleteBox by calling getXYPoints() function  
  43.                     CodeCompleteBox.Location = this.getXYPoints();  
  44.   
  45.                     //  adding controls of CodeCompleteBox to CCRichTextBox  
  46.                     this.Controls.Add(CodeCompleteBox);  
  47.   
  48.                     //  set Focus to CodeCompleteBox  
  49.                     CodeCompleteBox.Focus();  
  50.   
  51.                     //  set isCodeCompleteBoxAdded to true  
  52.                     isCodeCompleteBoxAdded = true;  
  53.   
  54.                     break;  
  55.                 }  
  56.   
  57.                 else  
  58.                 {  
  59.                     isCodeCompleteBoxAdded = false;  
  60.                 }  
  61.             }  
  62.         }  
  63.   
  64.         // check pressed key character is upper case letter or not  
  65.         else if (key == ch.ToString().ToUpper())  
  66.         {  
  67.             // Clear the CodeCompleteBox Items   
  68.             CodeCompleteBox.Items.Clear();  
  69.             //add each item to CodeCompleteBox  
  70.             foreach (String item in keywordslist)  
  71.             {  
  72.                 //check item is starts with EnteredKey or not  
  73.                 if (item.StartsWith(EnteredKey))  
  74.                 {  
  75.                     CodeCompleteBox.Items.Add(item);  
  76.                 }  
  77.             }  
  78.   
  79.   
  80.             //  read each item from CodeCompleteBox to set SelectedItem  
  81.             foreach (String item in keywordslist)  
  82.             {  
  83.                 if (item.StartsWith(EnteredKey))  
  84.                 {  
  85.                     CodeCompleteBox.SelectedItem = item;  
  86.   
  87.                     //  set Default cursor to CodeCompleteBox  
  88.                     CodeCompleteBox.Cursor = Cursors.Default;  
  89.   
  90.                     //  set Size to CodeCompleteBox  
  91.                     // width=this.getWidth() & height=this.getHeight()+(int)this.Font.Size  
  92.                     CodeCompleteBox.Size = new System.Drawing.Size(this.getWidth(), this.getHeight() + (int)this.Font.Size);  
  93.   
  94.                     //  set Location to CodeCompleteBox by calling getXYPoints() function  
  95.                     CodeCompleteBox.Location = this.getXYPoints();  
  96.   
  97.                     //  adding controls of CodeCompleteBox to CCRichTextBox  
  98.                     this.Controls.Add(CodeCompleteBox);  
  99.   
  100.                     //  set Focus to CodeCompleteBox  
  101.                     CodeCompleteBox.Focus();  
  102.   
  103.                     //  set isCodeCompleteBoxAdded to true  
  104.                     isCodeCompleteBoxAdded = true;  
  105.   
  106.                     break;  
  107.                 }  
  108.   
  109.                 else  
  110.                 {  
  111.                     isCodeCompleteBoxAdded = false;  
  112.                 }  
  113.             }  
  114.         }  
  115.     }  
  116. }  
Okay, let's perform all steps according to above algorithm.

1.
 Create ListBox Object,
  1. public ListBox CodeCompleteBox = new ListBox();  
2. Read X-Y coordinates from RichTextBox.

This function returns the (x,y) coordinates by adding or reducing the size of font of RichTextBox. See the following image that shows the x-y position up side down CodeCompleteBox.

   
  1.         public Point getXYPoints()  
  2.         {  
  3.             //get current caret position point from CCRichTextBox  
  4.             Point pt = this.GetPositionFromCharIndex(this.SelectionStart);  
  5.             // increase the Y co-ordinate size by 10 & Font size of CCRichTextBox  
  6.             pt.Y = pt.Y + (int)this.Font.Size + 10;  
  7.   
  8.             //  check Y co-ordinate value is greater than CCRichTextBox Height - CodeCompleteBox  
  9.             //   for add CodeCompleteBox at the Bottom of CCRichTextBox  
  10.             if (pt.Y > this.Height - CodeCompleteBox.Height)  
  11.             {  
  12.                 pt.Y = pt.Y - CodeCompleteBox.Height - (int)this.Font.Size - 10;  
  13.             }  
  14.   
  15.             return pt;  
  16.         }  
3. Declare the Boolean variable to identify whether the CodeCompleteBox is added or not,
  1. public static Boolean isCodeCompleteBoxAdded = false;  
String variable to identify the complete string,
  1. public static String EnteredKey = "";  
4. Declare array list of keywords. Here you can predefine the list in the program or can read the keywords using XML file. Download the source code, i have used both Array list & <List> of string. Here lets declare the array of list.
  1. public String[] keywordslist = {  
  2. "bool",   
  3. "break",   
  4. "case",   
  5. "catch",   
  6. "char",   
  7. "class",   
  8. "const",   
  9. "continue",   
  10. "default",   
  11. "do",   
  12. "double",  
  13. "else",   
  14. "enum",    
  15. "false",   
  16. "float",   
  17. "for",   
  18. "goto",   
  19. "if",    
  20. "int"  
  21.         };   
5. Add Key Press ,Text Changed, Key Down, Mouse Click, VScroll events to CCRichTextBox.

Key Press Event:

Here we will directly call the ProcessCodeCompletionAction() function. But here we can perform some more actions like creating classes or datatypes. I have declared two extra variables Boolean isClassCreated = false; & Boolean isDataTypeDeclared = false; for identify that the inserted item from CodeCompleteBox is class/datatype or not.For that you need to declare the list of classes & datatypes.

E.g: Once you select the item from CodeCompleteBox then CodeCompleteBox will not appear until you will press =,;, because to create object of Form you can define it in two ways:

Form frm; or Form frm=new Form();

Download the source code, once you drag & drop the CCRichTextBox to your form, in Properties you can enter the list of keywords/classes/datatypes.
  1.  protected override void OnKeyPress(KeyPressEventArgs e)  
  2.   {  
  3.       base.OnKeyPress(e);  
  4.   
  5.       ProcessAutoCompleteBrackets(e);  
  6.       String key = e.KeyChar.ToString();  
  7.       if (isClassCreated && (key == "=" || key == ";"))  
  8.       {  
  9.   
  10.           ProcessCodeCompletionAction(key);  
  11.   
  12.           isClassCreated = false;  
  13.       }  
  14.       else if (isClassCreated && key != "=")  
  15.       { }  
  16.       else if (isDataTypeDeclared && (key == ";" || key == "{"||key=="}" || key == "(" || key == ")"))  
  17.       {  
  18.   
  19.           ProcessCodeCompletionAction(key);  
  20.           isDataTypeDeclared = false;  
  21.       }  
  22.       else if (isDataTypeDeclared && key != ";")  
  23.       { }  
  24.       else  
  25.       {  
  26.           ProcessCodeCompletionAction(key);  
  27.       }  
  28.   }  
Text Changed Event: Remove CodeCompleteBox from CCRichTextBox if it's text is null.
  1. protected override void OnTextChanged(EventArgs e)  
  2. {  
  3.     base.OnTextChanged(e);  
  4.     if (this.Text == "")  
  5.     {  
  6.         if (isCodeCompleteBoxAdded)  
  7.         {  
  8.             this.Controls.Remove(CodeCompleteBox);  
  9.             EnteredKey = "";  
  10.         }  
  11.     }  
  12. }   
Key Down Event:

Check if Space, Enter, Escape & Back key is down then remove CodeCompleteBox from CCRichTextBox. Here I have shown only about Space key, add other keys yourself.
  1. protected override void OnKeyDown(KeyEventArgs e)  
  2. {  
  3.      base.OnKeyDown(e);  
  4.     
  5.   switch(e.KeyCode)  
  6.   {  
  7.     case Keys.Space:  
  8.                           if (isCodeCompleteBoxAdded)  
  9.                           {  
  10.                             this.Controls.Remove(CodeCompleteBox);  
  11.                             EnteredKey = "";  
  12.                           }  
  13.                           break;  
  14.   }  
  15. }  
Mouse Click Event: If isCodeCompleteBoxAdded is true then remove CodeCompleteBox from CCRichTextBox same as defined above.
 
VScroll Event: Code is same as above for Mouse Click.
 
6. Add Key Down, Key Press & Mouse Click Events to CodeCompleteBox.
  1.  public CCRichTextBox()  
  2. {  
  3.     CodeCompleteBox.KeyDown += new KeyEventHandler(CodeCompleteBox_KeyDown);  
  4.     CodeCompleteBox.KeyUp += new KeyEventHandler(CodeCompleteBox_KeyUp);  
  5.     CodeCompleteBox.KeyPress += new KeyPressEventHandler(CodeCompleteBox_KeyPress);  
  6.     CodeCompleteBox.MouseClick += new MouseEventHandler(CodeCompleteBox_MouseClick);  
  7. }  
Key Down:

First identify that the down key is Enter/Space or not. Then identify that the CodeCompleteBox is added to CCRichTextBox or not then identify that the selected item from CodeCompleteBox starts with EnteredKey or not then read selected item from CodeCompleteBox. Read the length of EnteredKey, as per the length replace the first  characters from selected item from CodeCompleteBox. Now insert that selected item into CCRichTextBox at SelectionStart position and then remove CodeCompleteBox from CCRichTextBox. If down key is Space then insert a single space next to the item. If down key is Left/Right then remove CodeCompleteBox from CCRichTextBox.

Here's the code for key Enter.
  1. private void CodeCompleteBox_KeyDown(object sender, KeyEventArgs e)  
  2. {  
  3.     switch (e.KeyCode)  
  4.     {  
  5.         case Keys.Enter:  
  6.             if (isCodeCompleteBoxAdded)  
  7.             {  
  8.                 if (EnteredKey != "")  
  9.                 {  
  10.                     if (EnteredKey.Length == 1)  
  11.                     {  
  12.                         int sel = this.SelectionStart;  
  13.                         String text = CodeCompleteBox.SelectedItem.ToString();  
  14.                         text = text.Remove(0, 1);  
  15.                         this.Text = this.Text.Insert(sel, text);  
  16.                         this.SelectionStart = sel + text.Length;  
  17.                         this.Controls.Remove(CodeCompleteBox);  
  18.   
  19.                         this.ProcessDeclaredClasses(CodeCompleteBox.SelectedItem.ToString());  
  20.                         this.ProcessDeclaredDataTypes(CodeCompleteBox.SelectedItem.ToString());  
  21.   
  22.                     }  
  23.                     else if (EnteredKey.Length == 2)  
  24.                     {  
  25.                         int sel = this.SelectionStart;  
  26.                         String text = CodeCompleteBox.SelectedItem.ToString();  
  27.                         text = text.Remove(0, 2);  
  28.                         this.Text = this.Text.Insert(sel, text);  
  29.                         this.SelectionStart = sel + text.Length;  
  30.                         this.Controls.Remove(CodeCompleteBox);  
  31.   
  32.                         this.ProcessDeclaredClasses(CodeCompleteBox.SelectedItem.ToString());  
  33.                         this.ProcessDeclaredDataTypes(CodeCompleteBox.SelectedItem.ToString());  
  34.   
  35.                     }  
  36.                     else if (EnteredKey.Length == 3)  
  37.                     {  
  38.                         int sel = this.SelectionStart;  
  39.                         String text = CodeCompleteBox.SelectedItem.ToString();  
  40.                         text = text.Remove(0, 3);  
  41.                         this.Text = this.Text.Insert(sel, text);  
  42.                         this.SelectionStart = sel + text.Length;  
  43.                         this.Controls.Remove(CodeCompleteBox);  
  44.   
  45.                         this.ProcessDeclaredClasses(CodeCompleteBox.SelectedItem.ToString());  
  46.                         this.ProcessDeclaredDataTypes(CodeCompleteBox.SelectedItem.ToString());  
  47.   
  48.                     }  
  49.                     else  
  50.                     {  
  51.                         int sel = this.SelectionStart;  
  52.                         String text = CodeCompleteBox.SelectedItem.ToString();  
  53.                         if (text.Contains(EnteredKey))  
  54.                         {  
  55.                             text = text.Replace(EnteredKey, "");  
  56.                         }  
  57.                         this.Text = this.Text.Insert(sel, text);  
  58.                         this.SelectionStart = sel + text.Length;  
  59.                         this.Controls.Remove(CodeCompleteBox);  
  60.   
  61.                         this.ProcessDeclaredClasses(CodeCompleteBox.SelectedItem.ToString());  
  62.                         this.ProcessDeclaredDataTypes(CodeCompleteBox.SelectedItem.ToString());  
  63.   
  64.                     }  
  65.                 }  
  66.             }  
  67.             break;  
  68.   
  69.         // if Left key is down then remove CodeCompleteBox from this  
  70.         case Keys.Left:  
  71.             if (isCodeCompleteBoxAdded)  
  72.             {  
  73.                 this.Controls.Remove(CodeCompleteBox);  
  74.                 EnteredKey = "";  
  75.             }  
  76.             break;  
  77.   
  78.         // if Right key is down then remove CodeCompleteBox from this  
  79.         case Keys.Right:  
  80.             if (isCodeCompleteBoxAdded)  
  81.             {  
  82.                 this.Controls.Remove(CodeCompleteBox);  
  83.                 EnteredKey = "";  
  84.   
  85.             }  
  86.             break;  
  87.     }  
  88. }  
Key Press Event:

This event is used to select the item that starts with EnteredKey after concatenation to it, then read all items from CodeCompleteBox and that item which starts with EnteredKey then set it to selected and also identify that the special character is pressed or not. If it is  pressed then remove CodeCompleteBox from CCRichTextBox.
  1. private void CodeCompleteBox_KeyPress(object sender, KeyPressEventArgs e)  
  2.       {  
  3.           String str = e.KeyChar.ToString();  
  4.   
  5.           // in this event we must insert pressed key to this because Focus is on CodeCompleteBox  
  6.   
  7.           // first check pressed key is not Space,Enter,Escape & Back  
  8.           // Space=32, Enter=13, Escape=27, Back=8  
  9.           if (Convert.ToInt32(e.KeyChar) != 13 && Convert.ToInt32(e.KeyChar) != 32 && Convert.ToInt32(e.KeyChar) != 27 && Convert.ToInt32(e.KeyChar) != 8)  
  10.           {  
  11.               if (isCodeCompleteBoxAdded)  
  12.               {  
  13.                   // insert pressed key to CCRichTextBox at SelectionStart position  
  14.                   int sel = this.SelectionStart;  
  15.                   this.Text = this.Text.Insert(sel, str);  
  16.                   this.SelectionStart = sel + 1;  
  17.                   e.Handled = true;  
  18.   
  19.                   // concat the EnteredKey and pressed key on CodeCompleteBox  
  20.                   EnteredKey = EnteredKey + str;  
  21.   
  22.                   // search item in CodeCompleteBox which starts with EnteredKey and set it to selected  
  23.                   foreach (String item in CodeCompleteBox.Items)  
  24.                   {  
  25.                       if (item.StartsWith(EnteredKey))  
  26.                       {  
  27.                           CodeCompleteBox.SelectedItem = item;  
  28.                           break;  
  29.                       }  
  30.                   }  
  31.               }  
  32.           }  
  33.   
  34.           // if pressed key is Back then set focus to CCRichTextBox  
  35.           else if (Convert.ToInt32(e.KeyChar) == 8)  
  36.           {  
  37.               this.Focus();  
  38.           }  
  39.   
  40.             // if pressed key is not Back then remove CodeCompleteBox from CCRichTextBox  
  41.           else if (Convert.ToInt32(e.KeyChar) != 8)  
  42.           {  
  43.               if (isCodeCompleteBoxAdded)  
  44.               {  
  45.                   this.Controls.Remove(CodeCompleteBox);  
  46.                   EnteredKey = "";  
  47.               }  
  48.           }  
  49.   
  50.   
  51.   
  52.           //  check pressed key on CodeCompleteBox is special character or not  
  53.           //   if it is a special character then remove CodeCompleteBox from CCRichTextBox  
  54.           switch (str)  
  55.           {  
  56.               case "~":  
  57.               case "`":  
  58.               case "!":  
  59.               case "@":  
  60.               case "#":  
  61.               case "$":  
  62.               case "%":  
  63.               case "^":  
  64.               case "&":  
  65.               case "*":  
  66.               case "-":  
  67.               case "_":  
  68.               case "+":  
  69.               case "=":  
  70.               case "(":  
  71.               case ")":  
  72.               case "[":  
  73.               case "]":  
  74.               case "{":  
  75.               case "}":  
  76.               case ":":  
  77.               case ";":  
  78.               case "\"":  
  79.               case "'":  
  80.               case "|":  
  81.               case "\\":  
  82.               case "<":  
  83.               case ">":  
  84.               case ",":  
  85.               case ".":  
  86.               case "/":  
  87.               case "?":  
  88.                   if (isCodeCompleteBoxAdded)  
  89.                   {  
  90.                       this.Controls.Remove(CodeCompleteBox);  
  91.                       EnteredKey = "";  
  92.                   }  
  93.                   break;  
  94.   
  95.           }  
  96.       }  
Mouse Click Event:

This event code is same as Enter key down event in CodeCompleteBox. That's it! All the steps of algorithm are performed. Download the source code to create code completion using XML file. In Properties, you can change the Backgroud & Foreground color of Code Completion window.