Static highlighting using CM v6

To implement a runmode-like functionality with CM6, use the @codemirror/highlight package like so

import {highlightTree, defaultHighlightStyle} from "@codemirror/highlight"
export function runmode(textContent: string, language: Language, callback: (text: string, style: string, from: number, to: number) => void, options?: Record<string, any>) {
  const tree = language.parseString(textContent);
  let pos = 0;
  highlightTree(tree, defaultHighlightStyle.match, (from, to, classes) => {
    from > pos && callback(textContent.slice(pos, from), null, pos, from);
    callback(textContent.slice(from, to), classes, from, to);
    pos = to;
  });
  pos != tree.length && callback(textContent.slice(pos, tree.length), null, pos, tree.length);
}

The reason why we need to keep a position state is because unstyled tokens are not emitted.

Note that in my experience, although dynamically loading languages is easier in CM6 because its given as es modules, I’ve found the overall bundle size required to replicate the runmode functionality larger because @codemirror/highlight depends on @codemirror/view and @codemirror/state but 1. that may be tree-shaking misconfiguration 2. if you’re highlighting in server, bundle size might not be a problem.

5 Likes