2

据我了解, monaco-editor和 VSCode 使用两种不同的格式来定义主题。

似乎早期版本的 VSC 主要使用允许使用此工具转换主题的tmTheme定义格式(另见2017 年的 GitHub 问题)。但是,由于 VSC 现在使用一种新格式来定义其主题,我想知道是否有一种(简单的)方法可以在 Monaco 编辑器中使用现有的 VSC 主题。

非常感谢你的帮助!:)

PS 这个2019 年的 GitHub 问题评论似乎表明确实没有简单的方法可以做到这一点,但希望从那时起事情已经发生了变化。

4

3 回答 3

5

我创建了一个小型的 POC 存储库来演示它是如何工作的。它基于 monaco-vscode-textmate-theme-converter 插件。你可以在这里找到 repo ,我在这里发布了一个实际转换主题的工具。请注意,由于一些加载问题,您可能需要在开始之前对演示应用程序进行硬刷新。

于 2021-02-16T07:29:13.567 回答
1

我使用 monaco,我发现这个开源repo包含了几乎所有经常使用的 VSC 主题,如 katzenmitch 和 cloud ,您可以将它们用作一个npm包。当我浏览代码时,我发现他使用了像钴主题这样的 JSON 格式,代码如下:

{
  "base": "vs-dark",
  "inherit": true,
  "rules": [
    {
      "background": "002240",
      "token": ""
    },
    {
      "foreground": "e1efff",
      "token": "punctuation - (punctuation.definition.string || punctuation.definition.comment)"
    },
    {
      "foreground": "ff628c",
      "token": "constant"
    },
    {
      "foreground": "ffdd00",
      "token": "entity"
    },
    {
      "foreground": "ff9d00",
      "token": "keyword"
    },
    {
      "foreground": "ffee80",
      "token": "storage"
    },
    {
      "foreground": "3ad900",
      "token": "string -string.unquoted.old-plist -string.unquoted.heredoc"
    },
    {
      "foreground": "3ad900",
      "token": "string.unquoted.heredoc string"
    },
    {
      "foreground": "0088ff",
      "fontStyle": "italic",
      "token": "comment"
    },
    {
      "foreground": "80ffbb",
      "token": "support"
    },
    {
      "foreground": "cccccc",
      "token": "variable"
    },
    {
      "foreground": "ff80e1",
      "token": "variable.language"
    },
    {
      "foreground": "ffee80",
      "token": "meta.function-call"
    },
    {
      "foreground": "f8f8f8",
      "background": "800f00",
      "token": "invalid"
    },
    {
      "foreground": "ffffff",
      "background": "223545",
      "token": "text source"
    },
    {
      "foreground": "ffffff",
      "background": "223545",
      "token": "string.unquoted.heredoc"
    },
    {
      "foreground": "ffffff",
      "background": "223545",
      "token": "source source"
    },
    {
      "foreground": "80fcff",
      "fontStyle": "italic",
      "token": "entity.other.inherited-class"
    },
    {
      "foreground": "9eff80",
      "token": "string.quoted source"
    },
    {
      "foreground": "80ff82",
      "token": "string constant"
    },
    {
      "foreground": "80ffc2",
      "token": "string.regexp"
    },
    {
      "foreground": "edef7d",
      "token": "string variable"
    },
    {
      "foreground": "ffb054",
      "token": "support.function"
    },
    {
      "foreground": "eb939a",
      "token": "support.constant"
    },
    {
      "foreground": "ff1e00",
      "token": "support.type.exception"
    },
    {
      "foreground": "8996a8",
      "token": "meta.preprocessor.c"
    },
    {
      "foreground": "afc4db",
      "token": "meta.preprocessor.c keyword"
    },
    {
      "foreground": "73817d",
      "token": "meta.sgml.html meta.doctype"
    },
    {
      "foreground": "73817d",
      "token": "meta.sgml.html meta.doctype entity"
    },
    {
      "foreground": "73817d",
      "token": "meta.sgml.html meta.doctype string"
    },
    {
      "foreground": "73817d",
      "token": "meta.xml-processing"
    },
    {
      "foreground": "73817d",
      "token": "meta.xml-processing entity"
    },
    {
      "foreground": "73817d",
      "token": "meta.xml-processing string"
    },
    {
      "foreground": "9effff",
      "token": "meta.tag"
    },
    {
      "foreground": "9effff",
      "token": "meta.tag entity"
    },
    {
      "foreground": "9effff",
      "token": "meta.selector.css entity.name.tag"
    },
    {
      "foreground": "ffb454",
      "token": "meta.selector.css entity.other.attribute-name.id"
    },
    {
      "foreground": "5fe461",
      "token": "meta.selector.css entity.other.attribute-name.class"
    },
    {
      "foreground": "9df39f",
      "token": "support.type.property-name.css"
    },
    {
      "foreground": "f6f080",
      "token": "meta.property-group support.constant.property-value.css"
    },
    {
      "foreground": "f6f080",
      "token": "meta.property-value support.constant.property-value.css"
    },
    {
      "foreground": "f6aa11",
      "token": "meta.preprocessor.at-rule keyword.control.at-rule"
    },
    {
      "foreground": "edf080",
      "token": "meta.property-value support.constant.named-color.css"
    },
    {
      "foreground": "edf080",
      "token": "meta.property-value constant"
    },
    {
      "foreground": "eb939a",
      "token": "meta.constructor.argument.css"
    },
    {
      "foreground": "f8f8f8",
      "background": "000e1a",
      "token": "meta.diff"
    },
    {
      "foreground": "f8f8f8",
      "background": "000e1a",
      "token": "meta.diff.header"
    },
    {
      "foreground": "f8f8f8",
      "background": "4c0900",
      "token": "markup.deleted"
    },
    {
      "foreground": "f8f8f8",
      "background": "806f00",
      "token": "markup.changed"
    },
    {
      "foreground": "f8f8f8",
      "background": "154f00",
      "token": "markup.inserted"
    },
    {
      "background": "8fddf630",
      "token": "markup.raw"
    },
    {
      "background": "004480",
      "token": "markup.quote"
    },
    {
      "background": "130d26",
      "token": "markup.list"
    },
    {
      "foreground": "c1afff",
      "fontStyle": "bold",
      "token": "markup.bold"
    },
    {
      "foreground": "b8ffd9",
      "fontStyle": "italic",
      "token": "markup.italic"
    },
    {
      "foreground": "c8e4fd",
      "background": "001221",
      "fontStyle": "bold",
      "token": "markup.heading"
    }
  ],
  "colors": {
    "editor.foreground": "#FFFFFF",
    "editor.background": "#002240",
    "editor.selectionBackground": "#B36539BF",
    "editor.lineHighlightBackground": "#00000059",
    "editorCursor.foreground": "#FFFFFF",
    "editorWhitespace.foreground": "#FFFFFF26"
  }
}

我建议你可以通过它。并制作您自己的主题,而不是使用默认的 VSC 主题,但如果您仍想使用 vsc 主题,有很多类似这个的 repos。或者,您可以使用https://bitwiser.in/monaco-themes/之类的工具从 tmTheme 文件中生成 monaco 主题,这些文件从中选择颜色theme files并生成 json 以直接与monaco.editor.defineTheme.

我希望这会有所帮助。

于 2021-08-16T05:49:21.587 回答
1

主题扩展仍然支持 tmTheme 格式,并在导入时转换(据我记忆)。然而,扩展中主题的主要定义是使用 dark_plus.json 中所示的方法。

将 json 格式转换为 monaco-editor 所期望的结构非常容易:

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-editor 中:

    /**
     * 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-editor。函数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();
    }
};
于 2021-01-30T10:46:43.333 回答