char-slop/berry

multipurpose self-modifiable agentic harness

git clone https://git.t4t.associates/char-slop/berry

Charlotte Sominitial commite6df845

main
2.2 KiB59 linesraw
1import type { HighlightReply, HighlightRequest } from "./highlight-worker.ts";
2
3let worker: Worker | null = null;
4let nextId = 0;
5const pending = new Map<number, PromiseWithResolvers<string | null>>();
6
7function spawnWorker(): Worker {
8  const spawned = new Worker(new URL("./highlight-worker.ts", import.meta.url), { type: "module" });
9  spawned.onmessage = ({ data }: MessageEvent<HighlightReply>) => {
10    const request = pending.get(data.id)!;
11    pending.delete(data.id);
12    if ("error" in data) request.reject(new Error(data.error));
13    else request.resolve(data.html);
14  };
15  // also fires if the script fails to load; respawn on next use rather than hang
16  spawned.onerror = (event) => {
17    spawned.terminate();
18    worker = null;
19    for (const request of pending.values()) request.reject(new Error(event.message));
20    pending.clear();
21  };
22  return spawned;
23}
24
25function splitHighlighted(nodes: Node[]): Node[][] {
26  const lines: Node[][] = [[]];
27  for (const node of nodes) {
28    let parts: Node[][];
29    if (node instanceof Text) {
30      parts = node.data.split("\n").map((text) => text ? [document.createTextNode(text)] : []);
31    } else if (node instanceof Element) {
32      parts = splitHighlighted([...node.childNodes]).map((children) => {
33        if (children.length === 0) return [];
34        const clone = node.cloneNode(false) as Element;
35        clone.append(...children);
36        return [clone];
37      });
38    } else {
39      parts = splitHighlighted([...node.childNodes]);
40    }
41    lines.at(-1)!.push(...parts[0]);
42    for (const part of parts.slice(1)) lines.push(part);
43  }
44  return lines;
45}
46
47/** `source` highlighted as `language`, line by line; `null` when arborium has no such grammar. */
48export async function highlightedLines(language: string, source: string): Promise<Node[][] | null> {
49  worker ??= spawnWorker();
50  const request = Promise.withResolvers<string | null>();
51  const id = nextId++;
52  pending.set(id, request);
53  worker.postMessage({ id, language, source } satisfies HighlightRequest);
54  const html = await request.promise;
55  if (html === null) return null;
56  const template = document.createElement("template");
57  template.innerHTML = html;
58  return splitHighlighted([...template.content.childNodes]);
59}