char/sorcery
static-files based git repo viewer
git clone https://git.t4t.associates/char/sorcery
f92b8f4
main
1import { availableLanguages , detectLanguage as sniffLanguage , highlight } from "@arborium/arborium" ; 2import { detectLanguage } from "./languages.ts" ; 3 4const available = new Set < string >( availableLanguages ); 5 6function languageOf ( path :string , source :string ) :string | null { 7const candidate = detectLanguage ( path ); 8if ( candidate && available . has ( candidate )) return candidate ; 9const detected = sniffLanguage ( source ); 10return detected && available . has ( detected ) ?detected :null ; 11} 12 13export async function highlightedHtml ( path :string , source :string ) :Promise < string | null > { 14const language = languageOf ( path , source ); 15return language ?await highlight ( language , source ) :null ; 16} 17 18function splitHighlighted ( nodes :Node []) :Node [][] { 19const lines :Node [][] = [[]]; 20for ( const node of nodes ) { 21let parts :Node [][]; 22if ( node instanceof Text ) { 23parts = node . data . split ( "\n" ). map ( text => text ?[ document . createTextNode ( text )] :[]); 24} else if ( node instanceof Element ) { 25parts = splitHighlighted ([ ...node . childNodes ]). map ( children => { 26if ( children . length === 0 ) return []; 27const clone = node . cloneNode ( false ) as Element ; 28clone . append ( ...children ); 29return [ clone ]; 30}); 31} else { 32parts = splitHighlighted ([ ...node . childNodes ]); 33} 34lines . at ( - 1 ) ! . push ( ...parts [ 0 ]); 35for ( const part of parts . slice ( 1 )) lines . push ( part ); 36} 37return lines ; 38} 39 40export async function highlightedLines ( path :string , source :string ) :Promise < Node [][] | null > { 41const html = await highlightedHtml ( path , source ); 42if ( html === null ) return null ; 43const template = document . createElement ( "template" ); 44template . innerHTML = html ; 45return splitHighlighted ([ ...template . content . childNodes ]); 46}