如何用Monarch为Markdown实现自定义语法高亮规则?
Monaco + Monarch 实现Markdown自定义语法高亮方案
一、修改Monarch配置添加自定义规则
Monarch的语法规则按顺序匹配,需将自定义规则放在对应匹配组的最前面,避免被其他规则优先覆盖。
1. 匹配||开头的行
在tokenizer.root数组顶部添加规则,优先识别以||开头的整行内容:
// 匹配以||开头的行 [/^(\s*)||(.*)$/, ['white', 'custom-special-line', 'custom-special-line']],
2. 匹配自定义关键词MyKeyword1/MyKeyword2
在tokenizer.linecontent数组顶部添加关键词匹配规则,确保在粗体、斜体等格式规则之前生效:
// 匹配自定义关键词 [/\b(MyKeyword1|MyKeyword2)\b/, 'custom-keyword'],
修改后的完整Monarch配置
// Difficulty: "Ultra-Violence" // Language definition for Markdown // Quite complex definition mostly due to almost full inclusion // of the HTML mode (so we can properly match nested HTML tag definitions) return { defaultToken: '', tokenPostfix: '.md', // escape codes control: /[\`*_\[\]{}()#+\-\.!]/, noncontrol: /[^\`*_\[\]{}()#+\-\.!]/, escapes: /\\(?:@control)/, // escape codes for javascript/CSS strings jsescapes: /\\(?:[btnfr\\"']|[0-7][0-7]?|[0-3][0-7]{2})/, // non matched elements empty: [ 'area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param' ], tokenizer: { root: [ // 新增:匹配以||开头的行 [/^(\s*)||(.*)$/, ['white', 'custom-special-line', 'custom-special-line']], // headers (with #) [/^(\s{0,3})(#+)((?:[^\\#]|@escapes)+)((?:#+)?)/, ['white', 'keyword', 'keyword', 'keyword']], // headers (with =) [/^\s*(=+|\-+)\s*$/, 'keyword'], // headers (with ***) [/^\s*((\*[ ]?)+)\s*$/, 'meta.separator'], // quote [/^\s*>+/, 'comment'], // list (starting with * or number) [/^\s*([\*\-+:]|\d+\.)\s/, 'keyword'], // code block (4 spaces indent) [/^(\t|[ ]{4})[^ ].*$/, 'string'], // code block (3 tilde) [/^\s*~~~\s*((?:\w|[\/\-#])+)?\s*$/, { token: 'string', next: '@codeblock' }], // github style code blocks (with backticks and language) [/^\s*```\s*((?:\w|[\/\-#])+)\s*$/, { token: 'string', next: '@codeblockgh', nextEmbedded: '$1' }], // github style code blocks (with backticks but no language) [/^\s*```\s*$/, { token: 'string', next: '@codeblock' }], // markup within lines { include: '@linecontent' }, ], codeblock: [ [/^\s*~~~\s*$/, { token: 'string', next: '@pop' }], [/^\s*```\s*$/, { token: 'string', next: '@pop' }], [/.*$/, 'variable.source'], ], // github style code blocks codeblockgh: [ [/```\s*$/, { token: 'variable.source', next: '@pop', nextEmbedded: '@pop' }], [/[^`]+/, 'variable.source'], ], linecontent: [ // 新增:匹配自定义关键词 [/\b(MyKeyword1|MyKeyword2)\b/, 'custom-keyword'], // escapes [/&\w+;/, 'string.escape'], [/@escapes/, 'escape'], // various markup [/\b__([^\\_]|@escapes|_(?!_))+__\b/, 'strong'], [/\*\*([^\\*]|@escapes|\*(?!\*))+\*\*/, 'strong'], [/\b_[^_]+_\b/, 'emphasis'], [/\*([^\\*]|@escapes)+\*/, 'emphasis'], [/`([^\\`]|@escapes)+`/, 'variable'], // links [/\{+[^}]+\}+/, 'string.target'], [/(!?\[)((?:[^\]\\]|@escapes)*)(\]\([^\)]+\))/, ['string.link', '', 'string.link']], [/(!?\[)((?:[^\]\\]|@escapes)*)(\])/, 'string.link'], // or html { include: 'html' }, ], // Note: it is tempting to rather switch to the real HTML mode instead of building our own here // but currently there is a limitation in Monarch that prevents us from doing it: The opening // '<' would start the HTML mode, however there is no way to jump 1 character back to let the // HTML mode also tokenize the opening angle bracket. Thus, even though we could jump to HTML, // we cannot correctly tokenize it in that mode yet. html: [ // html tags [/<(\w+)\/>/, 'tag'], [/<(\w+)/, { cases: { '@empty': { token: 'tag', next: '@tag.$1' }, '@default': { token: 'tag', next: '@tag.$1' } } }], [/<\/(\w+)\s*>/, { token: 'tag' }], [/<!--/, 'comment', '@comment'] ], comment: [ [/[^<\-]+/, 'comment.content'], [/-->/, 'comment', '@pop'], [/<!--/, 'comment.content.invalid'], [/[<\-]/, 'comment.content'] ], // Almost full HTML tag matching, complete with embedded scripts & styles tag: [ [/[ \t\r\n]+/, 'white'], [/(type)(\s*=\s*)(")([^"]+)(")/, ['attribute.name.html', 'delimiter.html', 'string.html', { token: 'string.html', switchTo: '@tag.$S2.$4' }, 'string.html']], [/(type)(\s*=\s*)(')([^']+)(')/, ['attribute.name.html', 'delimiter.html', 'string.html', { token: 'string.html', switchTo: '@tag.$S2.$4' }, 'string.html']], [/(\w+)(\s*=\s*)("[^"]*"|'[^']*')/, ['attribute.name.html', 'delimiter.html', 'string.html']], [/\w+/, 'attribute.name.html'], [/\/>/, 'tag', '@pop'], [/>/, { cases: { '$S2==style': { token: 'tag', switchTo: 'embeddedStyle', nextEmbedded: 'text/css' }, '$S2==script': { cases: { '$S3': { token: 'tag', switchTo: 'embeddedScript', nextEmbedded: '$S3' }, '@default': { token: 'tag', switchTo: 'embeddedScript', nextEmbedded: 'text/javascript' } } }, '@default': { token: 'tag', next: '@pop' } } }], ], embeddedStyle: [ [/[^<]+/, ''], [/<\/style\s*>/, { token: '@rematch', next: '@pop', nextEmbedded: '@pop' }], [/</, ''] ], embeddedScript: [ [/[^<]+/, ''], [/<\/script\s*>/, { token: '@rematch', next: '@pop', nextEmbedded: '@pop' }], [/</, ''] ], } };
二、设置自定义颜色与CSS变量
Monarch支持通过自定义主题关联token与颜色,也可直接使用CSS变量实现动态颜色配置。
1. 自定义主题映射token颜色
通过monaco.editor.defineTheme创建或修改主题,添加自定义token的样式配置:
monaco.editor.defineTheme('custom-markdown-theme', { base: 'vs', // 基于现有主题(可选vs/vs-dark/hc-black) inherit: true, // 继承基础主题的其他样式 rules: [ { token: 'custom-special-line', foreground: '#ff4757', fontStyle: 'italic' }, // 使用CSS变量 { token: 'custom-keyword', foreground: 'var(--custom-keyword-color)', fontStyle: 'bold' } ], colors: { // 可选:配置编辑器其他区域颜色 'editor.background': '#f8f9fa' } }); // 应用自定义主题 monaco.editor.create(document.getElementById('container'), { value: '你的Markdown内容', language: 'markdown', theme: 'custom-markdown-theme' });
2. 定义CSS变量
在页面CSS中定义对应变量即可生效:
:root { --custom-keyword-color: #2ed573; }
关键注意事项
- 规则顺序:Monarch按数组顺序匹配,自定义规则必须放在可能覆盖它的规则前面(比如
||行规则要放在标题、列表等行规则之前) - 关键词匹配:使用
\b确保匹配完整单词,避免部分匹配(如不会匹配MyKeyword1abc) - CSS变量支持:Monarch完全兼容CSS变量,主题中使用
var(...)格式即可引用
内容的提问来源于stack exchange,提问作者darkhorse
相关产品推荐
相关产品推荐

