/** * Rendering a fence as coloured code, and a patch as a diff. * * `@pierre/diffs` does both, over Shiki, and is used only to draw: the source * of every block on this page stays where it was, as Lexical text children * under Yjs, and what is drawn here is a second, read-only view of it. The * library has an edit mode and it must not be turned on — it would put a * character model of its own beside the one the room is collaborating in, and * the two would disagree the moment two people typed. * * It arrives on demand. Shiki's grammars and this library together are larger * than everything else the editor loads, and a plan with no code in it should * pay none of it. * * A diff fence is a unified patch or it is not a diff. The parser is asked to * throw rather than to salvage, because half a patch rendered as a diff is a * change nobody made: the hunk headers are what carry the filename and the * line numbers, and inventing them from a loose run of `+` and `-` lines would * put both in the reader's head with nothing behind them. What it refuses is * shown as coloured diff text instead, which is what it is. */ import { Component, useEffect, useMemo, useState } from "react"; import { fileNameOf, repaired, titled } from "./code"; import type { ErrorInfo, ReactNode } from "react"; import type { Kind } from "./code"; type Core = typeof import("@pierre/diffs"); type Views = typeof import("@pierre/diffs/react"); type Renderer = { File: Views["File"]; FileDiff: Views["FileDiff"]; parsePatchFiles: Core["parsePatchFiles"]; resolveLanguage: Core["resolveLanguage"]; }; /** What the highlighter calls text it has no grammar for. */ const PLAIN = "text"; /** * One theme, named once. * * The page is light only — `theme.css` says so and carries no second palette — * so a `{ dark, light }` pair would load a second set of colours nothing can * ever ask for. */ const THEME = "pierre-light"; /** * Keeps the first file's change counts clear of the block's own controls, * which float over the top-end corner of the box this header sits in. */ function chromeRoom() { return