You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 18集成Monaco Editor:自定义主题失效问题排查

Angular 18集成Monaco Editor自定义主题与Monarch规则不生效问题

我计划在Angular 18应用中集成Monaco Editor用于编辑C#代码,暂不使用语言服务器,通过自定义主题与Monarch分词规则实现C#语法高亮,但自定义关键词hello始终无法显示预期的绿色,其他主题颜色设置也未生效。

现有实现代码

app.module.ts

monaco.languages.register({ id: 'csharp' });

// Set Monarch tokenization rules for C# language
monaco.languages.setMonarchTokensProvider('csharp', {
  keywords: ['public', 'void', 'if', 'else', 'for', 'while', 'return', 'using'],
  typeKeywords: ['Console', 'string', 'int', 'bool', 'double'],
  operators: ['=', '>', '<', '!', '==', '!=', '+', '-', '*', '/', '&&', '||'],
  symbols: /[>=<!~?:&|+\-*\/\^%]+/,
  tokenizer: {
    root: [
      // Match identifiers
      [/[A-Z][\w$]*/, {
        cases: {
          '@typeKeywords': 'type',    // Types like Console (green)
          '@default': 'identifier'    // Other identifiers
        }
      }],
      // Match keywords
      [/[a-zA-Z_]\w*/, {
        cases: {
          '@keywords': 'keyword',     // C# keywords (blue)
          'hello': 'helloToken',      // Custom token for "hello"
          '@default': 'identifier'    // Default identifier
        }
      }],
      // Recognize strings
      [/".*"/, 'string'],
      // Match brackets, operators, etc.
      [/[{}()\[\]]/, '@brackets'],
      [/@symbols/, { cases: { '@operators': 'operator' } }]
    ]
  }
});

export const customTheme: monaco.editor.IStandaloneThemeData = {
  base: 'vs-dark',
  inherit: true,
  rules: [
    { token: '', foreground: '2A2C2D' },
    { token: 'hello', foreground: '#66ff66' },
    { token: 'string.key.json', foreground: '7b3814' },
    { token: 'string.value.json', foreground: '0F6980', fontStyle: 'bold' }
  ],
  colors: {
    'editor.background': '#ff0000',
    'editor.lineHighlightBackground': '#ff0000',
    'editorCursor.foreground': '#ff0000',
    'editor.selectionBackground': '#ff0000',
    'editor.inactiveSelectionBackground': '#ff0000',
  }
};


const monacoConfig: NgxMonacoEditorConfig = {
  baseUrl: 'assets', // configure base path for monaco editor. Starting with version 8.0.0 it defaults to './assets'. Previous releases default to '/assets'
  defaultOptions: { scrollBeyondLastLine: false }, // pass default options to be used
  onMonacoLoad: () => {
    monaco.editor.defineTheme('customTheme', customTheme);
  },
  monacoRequire: (<any>window).monacoRequire,
  requireConfig: { preferScriptTags: true }
};

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    CommonModule,
    FormsModule,
    BrowserModule,
    AppRoutingModule,
    MonacoEditorModule.forRoot(monacoConfig)
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'monaco-test4';

  editorOptions = { theme: 'customTheme', language: 'csharp' };
  code: string = `public void x() {
    Console.WriteLine("hello world");
    hello; // This should be highlighted
  }`;
}

app.component.html

<div style="height: 100vh; display: flex; flex-direction: column;">
    <h1>{{ title }}</h1>
    <ngx-monaco-editor
      [options]="editorOptions"
      [(ngModel)]="code"
      style="flex: 1; margin-top: 20px;"
    ></ngx-monaco-editor>
  </div>

问题分析与修正方案

1. Token名称不匹配

Monarch规则中给hello定义的token是helloToken,但主题规则里写的是hello,两者名称不一致,导致主题无法匹配到该token。

2. 主题规则干扰与优先级问题

  • 空token规则{ token: '', foreground: '2A2C2D' }会覆盖基础主题的全局样式,干扰其他token的显示。
  • inherit: true时,基础主题规则优先级可能高于自定义规则,需确保自定义token名称准确无冲突。

3. Monaco初始化顺序问题

语言注册和Monarch规则设置在模块顶层执行时,Monaco可能尚未完成初始化,需将这些逻辑移到onMonacoLoad回调中,确保API就绪。


修正后的代码

app.module.ts

export const customTheme: monaco.editor.IStandaloneThemeData = {
  base: 'vs-dark',
  inherit: true,
  rules: [
    { token: 'helloToken', foreground: '#66ff66' }, // 匹配Monarch中的token名称
    { token: 'type', foreground: '#66ff66' }, // 显式定义类型颜色
    { token: 'keyword', foreground: '#569cd6' }, // 显式定义关键词颜色
    { token: 'string', foreground: '#ce9178' } // 显式定义字符串颜色
  ],
  colors: {
    'editor.background': '#1e1e1e',
    'editor.lineHighlightBackground': '#2a2a2a',
    'editorCursor.foreground': '#ffffff',
    'editor.selectionBackground': '#264f78',
    'editor.inactiveSelectionBackground': '#1e1e1e',
  }
};


const monacoConfig: NgxMonacoEditorConfig = {
  baseUrl: 'assets',
  defaultOptions: { scrollBeyondLastLine: false },
  onMonacoLoad: () => {
    // 将语言注册和Monarch规则移到此处,确保Monaco已初始化
    monaco.languages.register({ id: 'csharp' });

    monaco.languages.setMonarchTokensProvider('csharp', {
      keywords: ['public', 'void', 'if', 'else', 'for', 'while', 'return', 'using'],
      typeKeywords: ['Console', 'string', 'int', 'bool', 'double'],
      operators: ['=', '>', '<', '!', '==', '!=', '+', '-', '*', '/', '&&', '||'],
      symbols: /[>=<!~?:&|+\-*\/\^%]+/,
      tokenizer: {
        root: [
          // 调整匹配顺序,先处理关键词和自定义token
          [/[a-zA-Z_]\w*/, {
            cases: {
              '@keywords': 'keyword',
              '@typeKeywords': 'type',
              'hello': 'helloToken',
              '@default': 'identifier'
            }
          }],
          // 完善字符串匹配,支持转义字符
          [/"/, 'string', '@string'],
          // 括号与运算符
          [/[{}()\[\]]/, '@brackets'],
          [/@symbols/, { cases: { '@operators': 'operator' } }]
        ],
        string: [
          [/[^\\"]+/, 'string'],
          [/\\./, 'string.escape'],
          [/"/, 'string', '@pop']
        ]
      }
    });

    monaco.editor.defineTheme('customTheme', customTheme);
  },
  monacoRequire: (<any>window).monacoRequire,
  requireConfig: { preferScriptTags: true }
};

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    CommonModule,
    FormsModule,
    BrowserModule,
    AppRoutingModule,
    MonacoEditorModule.forRoot(monacoConfig)
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

额外说明

  • 调整Monaco规则匹配顺序,避免自定义token被标识符规则提前拦截。
  • 完善字符串tokenizer,支持转义字符,提升语法高亮准确性。
  • 显式定义基础token颜色,避免继承主题样式不符合预期。

内容的提问来源于stack exchange,提问作者Banana828

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 02:39:51