DEV Community

Cover image for WPF: Create Syntax Editor for Any Language in 5 Minutes
Suresh Mohan for Syncfusion, Inc.

Posted on • Originally published at syncfusion.com on

WPF: Create Syntax Editor for Any Language in 5 Minutes

The Syntax Editor provides built-in support for 10+ procedural and markup languages, including C#, Visual Basic, XAML, and JavaScript. It also comes with custom language configurations to apply syntax highlighting and outlining based on the user’s needs.

The Syntax Editor allows users to create a custom language with ease by inheriting one of the following base classes that contain a basic level of implementations and require a minimal set of configurations:

For detailed information on the implementation of these base classes, refer tocustom language support documentation.

The ProceduralLanguageBase class contains syntax highlighting, outlining, and auto-mode IntelliSense implementations for procedural languages such as C# and Visual Basic, whereas the MarkupLanguageBase class contains syntax highlighting and outlining implementations for markup languages such as XAML and XML, and scripting languages such as JavaScript.

Let’s see how to configure a custom language in the Syntax Editor.

Configuring a custom language: IronPython

The following steps explain how to configure the custom language IronPython :

Step 1: Create a new class, inheriting from the ProceduralLanguageBase class.

Create a new class inheriting from the ProceduralLanguageBase class since IronPython ’s start and end tags match with procedural languages. Set the basic properties of the language in the inherited class by using the following code:

public class PythonLanguage : ProceduralLanguageBase
{
    public PythonLanguage(EditControl control) : base(control)
    {
        this.Name = "Python";
        this.FileExtension = "py";
        this.ApplyColoring = true;
        this.SupportsIntellisense = false;
        this.SupportsOutlining = true;
        this.TextForeground = Brushes.Black;
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Create a format collection for IronPython.

Create a collection of IFormat -implemented classes to apply in the Formats property of the custom language to decide the color applied to tokens by using the following code.

<syncfusion:FormatsCollection x:Key="pythonLanguageFormats">
<syncfusion:EditFormats Foreground="Green" FormatName="CommentFormat"/>
<syncfusion:EditFormats Foreground="Black" FormatName="MultilineCommentFormat"/>
<syncfusion:EditFormats Foreground="Blue" FormatName="KeywordFormat"/>
<syncfusion:EditFormats Foreground="Navy" FormatName="OperatorFormat"/>
<syncfusion:EditFormats Foreground="Gray" FormatName="LiteralsFormat"/>
</syncfusion:FormatsCollection>
Enter fullscreen mode Exit fullscreen mode

Step 3: Create a Lexem collection for IronPython.

Create a collection of ILexem -implemented classes—which decides keywords, comments, literals, and preprocessor information for the custom language—by using the following code.

<syncfusion:LexemCollection x:Key="pythonLanguageLexems">
<syncfusion:Lexem StartText="class \w+[\s:\w,()]+" IsRegex="True" IsMultiline="True" ContainsEndText="True" LexemType="CodeSnippet" EndText="\r\n" ScopeLevel="Class" ShowAlternateIntellisenseText="True" IntellisenseDisplayText="class"/>
<syncfusion:Lexem StartText="def \w+[\s:\w,()]+" IsRegex="True" IsMultiline="True" ContainsEndText="True" LexemType="CodeSnippet" EndText="\r\n" ScopeLevel="Member" ShowAlternateIntellisenseText="True" IntellisenseDisplayText="def"/>
<syncfusion:Lexem StartText="#" EndText="\r\n" IsMultiline="False" ContainsEndText="True" LexemType="Comment" FormatName="CommentFormat"/>
<syncfusion:Lexem StartText=""""" EndText=""""" IsMultiline="True" ContainsEndText="True" LexemType="Comment" FormatName="CommentFormat" />
<syncfusion:Lexem StartText="and" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="as" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="assert" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="break" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="class" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="continue" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="def" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="del" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="elif" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="else" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="except" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="exec" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="finally" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="for" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="from" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="global" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="if" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="import" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="in" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="is" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="lambda" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="not" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="or" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="pass" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="print" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="raise" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="return" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="try" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="while" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="with" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText="yeild" ContainsEndText="False" IsMultiline="False" LexemType="Keyword" FormatName="KeywordFormat"/>
<syncfusion:Lexem StartText=""" EndText=""" IsMultiline="False" LexemType="Literals" FormatName="LiteralsFormat"/>
<syncfusion:Lexem StartText="(" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText=")" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="[" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="]" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="\{" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="\}" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="." ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="," ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText=";" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText=":" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="+" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="-" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="/" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="%" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="^" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="*" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="**" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="|" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="|=" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="&" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="~" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="=" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="<" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText=">" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="==" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="!=" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="<=" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText=">=" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="+=" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="-=" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="*=" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="%=" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="/=" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="&=" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="^=" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="|=" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="<<" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="<<=" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="=>" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="<>" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText=">>=" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
<syncfusion:Lexem StartText="**;=" ContainsEndText="False" IsMultiline="False" LexemType="Operator" FormatName="OperatorFormat"/>
</syncfusion:LexemCollection>
Enter fullscreen mode Exit fullscreen mode

Step 4: Assign Lexem and Format properties to custom python language.

Initialize and assign Lexem and Format collections to the custom Python language.

PythonLanguage customLanguage = new PythonLanguage(obj as EditControl);
customLanguage.Lexem = this.Resources["pythonLanguageLexems"] as LexemCollection;
customLanguage.Formats = this.Resources["pythonLanguageFormats"] as FormatsCollection;
Enter fullscreen mode Exit fullscreen mode

If there is still any need to customize colors for syntax, the ApplyColoring method can be overridden to achieve further customization of colors. Similarly, to customize outlining, the ApplyExpandCollapse method can be overridden. Please refer to this documentation topic for detailed information on the usage of overridden methods.

After executing the above configurations, we will get the following output for the IronPython language:

WPF Syntax Editor Customized to Support IronPyton
WPF Syntax Editor Customized to Support IronPyton

References

To learn more, refer to the documentation custom language support and configuring custom language using WPF syntax editor demo.

Conclusion

I hope you now feel confident enough to configure a custom language for the Syntax Editor on your own in just four simple steps. This feature will definitely help you extend the usage of the Syntax Editor beyond the supported procedural and markup languages.

If you want to play around with the Syntax Editor, you’ll be happy to know that our WPF demos are now available in the Microsoft Store, and our .NET Core demos are available in the App Center.

For existing customers, the newest version of Essential Studio is available for download from the License and Downloads page. If you are not yet a Syncfusion customer, you can try our 30-day free trial to check out our available features.

If you wish to send us feedback or ask any questions, please use the comments section below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!

Top comments (0)