Dan
Dan

Reputation: 3103

How to Create a Custom Language in Monaco Editor for Inline CSS (Without Selectors or Brackets)

I am working on integrating Monaco Editor into a project and need to customize the CSS language support for a specific use case. My goal is to adapt the CSS language mode for inline styles, similar to what's used in HTML's style attribute. This means I need to configure the language mode to accept CSS properties and values without the need for selectors or curly braces.

Specific Problem: I am looking for a way to modify the existing CSS language configuration in Monaco Editor so that it accepts CSS properties and values directly (without the need for enclosing them in curly braces {}) and retains other features like syntax highlighting and autocomplete.

What I've Tried:

languages.register({ id: "inlineStyle" });

languages.onLanguage("inlineStyle", () => {
    languages.setLanguageConfiguration("inlineStyle", conf);
    languages.setMonarchTokensProvider("inlineStyle", {tokenizer: {
        root: [
            [/([a-zA-Z\-]+)\s*:/, "property"],
            [/([a-zA-Z\-]+)\s*$/, "property"],
            [/([a-zA-Z\-]+)\s*;\s*$/, "property"],
            [/([a-zA-Z0-9\s\.\#\-\(\)]+)(?=;|$)/, "value"],
        ]
    }});

    function fetchCssProperties() {
        // This is a simplified example. In a real application, you might fetch these properties from a server or a file.
        return [
            { name: "color", values: ["red", "green", "blue"] },
            { name: "background-color", values: ["yellow", "cyan", "magenta"] },
            { name: "width", values: ["100px", "50%", "auto"] },
            { name: "height", values: ["200px", "75%", "auto"] },
            // Add more properties as needed...
        ];
    }

    languages.registerCompletionItemProvider("inlineStyle", {
        provideCompletionItems: function(model, position) {
            // Fetch CSS properties and their values from a data source
            const cssProperties = fetchCssProperties();

            // Map CSS properties and their values to Monaco Editor completion items
            const completionItems = cssProperties.flatMap(property => {
                const propertyCompletionItem = {
                    label: property.name,
                    kind: languages.CompletionItemKind.Property,
                    insertText: property.name + ": ",
                    detail: "CSS Property",
                    documentation: "Inserts a CSS property"
                };

                const valueCompletionItems = property.values.map(value => {
                    return {
                        label: value,
                        kind: languages.CompletionItemKind.Value,
                        insertText: value,
                        detail: "CSS Value",
                        documentation: `Inserts the value "${value}" for the CSS property "${property.name}"`
                    };
                });

                return [propertyCompletionItem, ...valueCompletionItems];
            });

            return { suggestions: completionItems };
        }
    });

});

The above code works (kind of) but relies only on the properties I wrote in fetchCssProperties. Also, the whole list of CSS properties and values might be quite extensive, and I don't think parsing it every time I type is a good idea. I'm pretty sure Monaco has a better way of dealing with this for their basic CSS language.

My Question: Could anyone provide guidance or examples on how to modify the existing CSS language configuration in Monaco Editor to support direct input of CSS properties and values, without selectors and curly braces?

Any help or pointers to relevant parts of the Monaco Editor API or similar implementations would be greatly appreciated.

Thank you!

Upvotes: 0

Views: 461

Answers (1)

Mike Lischke
Mike Lischke

Reputation: 53532

There's no way to modify an existing language configuration or highlighter or code completion provider etc.

All you could do is to create your own language. Certain parts like the language configuration (braces, keywords and such) can be imported from an existing definition and be used to create a new definition from, but that's it.

And before you ask how to do that: it's not a simple thing that can be answered with a single answer here.

Upvotes: 1

Related Questions