import { availableLanguages, detectLanguage as sniffLanguage, highlight } from "@arborium/arborium"; import { detectLanguage } from "./languages.ts"; const available = new Set(availableLanguages); function languageOf(path: string, source: string): string | null { const candidate = detectLanguage(path); if (candidate && available.has(candidate)) return candidate; const detected = sniffLanguage(source); return detected && available.has(detected) ? detected : null; } export async function highlightedHtml(path: string, source: string): Promise { const language = languageOf(path, source); return language ? await highlight(language, source) : null; } function splitHighlighted(nodes: Node[]): Node[][] { const lines: Node[][] = [[]]; for (const node of nodes) { let parts: Node[][]; if (node instanceof Text) { parts = node.data.split("\n").map(text => text ? [document.createTextNode(text)] : []); } else if (node instanceof Element) { parts = splitHighlighted([...node.childNodes]).map(children => { if (children.length === 0) return []; const clone = node.cloneNode(false) as Element; clone.append(...children); return [clone]; }); } else { parts = splitHighlighted([...node.childNodes]); } lines.at(-1)!.push(...parts[0]); for (const part of parts.slice(1)) lines.push(part); } return lines; } export async function highlightedLines(path: string, source: string): Promise { const html = await highlightedHtml(path, source); if (html === null) return null; const template = document.createElement("template"); template.innerHTML = html; return splitHighlighted([...template.content.childNodes]); }