diff --git a/services/web/frontend/js/features/source-editor/extensions/class-highlighter.ts b/services/web/frontend/js/features/source-editor/extensions/class-highlighter.ts index 895b29b4a9..afef81b233 100644 --- a/services/web/frontend/js/features/source-editor/extensions/class-highlighter.ts +++ b/services/web/frontend/js/features/source-editor/extensions/class-highlighter.ts @@ -46,5 +46,6 @@ export const classHighlighter = tagHighlighter([ { tag: tags.invalid, class: 'tok-invalid' }, { tag: tags.punctuation, class: 'tok-punctuation' }, // additional + { tag: tags.attributeName, class: 'tok-attributeName' }, { tag: tags.attributeValue, class: 'tok-attributeValue' }, ]) diff --git a/services/web/frontend/js/features/source-editor/lezer-typst/tokens.mjs b/services/web/frontend/js/features/source-editor/lezer-typst/tokens.mjs index 54d6b26668..a29d433106 100644 --- a/services/web/frontend/js/features/source-editor/lezer-typst/tokens.mjs +++ b/services/web/frontend/js/features/source-editor/lezer-typst/tokens.mjs @@ -321,12 +321,17 @@ export const codeIdentTokenizer = new ExternalTokenizer( if (!stack.canShift(CodeIdent)) return // Guard: only fire in code context. - // Walk back past whitespace (including newlines inside multi-line arg lists) - // to the nearest non-space character and check that it is a code-mode delimiter. + // Walk back past whitespace to the nearest non-space character. let back = -1 while (input.peek(back) === SPACE || input.peek(back) === TAB || input.peek(back) === NEWLINE) back-- const prev = input.peek(back) - if (prev !== HASH && prev !== DOT && prev !== OPEN_PAREN && prev !== COMMA) return + if (prev !== HASH && prev !== DOT && prev !== OPEN_PAREN && prev !== COMMA) { + // May be after a keyword like '#set' or '#show': scan back through the + // keyword word itself and check that '#' immediately precedes it. + if (!isIdentTail(prev)) return + while (isIdentTail(input.peek(back))) back-- + if (input.peek(back) !== HASH) return + } // Must start with an identifier head character. if (!isIdentHead(input.next)) return