From ae522dfee400e4f52dcfb53965f0baa7e1e06ab2 Mon Sep 17 00:00:00 2001 From: Jinjing <6427696+AmethystLiang@users.noreply.github.com> Date: Fri, 13 Nov 2026 14:50:41 -0800 Subject: [PATCH] fix(markdown): highlight YAML frontmatter in the source editor The markdown grammar's frontMatter rule embeds source.yaml at the start of the document, but Orca loaded YAML only when a ```yaml fence label was seen, so frontmatter stayed plain text. Load the YAML grammar together with markdown. Fixes #41658 Co-authored-by: Garrett Peppers --- .../markdown-textmate-tokens.test.ts | 28 +++++++++++++++++++ .../markdown-textmate-tokens.ts | 7 +++-- 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 src/renderer/src/lib/monaco-languages/markdown-textmate-tokens.test.ts diff --git a/src/renderer/src/lib/monaco-languages/markdown-textmate-tokens.test.ts b/src/renderer/src/lib/monaco-languages/markdown-textmate-tokens.test.ts new file mode 100644 index 00000000000..57fa2a8f6c4 --- /dev/null +++ b/src/renderer/src/lib/monaco-languages/markdown-textmate-tokens.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, it, vi } from 'vitest' +import { loadNodeOniguruma } from '../syntax-highlighting/oniguruma-test-harness' +import { createMarkdownTokensProvider } from './markdown-textmate-tokens' + +vi.mock('../syntax-highlighting/oniguruma', () => ({ loadOniguruma: loadNodeOniguruma })) + +describe('markdown tokenization', () => { + it('colors frontmatter as YAML on first paint, then returns to markdown', async () => { + const provider = await createMarkdownTokensProvider({ + editor: { defineTheme: vi.fn() }, + languages: { setTokensProvider: vi.fn() } + }) + let state = provider.getInitialState() + const tokens = ['---', 'name: "Orca"', 'enabled: true # flag', '---', '# Heading'].map( + (line) => { + const result = provider.tokenize(line, state) + state = result.endState + return result.tokens + } + ) + + expect(tokens[1]).toContainEqual({ startIndex: 0, scopes: 'md.entity.name.tag.yaml' }) + expect(tokens[1]).toContainEqual({ startIndex: 6, scopes: 'md.string.quoted.double.yaml' }) + expect(tokens[2]).toContainEqual({ startIndex: 9, scopes: 'md.constant.language.boolean.yaml' }) + expect(tokens[2]).toContainEqual({ startIndex: 14, scopes: 'md.comment.line.number-sign.yaml' }) + expect(tokens[4]).toContainEqual({ startIndex: 2, scopes: 'md.entity.name.section.markdown' }) + }) +}) diff --git a/src/renderer/src/lib/monaco-languages/markdown-textmate-tokens.ts b/src/renderer/src/lib/monaco-languages/markdown-textmate-tokens.ts index 8c134d3c77d..42be53ca397 100644 --- a/src/renderer/src/lib/monaco-languages/markdown-textmate-tokens.ts +++ b/src/renderer/src/lib/monaco-languages/markdown-textmate-tokens.ts @@ -49,24 +49,27 @@ function fenceLanguagesByLabel( return byLabel } -/** VS Code's markdown grammar with Dark+/Light+ colors; fence grammars load on first sight. */ +/** VS Code's markdown grammar with Dark+/Light+ colors; YAML loads up front for frontmatter, fence grammars on first sight. */ export async function createMarkdownTokensProvider( monaco: MonacoModule ): Promise { const [ editorCore, { default: markdownGrammars }, + { default: yamlGrammars }, { bundledLanguagesInfo }, { rules: darkRules }, { rules: lightRules } ] = await Promise.all([ loadEditorCore(), import('shiki/langs/markdown.mjs'), + import('shiki/langs/yaml.mjs'), import('shiki/langs'), loadBuiltInMarkdownRules('dark'), loadBuiltInMarkdownRules('light') ]) - await editorCore.core.loadLanguage(...markdownGrammars) + // Why: frontmatter embeds YAML at the document start, with no fence label to trigger a lazy load. + await editorCore.core.loadLanguage(...markdownGrammars, ...yamlGrammars) // Why: Orca's editors all use the built-in theme names; redefining them keeps every setTheme caller unchanged. monaco.editor.defineTheme('vs-dark', {