简体   繁体   English

如何在 monaco-editor 中使用 VSC 主题?

[英]How to use a VSC theme in monaco-editor?

To my understanding monaco-editor and VSCode are using two different formats to define themes.据我了解, monaco-editor和 VSCode 使用两种不同的格式来定义主题。

It seems that an earlier version of VSC primarily used the tmTheme definition format which allowed themes to be converted using this tool (also see a GitHub issue from 2017 ).似乎早期版本的 VSC 主要使用tmTheme定义格式,该格式允许使用此工具转换主题(另请参阅2017 年的 GitHub 问题)。 However, since VSC is now using a new format to define its themes, I'm wondering whether there is a (simple) way to use existing VSC themes in the Monaco editor.但是,由于 VSC 现在使用一种新格式来定义其主题,我想知道是否有一种(简单的)方法可以在 Monaco 编辑器中使用现有的 VSC 主题。

Thanks a lot for your help: :)非常感谢你的帮助: :)

PS This GitHub issue comment from 2019 seems to indicate that there is indeed no easy way to do this but hopefully things have changed since then. PS 这个GitHub 2019 年的问题评论似乎表明确实没有简单的方法可以做到这一点,但希望从那时起事情已经发生了变化。

The tmTheme format is still supported in theme extensions and converted on import (from what I remember).主题扩展仍然支持 tmTheme 格式,并在导入时转换(据我记忆)。 The primary definition of a theme in an extension, however, is using the approach like shown in dark_plus.json.然而,扩展中主题的主要定义是使用类似于 dark_plus.json 中所示的方法。

It's pretty easy to convert the json format to the structure that's expected by monaco-editor:将 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.
}

These interfaces describe the format of the json file.这些接口描述了 json 文件的格式。 Older theme definitions use the settings member to define theme colors.较旧的主题定义使用settings成员来定义主题 colors。 In such a case simply set the tokenColors member to the settings member and proceed.在这种情况下,只需将tokenColors成员设置为settings成员并继续。

Once the theme has been loaded you can use this static method to load it into monaco-editor:加载主题后,您可以使用此 static 方法将其加载到 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 is my TS class that wraps the monaco-editor. CodeEditor是我的 TS class 包装了 monaco-editor。 The function colorToHex is defined as: function 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();
    }
};

I created a small, POC repo to demonstrate how this can work.我创建了一个小型的 POC 存储库来演示它是如何工作的。 It's based on the monaco-vscode-textmate-theme-converter plugin.它基于 monaco-vscode-textmate-theme-converter 插件。 You can find the repo here and I published a tool to actually convert a theme here .你可以在 这里找到 repo,我在这里发布了一个实际转换主题的工具。 Note, due to some loading issues you might need to do a hard refresh of the demo app before starting.请注意,由于一些加载问题,您可能需要在开始之前对演示应用程序进行硬刷新。

I use monaco and I found this open source repo which conatins almost all the regualrly used VSC themes like katzenmitch and cloud, which you could use as a npm package.我使用 monaco,我发现这个开源repo包含了几乎所有经常使用的 VSC 主题,如 katzenmitch 和 cloud,您可以将其用作npm package。 When I went through the code I found that he used JSON format like for cobalt theme it was this code:当我浏览代码时,我发现他使用了 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"
  }
}

I suggest you could go through it.我建议你可以通过它 go 。 and make your own theme instead of using default VSC themes but if you still want to use vsc themes there are many repos like this one.并制作您自己的主题,而不是使用默认的 VSC 主题,但如果您仍想使用 vsc 主题,有很多类似这个的 repos。 Or you could use tools like https://bitwiser.in/monaco-themes/ to generate theme for monaco from tmTheme files that picks colors from theme files and generates a json to be used directly with monaco.editor.defineTheme . Or you could use tools like https://bitwiser.in/monaco-themes/ to generate theme for monaco from tmTheme files that picks colors from theme files and generates a json to be used directly with monaco.editor.defineTheme .

I hope this helped.我希望这会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM