import hljs from "npm:highlight.js/lib/core"; import javascript from "npm:highlight.js/lib/languages/javascript"; import python from "npm:highlight.js/lib/languages/python"; import rust from "npm:highlight.js/lib/languages/rust"; import typescript from "npm:highlight.js/lib/languages/typescript"; hljs.registerLanguage("javascript", javascript); hljs.registerLanguage("rust", rust); hljs.registerLanguage("python", python); hljs.registerLanguage("typescript", typescript); export class ChatResponse { element = (
); currentLine: Text | undefined; codeBlockContext: Element | undefined; thinkingContext: HTMLDetailsElement | undefined; currentContext(): Element { if (this.codeBlockContext) return this.codeBlockContext; if (this.thinkingContext) return this.thinkingContext; return this.element; } finalizeLine() { if (!this.currentLine?.textContent) return; const line = this.currentLine.textContent; if (!this.thinkingContext && line === "") { this.thinkingContext = (
{``}
) as HTMLDetailsElement; this.element.append(this.thinkingContext); this.currentLine.remove(); } else if (this.thinkingContext && line === "
") { this.currentLine.remove(); this.thinkingContext.open = false; this.thinkingContext = undefined; } if (line.startsWith("```")) { const remainder = line.substring(3).trimStart(); this.currentLine.remove(); if (!this.codeBlockContext) { const pre = (
            
          
); this.currentContext().append(pre); this.codeBlockContext = pre.querySelector("code")!; } else { hljs.highlightElement(this.codeBlockContext as HTMLElement); // TODO: highlight.js the guy this.codeBlockContext = undefined; this.currentContext().append(remainder); } } } append(text: string) { const tokens = text .split(/(\s+)/) .flatMap(s => s.split(/(\n)/)) .filter(s => s); for (const token of tokens) { if (token === "\n") { if (!this.currentLine) continue; this.finalizeLine(); this.currentLine.appendData(token); this.currentLine = undefined; continue; } if (this.currentLine === undefined) { this.currentLine = document.createTextNode(token); this.currentContext().append(this.currentLine); } else { this.currentLine.appendData(token); } } } finalize() { this.finalizeLine(); // TODO: check if we have a dangling think section or code block and lift it back out } }