Code blocks
Fenced blocks are syntax highlighted in edit-md and view modes. The
highlighter is the package's own: a small lexer driven by data-only
grammars (no Prism, highlight.js or Shiki in your bundle). A language is a
file of about 30 lines.
Built in: JavaScript / TypeScript, Kotlin, Java, C / C++, Python, Go, Rust,
JSON, YAML, shell, SQL, CSS, HTML / XML, diff and markdown, plus the usual
aliases (ts, tsx, kt, yml, sh, bash, …). BUILTIN_CODE_LANGUAGES
lists them and getCodeLanguages() returns the current registry.
Unknown languages and untagged blocks render as plain text with the same
line structure, so cursor movement and indentation behave identically.
Untagged blocks export as a bare ``` fence (the CODE_BLOCK
transformer does this; it replaces Lexical's CODE).
Type ``` (optionally followed by a language) and press Enter to
start a block.
Colours
Each token type has one class (zui-token-<type>) and one custom property
(--zui-code-<type> on .zui-code), with light defaults and .dark
overrides. Retheme by overriding the properties:
.zui-code {
--zui-code-keyword: #7c3aed;
--zui-code-string: #047857;
}
.dark .zui-code {
--zui-code-keyword: #c4b5fd;
}
Token types (CODE_TOKEN_TYPES): comment, string, number,
keyword, builtin, type, function, property, variable,
constant, operator, punctuation, tag, attr, regex, meta,
inserted, deleted. Operators and punctuation inherit the text colour on
purpose: fewer colours, calmer blocks. inserted / deleted (diff) also
get --zui-code-inserted-background / --zui-code-deleted-background.
The same block with a wrapper class that overrides five of the properties (purple keywords, green strings, blue functions), in both colour modes:
Adding a language
A grammar (CodeGrammar) is a list of ordered regex rules plus word lists.
Rules are regex sources (no capturing groups or backreferences;
unterminated strings should stop at the line end). Identifiers no rule
claims are classified by the lists, then by two optional heuristics.
Register it before the editor mounts:
import { registerCodeLanguage } from '@zuilib/text-editor'
registerCodeLanguage({
name: 'toml',
rules: [
{ type: 'comment', match: '#[^\\n]*' },
{ type: 'meta', match: '(?<=^|\\n)\\[[^\\]]*\\]' },
{ type: 'property', match: '(?<=^|\\n)[\\w.-]+(?=\\s*=)' },
{ type: 'string', match: '"(?:[^"\\\\\\n]|\\\\.)*"?' },
{ type: 'number', match: '\\b\\d[\\d_]*(?:\\.\\d+)?\\b' },
],
constants: ['true', 'false'],
})
Word lists: keywords, builtins, types, constants. Heuristics:
callIsFunction marks an identifier followed by ( as a function;
capitalizedIsType marks Capitalized identifiers as type and
SCREAMING_CASE ones as constant. aliases adds extra names for the
same grammar.
Outside the editor, tokenizeCode(code, grammar) returns the flat
CodeToken list, resolveCodeLanguage(name) resolves aliases,
hasCodeLanguage(name) checks the registry, and codeTokenizer is the
Lexical tokenizer adapter. registerCodeBlockHighlighting(editor) wires
highlighting into a Lexical editor you assemble yourself.