In the Regex Editor sample we provide a (mostly) full implementation of a Language Service for Visual Studio 2010, along with some editor manipulation and hosting the editor in a new window.

To launch the new regex editor we have two different launch points: when writing "new Regex(" and when ctrl+clicking the text inside that declaration.

The first launch point is handled by a KeyProcessor. The key processor is provided by an IKeyProcessorProvider. When "(" is pressed, the key processor checks the rest of the line and, if necessary, shows the regex editor using a RegexEditorService we provide elsewhere.

The second launch point is handled by an IMouseProcessor. The IMouseProcessor is provided by an IMouseProcessorProvider which additionally imports an IToolTipProviderFactory that will be used to show a tooltip when the mouse cursor hovers over a valid regex, showing that the editor can be shown by doing a Ctrl+Click on the text. The IMouseProcessor also checks the cursor position and launches the editor on keyup.

There is a separate IKeyProcessorProvider in the actual editor (called RegexEditorProcessorProvider) that will intercept the keyboard and send it to the new editor.

When a launch point is hit, we create a new ITextBuffer and IWpfTextViewHost (in RegexEditorService.ShowEditor), and show the RegexEditorDialog. The actual hosting occurs in the constructor of the RegexEditorDialog, where we add the HostControl field from the IWpfTextViewHost we created to the controls in the dialog. This editor has assigned a Content Type of "regex". This will help when providing Coloring, Completion and Brace Matching.

We have a very simple parser to parse the regex that constructs an AST created only with Token objects. These objects have a TokenKind that identify the kind of token (for coloring and completion). The parser is parsed each time the text buffer changes, tracked by exporting an IWpfTextViewCreationListener that let's us hook when the text view is being created and subscribe to the Changed event early on the process. This parser is used for Coloring (classification), Completion and Brace Matching.

For classification, we first need to provide Type Definitions (exporting ClassificationTypeDefinition). These define what new classifications are available. The classifications are not attached to a single language. Once the Type Definitions are in place, we need to provide Format Definitions (inheriting ClassificationFormatDefinition and exporting EditorFormatDefinition). These define default look for each Type Definition. Then we need to do the actual classification (stating which character in the buffer is of which type). This is done in an IClassifier. To provide an IClassifier we implement an IClassifierProvider. In the provider, we import an IClassificationTypeRegistryService, that will give us the type information for classification types. The IClassifier has a method (GetClassificationSpans) that will be called by Visual Studio when classification is needed and an event (ClassificationChanged) that we must raise when we need to change classification for a span.

For completion, we're implementing a Controller (which states when completion should be called) and a Source (which states what are the possible values for the completion). They implement IIntellisenseController and ICompletionSource, respectively, and are provided by IIntellisenseControllerProvider and ICompletionSourceProvider. The Controller is used to show completion when a trigger character is entered in the buffer (either "{", "[", "(" or "\"). The Source will provide a list of possible values depending on the context.

For Brace Matching there is no standard interface to implement in Visual Studio (yet), so we're providing an IBraceMatherProvider and IBraceMatcher to be consumed by a Presenter (and a PresenterFactory that implements IWpfTextViewCreationListener), and to be provided by RegexBraceMatcherProvider and RegexBraceMatcher. The presenter will import these objects and use them to know where to show matching braces. Actually showing the braces (using a TextMarkerTag) is a responsibility of the presenter.

Last edited Dec 1, 2009 at 1:09 PM by joj, version 1


No comments yet.