();
useEffect(() => {
let live = true;
load().then(
value => {
if (live) setRenderer(value);
},
error => {
console.error("[plan] could not load the code renderer:", error);
if (live) setBroken(true);
},
);
return () => {
live = false;
};
}, []);
useEffect(() => {
if (!renderer) return;
let live = true;
void grammar(language, renderer.resolveLanguage).then(value => {
if (live) setResolved(value);
});
return () => {
live = false;
};
}, [renderer, language]);
/*
* Everything handed to the library is memoised, and not as a courtesy: it
* compares by reference to decide whether anything changed, so a fresh
* object on every keystroke elsewhere in the plan would re-render and
* re-highlight every block on the page.
*/
let file = useMemo(
() => ({ name: fileNameOf(language, meta), contents: source, lang: resolved ?? PLAIN }),
[language, meta, source, resolved],
);
let patch = useMemo(() => {
if (kind !== "diff" || !renderer) return undefined;
try {
let read = renderer.parsePatchFiles(repaired(source), undefined, true);
let files = read.flatMap(patch => patch.files);
return files.length > 0 ? files : undefined;
} catch {
// Not a patch. Said by the parser rather than guessed at here,
// which is the only reading of the format that cannot drift.
return undefined;
}
}, [kind, renderer, source]);
let options = useMemo(
() => ({
theme: THEME,
themeType: "light" as const,
// A diff's fallback has no title in the block's own header.
disableFileHeader: kind !== "diff" || !titled(meta),
disableLineNumbers: true,
overflow: "scroll" as const,
disableWorkerPool: true,
}),
[kind, meta],
);
let diffOptions = useMemo(
() => ({
theme: THEME,
themeType: "light" as const,
// Three panes wide, so side by side would be two unreadable
// columns. The filename comes from the patch and is the whole
// point of rendering one, so its header stays.
diffStyle: "unified" as const,
/*
* A patch carries only what it changed, so there is nothing to
* expand into: the separator that offers to expand would be a
* control that cannot work. `metadata` says `@@ -60,6 +60,22 @@`,
* which is what the source says too.
*/
hunkSeparators: "metadata" as const,
overflow: "scroll" as const,
disableWorkerPool: true,
}),
[],
);
if (broken) return could not be rendered
;
// Nothing yet. Drawing a box the height of the eventual render would move
// the prose under it twice; the source is on screen throughout.
if (!renderer) return null;
let { File, FileDiff } = renderer;
return (
{patch
? patch.map((fileDiff, index) => (
))
: }
);
}