Search code examples
monaco-editor

Need Monaco Editor For Custom Expression


I am looking for a monaco editor language/configuration for something pretty custom. I have been playing with the editor playground for custom languages: https://microsoft.github.io/monaco-editor/playground.html#extending-language-services-custom-languages, but haven't quite gotten close to what I need.

I basically want a single-line expression editor where the user can enter items from a limited set of known functions and utilize a list of existing parameters and/or literals.

Almost something like the formula box in Excel, but with highlighting of known/unknown words, as general highlighting of invalid syntax. Needs to allow nested evaluation

Examples: This should be allowed:

ADD(1, AVG(1, 2, 4)-5*(STDDEV(@Param1, @Param2))

This should show as an error with "Foof" highlighted in red since it's not in the allowed list:

Foof(1, 2) 

I am not too worried about type checking for now (adding string to bool to int), but bonus if that's incorporated.

ADD, AVG, STDDEV are all pulled from a known list. All other keywords (if we start with an existing language definition) need to be disallowed.

Don't want to support full C# style syntax. No code blocks {} allowed. Array syntax [] can be allowed.

Add(@SomeParamArray[5], @SomeParamArray[6]) should be allowed.

Thanks!


Solution

  • That's a very broad question and as such not very useful for a Q&A site like Stackoverflow. Nonetheless let me give you a number of keypoints for the road laying ahead of you:

    • Define your custom language with a Monarch syntax definintion, as a language contribution. In the monaco-editor NPM package look in the monaco-editor/esm/vs/basic-languages/javascript folder for an example how the language contribution and definition files have to look like.
    • Register both with Monaco:
            languages.onLanguage(msg.id, () => {
                msg.loader().then((module: any) => {
                    languages.setMonarchTokensProvider(msg.id, module.language);
                    languages.setLanguageConfiguration(msg.id, module.languageConfiguration);
                });
            });
    

    The value msg stands for a variable that defines your language extension point:

    export const msg: languages.ILanguageExtensionPoint & { [key: string]: any} = {
        id: "msg",
        extensions: [".msg"],
        aliases: ["MSG"],
        mimetypes: ["text/msg"],
        loader: (): any => import("./msg"),
    };
    
    • Create a parser which can be used to check the syntax of the input. Use that to add monaco-editor decorations to mark syntax errors.

    • Optionally create code completion, hover and signature help providers to give the user support for writing input in your custom language.