Skip to content

g1t/apps/web/app/lib/highlight.server.ts

69 lines2,510 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Usage, Billing settings and prepaid AI credit; fixes from the UX audit1import type { Comparison } from "@g1t/contracts";
2
3import type { HighlightedComparison, HighlightedFile } from "./diff";
4
Fast pages, required checks on the branch, self-hosted runners, honest incidents5// Shiki and its grammars load on the first file highlighted, not when the
6// Worker starts: most requests highlight nothing.
7const shiki = () => import("./shiki");
API and MCP server, Rust identity service, registration, site redesign8
9const MAX_HIGHLIGHT_CHARS = 200_000;
10
11/**
12 * Highlighted HTML for a file, or null when its language is unknown or it
13 * is too large, in which case the caller shows plain text.
14 */
Agents as a team: lifecycle, merge queue, billing and a new shell15export async function highlight(path: string, text: string): Promise<string | null> {
Fast pages, required checks on the branch, self-hosted runners, honest incidents16 const { THEME, getHighlighter, languageOf } = await shiki();
Agents as a team: lifecycle, merge queue, billing and a new shell17 const lang = languageOf(path);
18 if (!lang || text.length > MAX_HIGHLIGHT_CHARS) return null;
19 try {
20 return (await getHighlighter()).codeToHtml(text.replace(/\n$/, ""), { lang, theme: THEME });
21 } catch {
22 return null;
23 }
24}
25
26/**
27 * A file's lines as highlighted HTML, one string per line, or null when its
28 * language is unknown or it is too large.
29 */
30export async function highlightLines(path: string, text: string): Promise<string[] | null> {
Fast pages, required checks on the branch, self-hosted runners, honest incidents31 const { getHighlighter, languageOf, linesToHtml } = await shiki();
Agents as a team: lifecycle, merge queue, billing and a new shell32 const lang = languageOf(path);
API and MCP server, Rust identity service, registration, site redesign33 if (!lang || text.length > MAX_HIGHLIGHT_CHARS) return null;
34 try {
Agents as a team: lifecycle, merge queue, billing and a new shell35 return linesToHtml(await getHighlighter(), text.replace(/\n$/, ""), lang);
API and MCP server, Rust identity service, registration, site redesign36 } catch {
37 return null;
38 }
39}
Usage, Billing settings and prepaid AI credit; fixes from the UX audit40
41/**
42 * How much of a change is highlighted before the page is sent: its first
43 * screens. The rest is highlighted in the browser as it comes near
44 * (components/diff-view.tsx), so a large change never holds the page up.
45 */
46const FIRST_SCREENS_CHARS = 40_000;
47
48/**
49 * A comparison with its first files' lines highlighted, in order, until
50 * the budget runs out, so what is on screen when the page arrives already
51 * has its colours.
52 */
53export async function highlightFirstFiles(comparison: Comparison): Promise<HighlightedComparison> {
54 let budget = FIRST_SCREENS_CHARS;
55 const files: HighlightedFile[] = [];
56 for (const file of comparison.files) {
57 const size = file.hunks.reduce((sum, hunk) => sum + hunk.lines.reduce((n, line) => n + line.text.length + 1, 0), 0);
58 if (budget <= 0 || size > budget || file.binary) {
59 // Past the first screens: everything after it waits for the browser.
60 budget = 0;
61 files.push(file);
62 continue;
63 }
64 budget -= size;
65 const { highlightFile } = await shiki();
66 files.push((await highlightFile(file).catch(() => null)) ?? file);
67 }
68 return { ...comparison, files };
69}