Click here to Skip to main content
Click here to Skip to main content

DIY Intellisense

, 12 Jan 2004
Rate this:
Please Sign up or sign in to vote.
Do it yourself intellisense/autocompletion.

Sample Image - DIY-Intellisense.gif

Quick start

Download the project, compile and run it. Go to the menu and load %systemroot%\Microsoft.NET\Framework\v1.xxx\system.dll. Type System then a "." in the richtextbox. A listbox of classes/namespaces will appear.

Note: The namespace icon is used for both namespaces and types with no icons, this is laziness on my part.

Introduction

If you're a programmer and not familiar with intellisense, the chances are you've been hiding in a cave on a dialysis machine for the past 5 years. Intellisense is a Microsoft trademark, but the concept is available by dozens of code editors. In simple terms, it's a drop down list that appears when you type a recognized word into your code editor. For example, typing in System, then a "." inside Visual Studio .NET will show a drop down list of types for the System namespace. Another example can be found in Macromedia Dreamweaver - typing in a particular HTML tag and then a space will cause a list of attributes for that HTML tag to appear.

A fuzzy discussion about the history of intellisense can be found here.

In this article and the accompanying code, I'll demonstrate how to implement an intellisense-like system (I'll call it auto completion from now on) for a RichTextBox, triggered by the user pressing the "." key.

The complete project has the following features:

  • Auto complete from a drop down list
  • Easy-to-customize storage of the items that appear in the drop down listbox

I also threw the following in for good measure:

  • Icons display in the listbox, next to each item
  • Simple no thrills tooltip appears with a parameter list when you type a method name and a "("
  • Populating the autocompletion lookup tree through loading an assembly.

All of this doesn't look too much on virtual-paper, but the source code is almost 900 lines (including the form component layout code). I'll go through the code bit-by-bit, but first, the requirements.

The requirements

The project is a simple form with a RichTextBox and a main menu. The RichTextBox control hasn't been subclassed in any way, it's had its font changed to Courier and that's it.

The basic requirement is that when a user types a word, and then a ".", and the word is a known word, a list of items appear in a ListBox, underneath and to the right of the "." they just typed. From this, they can select an item from the ListBox, whose text is then pasted onto the RichTextBox, completing the word they were typing.

The form also has a TreeView, used for storing the items to be looked up, a ListBox, to display the items, and a text field which is used as cheap and cheerful tooltip for the method parameter lists.

Pressing the magic "." key

The RichTextBox's OnKeyDown event checks for an OemPeriod (I'm assuming this works on all machines being used). When a dot is pressed, the previous word is retrieved using the getLastWord() method.

This word is then checked to see if it exists inside the tree that we use for storing our lookups (described next). If it's found, the ListBox is populated with these items. populateListBox() manages this, returning a boolean for whether it populated any items or not. After this, the ListBox is positioned.

Luckily, the RichTextBox features a method that makes this task simple. Using the RichTextBox's GetPositionFromCharIndex(), we can get a Point struct for the current caret position. Using this, we position the ListBox's X coordinate according to the .'s and the Y is the same, but the height of the font is added (I tweaked it slightly, removing an extra 2 pixels for Courier); it is then positioned to appear underneath the ".". Visual Studio .NET positions the box above or below the current line, depending on the line position you're at in the text editor (the box appears above if you're on the last line of the text editor). I haven't added this feature, but I imagine it wouldn't be too hard to do.

The lookup tree

As I mentioned, all the items that the autocomplete looks for are stored in a TreeView. For the type of code completion I'm implementing - Namespaces/classes/methods - storing the items in a tree makes perfect sense. For something like HTML code completion, this would also be the ideal candidate, the root nodes could be the core set of HTML tags, and the nodes underneath would be the attributes. For a flat list, the TreeView could possibly be got rid of, and the ListBox used on its own.

When I started the project, I started to create my own tree implementation for storing the items. I then realized there was no point doing this as .NET provided the structure for me in the form of a TreeView. It's got the overhead of a being a control, however it allows you to easily add and edit items inside an IDE like Visual Studio .NET, Borland C# builder, #develop, etc., making the job quicker.

Code completion behavior

Once the "." is pressed and the drop down list of items appear, the following logic is applied:

  • Focus is sent back to the RichTextBox, which traps the up and down key. These keys are then used to move up and down the ListBox.
  • If an item is a selected, and the user presses the Return, Space or Tab key, then the ListBox of items hides, and auto completion of the word is fired.
  • When the ListBox is visible, any alpha-numerical key can be pressed. Any other key except Backspace or Shift hides the ListBox.
  • Pressing the delete key hides the ListBox if the character being deleted is a "." .
  • When any alpha-numerical key is pressed, a string is concatenated from the typed characters.
  • The ListBox is searched to see if any of its items begin with the combination typed, if they do, then this item is selected.
  • Double clicking on an item in the ListBox fires the autocompletion.

All of this is checked in the RichTextBox's OnKeyDown event.

Finding an item in the tree

Once the previous word that was typed is found, the TreeView is searched to see if the word can be found. As the word can contain a full namespace, it is broken down according to the dots, and the FullPath property of the node is checked against a concatenated string. This is done inside a recursive function. When a node is found, this is stored in a member variable, which is then used to populate the ListBox with all the child nodes. The nodes are sorted by their text by creating an array of a custom type, which implements IComparable. This array is populated from the TreeNode, then sorted and the ListBox is populated using it.

Obviously, sorting the items each time they're populated is quite a slow way around, a preferred method would be to sort the tree when it's populated. A sorteable TreeView would be a whole new article though (has anyone implemented one?!), this suffices for now.

Autocompleting the text

This is a fairly simple procedure - everything before the dot is stored in a string, and everything after the dot is stored in another string, and a new string has the selected ListBox item's text appended in the middle of the two. The RichTextBox's text is then replaced with this new text. I haven't tested this method with large amounts of text, it may require customizing the RichTextBox if flickering starts to occur.

Extras

To demonstrate the autocompletion, additional 2 methods are in the source, for reading an assembly and populating the tree with its types. The readAssembly() method loads an assembly in and cycles through all its types, adding nodes to the tree for namespaces, classes, methods, fields and events. Each type uses addMembers() to have its fields, methods and events added as nodes.

Each ListBox item features an icon to indicate what type it is - this type is stored inside each TreeNode's Tag property. The Tag property also stores a method's parameter list as a string, so we assume the node is a method if the Tag property is a string. The display of icons in the ListBox is done using the GListBox class.

As mentioned above, when a method is typed and the left bracket '(' key is pressed, a tooltip is displayed with the parameter list for the method. I couldn't find any free custom tooltip implementations for this, so I used the displaying of a TextBox with the details in, positioning it the same way the ListBox of items is positioned.

Conclusion

I don't want to over-bloat this article by going into great depths about each method, so I'll stop here. Hopefully it's useful to people. I want to point out that it's proof of concept code rather than any finished product; I haven't tested the TreeView to see how well it weathers with 1000s of nodes, and there are minor things I could improve in it (given a team of developers, a big paycheck and the knowledge that the biggest company in the world was backing me!)

Known Bugs

  • You may get an index out of bounds error when you go to view the form designer. This is a problem with the GListBox, I didn't fix the error. It's only at design time, the project still compiles fine.
  • Using the tab for autocomplete adds a tab to RichTextBox (even though e.Handled = true...something for me to look at on a rainy day).
  • Tooltip doesn't stay in front of the form.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

yetanotherchris
Web Developer
United Kingdom United Kingdom
London based C# programmer.
 
I maintain my own pet C# site http://www.sloppycode.net in my spare time.

Comments and Discussions

 
GeneralAmazing Pinmemberr3dqu33n11-Apr-14 20:59 
QuestionHave you looked at re-implementing this using the June 2012 CTP of Roslyn? PinmemberChris Sells23-Jun-12 14:18 
SuggestionFix for design view PinmemberStimphy21-May-12 18:52 
GeneralRe: Fix for design view Pinprofessionaluzairali00129-Jan-14 4:34 
GeneralIntellisense help PinmemberMember 443453629-Mar-11 4:12 
GeneralBreaks out of Intellisense on "shift" keypress PinmemberG2Chris5-Jan-11 12:15 
GeneralRe: Breaks out of Intellisense on "shift" keypress PinmemberMatthew Rhoden5-Jan-12 8:41 
GeneralTo fix the font width issue for the textbox PinmemberRaidenFlyboy7-May-10 9:09 
GeneralHi,Some Data Base Issues When i try to bind the dataset to the listbox Pinmemberpuja1618-Apr-10 20:09 
GeneralThis is an amazing feat! PinmemberDiamonddrake6-Apr-10 9:00 
GeneralUse of code Pinmemberszb_szb6-Aug-09 20:39 
GeneralUsing Intellisense PinmemberMr. Badr CHOUFFAI15-Jul-09 4:37 
Generalthis is awesome! Pinmemberfirehak16-Apr-09 16:11 
QuestionCommercial use? Pinmembersanme9831-May-08 6:13 
GeneralI wonder if it would be OK... Pinmembertherearefartoomanybens11-Dec-07 12:28 
I'd like to borrow inspiration and a little code from your GListBox... if that would be alright?
 
I'm steadily expanding some more usable WinForm components, I will opensource and codeproject it when its finished - but an autocompleting RichEdit is a so-darn-useful component to have in the toolbox it'd be criminal not to elaborate on your work.
 
You should have P/Invoked GetCaretPos too silly!
 
... Roll eyes | :rolleyes: but I have done that for you hahaha...
 
CSharp-on-Rails here we go!
QuestionDo not work ! PinmemberYeurl_200719-Mar-07 23:53 
AnswerRe: Do not work ! PinmemberWouter Demuynck3-May-07 23:30 
QuestionHow to fix the tab key not being handled.. Pinmemberillium13-Dec-06 20:26 
AnswerRe: How to fix the tab key not being handled.. PinmemberVegio2-Feb-09 3:01 
QuestionClipping PinmemberCyclonicEvent10-Nov-06 23:44 
AnswerRe: Clipping PinmemberCyclonicEvent11-Nov-06 4:03 
Generalintellisense for db Pinmemberrizomatosa16-Oct-06 7:43 
General=) PinmemberChris Nevill14-Jan-06 6:19 
GeneralRe: =) Pinmembersmallguy7814-Nov-06 0:23 
GeneralRe: =) PinmemberChris Nevill14-Nov-06 0:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140821.2 | Last Updated 13 Jan 2004
Article Copyright 2004 by yetanotherchris
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid