Как использовать тему VSC в монако-редакторе?

Насколько я понимаю, monaco-editor и VSCode используют два разных формата для определения тем.

Похоже, что более ранняя версия VSC в основном использовала tmTheme формат определения, который позволял темы для преобразования с помощью этого инструмента (также см. проблема GitHub от 2017 г.). Однако, поскольку VSC теперь использует новый формат для определения своих тем, мне интересно, есть ли (простой) способ использовать существующие темы VSC в редакторе Monaco.

Спасибо большое за вашу помощь! :)

P.S. Этот комментарий к проблеме GitHub от 2019 года, кажется, указывает на наличие действительно нет простого способа сделать это, но, надеюсь, с тех пор все изменилось. ????


person schickling    schedule 29.01.2021    source источник


Ответы (2)


Я создал небольшое репозиторий POC, чтобы продемонстрировать, как это может работать. Он основан на плагине monaco-vscode-textmate-theme-converter. Вы можете найти репозиторий здесь, и я опубликовал инструмент для фактического преобразования темы здесь. Обратите внимание: из-за некоторых проблем с загрузкой вам может потребоваться жесткое обновление демонстрационного приложения перед запуском.

person cbutler    schedule 16.02.2021

Формат tmTheme по-прежнему поддерживается в расширениях тем и конвертируется при импорте (насколько я помню). Однако основное определение темы в расширении использует подход, подобный показанному в dark_plus.json.

Довольно легко преобразовать формат json в структуру, которую ожидает редактор monaco:

export interface Colors { [key: string]: string }
export interface ITokenEntry {
    name?: string;
    scope: string[] | string;
    settings: {
        foreground?: string;
        background?: string;
        fontStyle?: string;
    };
}

// This is the structure of a vscode theme file.
export interface IThemeObject {
    name: string;
    type?: string;
    include?: string;
    colors?: Colors;

    settings?: ITokenEntry[];    // Old style specification.
    tokenColors?: ITokenEntry[]; // This is how it should be done now.
}

Эти интерфейсы описывают формат файла json. В более старых определениях темы для определения цветов темы используется член settings. В таком случае просто установите член tokenColors на член settings и продолжайте.

После загрузки темы вы можете использовать этот статический метод, чтобы загрузить ее в редактор monaco:

    /**
     * Updates the theme used by all code editor instances.
     *
     * @param theme The theme name.
     * @param type The base type of the theme.
     * @param values The actual theme values.
     */
    public static updateTheme(theme: string, type: "light" | "dark", values: IThemeObject): void {
        // Convert all color values to CSS hex form.
        const entries: { [key: string]: string } = {};
        for (const [key, value] of Object.entries(values.colors || {})) {
            entries[key] = colorToHex(value) || "";
        }

        const tokenRules: Monaco.ITokenThemeRule[] = [];
        (values.tokenColors || []).forEach((value: ITokenEntry): void => {
            const scopeValue = value.scope || [];
            const scopes = Array.isArray(scopeValue) ? scopeValue : scopeValue.split(",");
            scopes.forEach((scope: string): void => {
                tokenRules.push({
                    token: scope,
                    foreground: colorToHex(value.settings.foreground),
                    background: colorToHex(value.settings.background),
                    fontStyle: value.settings.fontStyle,
                });
            });
        });

        CodeEditor.currentThemeId = theme.replace(/[^a-zA-Z]+/g, "-");
        Monaco.defineTheme(CodeEditor.currentThemeId, {
            base: type === "light" ? "vs" : "vs-dark",
            inherit: true,
            rules: tokenRules,
            colors: entries,
        });

        Monaco.setTheme(CodeEditor.currentThemeId);
    }

CodeEditor - это мой класс TS, который является оболочкой для редактора monaco. Функция colorToHex определяется как:

import Color from "color";

/**
 * Converts a color string or a color to a hex string.
 *
 * @param color The value to convert.
 *
 * @returns A hex string of the given color, including the alpha value.
 */
export const colorToHex = (color: string | Color | undefined): string | undefined => {
    if (!color) {
        return;
    }

    if (typeof color === "string") {
        color = new Color(color);
    }

    // Hex color values have no alpha component, so we have to add that explicitly.
    if (color.alpha() < 1) {
        let alpha = Math.round((color.alpha() * 255)).toString(16);
        if (alpha.length < 2) {
            alpha = "0" + alpha;
        }

        return color.hex() + alpha;
    } else {
        return color.hex();
    }
};
person Mike Lischke    schedule 30.01.2021
comment
Большое спасибо за ответ, Майк. Хотя преобразованная тема (VSC - ›Monaco) работает, есть еще много различий в окончательном результате рендеринга. Вот пример: - Скриншот VSC (желаемый результат): i.imgur.com/OXlCmJN.png - Скриншот Монако: i.imgur.com/A9gTAy2.png Можно найти рабочий код здесь: repl.it/@schickling/monaco-vite#src/main. ts - person schickling; 04.02.2021
comment
У вас не может быть всех одинаковых цветов, потому что vscode добавляет семантическую подсветку поверх подсветки синтаксиса. Вы можете увидеть это, например, по разным цветам для двух идентификаторов (имени функции и параметров). Monaco не поддерживает семантическое выделение из коробки. - person Mike Lischke; 04.02.2021
comment
Спасибо за разъяснения. Эта несовместимость кажется весьма прискорбной, учитывая, что VSCode и Monaco основаны на одной и той же кодовой базе. Надеюсь, это ограничение скоро будет устранено разработчиками. - person schickling; 04.02.2021
comment
Привет! Я пытаюсь выяснить то же самое прямо сейчас, поэтому, если вы найдете ответ, я буду очень признателен, если вы поделитесь. И просто чтобы я не подошел к столу с пустыми руками, я предполагаю, что вы читали, как codeandbox обходят это, из сообщения Айвза здесь: codeandbox.io/post/introduction-themes#how-it-works - person cbutler; 04.02.2021
comment
Я также нашел этот пакет и очень надеялся, но не мог заставить его работать: github.com/Nishkalkashyap/ - person cbutler; 04.02.2021
comment
Майк, не могли бы вы подробнее объяснить, как работает семантическое выделение? Я не совсем понимаю суть проблемы - person cbutler; 04.02.2021
comment
Извините за все комментарии, но я также задал аналогичный вопрос за день или около того до вас, и там я думал об использовании css в качестве решения, но, как указал Майк, это не очень хороший подход. stackoverflow .com / questions / 65921179 / - person cbutler; 04.02.2021