@opentui/core 0.1.24 → 0.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/3d.js +1 -1
  2. package/README.md +5 -1
  3. package/Renderable.d.ts +18 -8
  4. package/animation/Timeline.d.ts +2 -1
  5. package/ansi.d.ts +2 -17
  6. package/assets/javascript/highlights.scm +205 -0
  7. package/assets/javascript/tree-sitter-javascript.wasm +0 -0
  8. package/assets/typescript/highlights.scm +604 -0
  9. package/assets/typescript/tree-sitter-typescript.wasm +0 -0
  10. package/{index-0yx9rnxg.js → index-pxa2sv92.js} +1798 -258
  11. package/index-pxa2sv92.js.map +52 -0
  12. package/index.js +449 -246
  13. package/index.js.map +15 -13
  14. package/lib/KeyHandler.d.ts +51 -9
  15. package/lib/data-paths.d.ts +26 -0
  16. package/lib/debounce.d.ts +42 -0
  17. package/lib/env.d.ts +42 -0
  18. package/lib/hast-styled-text.d.ts +3 -23
  19. package/lib/index.d.ts +6 -0
  20. package/lib/parse.keypress.d.ts +2 -2
  21. package/lib/queue.d.ts +15 -0
  22. package/lib/scroll-acceleration.d.ts +43 -0
  23. package/{singleton.d.ts → lib/singleton.d.ts} +2 -0
  24. package/lib/styled-text.d.ts +0 -15
  25. package/lib/syntax-style.d.ts +36 -0
  26. package/lib/tree-sitter/assets/update.d.ts +11 -0
  27. package/lib/tree-sitter/client.d.ts +46 -0
  28. package/lib/tree-sitter/default-parsers.d.ts +2 -0
  29. package/lib/tree-sitter/download-utils.d.ts +21 -0
  30. package/lib/tree-sitter/index.d.ts +10 -0
  31. package/lib/tree-sitter/parser.worker.d.ts +1 -0
  32. package/lib/tree-sitter/resolve-ft.d.ts +2 -0
  33. package/lib/tree-sitter/types.d.ts +64 -0
  34. package/lib/tree-sitter-styled-text.d.ts +7 -0
  35. package/lib/validate-dir-name.d.ts +1 -0
  36. package/package.json +21 -8
  37. package/parser.worker.js +640 -0
  38. package/parser.worker.js.map +11 -0
  39. package/renderables/ASCIIFont.d.ts +1 -1
  40. package/renderables/Code.d.ts +31 -0
  41. package/renderables/Input.d.ts +4 -4
  42. package/renderables/ScrollBar.d.ts +2 -2
  43. package/renderables/ScrollBox.d.ts +7 -3
  44. package/renderables/Select.d.ts +2 -2
  45. package/renderables/TabSelect.d.ts +2 -2
  46. package/renderables/Text.d.ts +11 -65
  47. package/renderables/TextBufferRenderable.d.ts +81 -0
  48. package/renderables/TextNode.d.ts +1 -0
  49. package/renderables/index.d.ts +2 -0
  50. package/renderer.d.ts +5 -3
  51. package/testing/mock-keys.d.ts +1 -0
  52. package/testing/spy.d.ts +7 -0
  53. package/testing/test-renderer.d.ts +1 -0
  54. package/testing.d.ts +1 -0
  55. package/testing.js +31 -6
  56. package/testing.js.map +6 -5
  57. package/types.d.ts +2 -1
  58. package/zig.d.ts +1 -0
  59. package/index-0yx9rnxg.js.map +0 -38
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/lib/tree-sitter/parser.worker.ts", "../src/lib/tree-sitter/download-utils.ts"],
4
+ "sourcesContent": [
5
+ "import { Parser, Query, Tree, Language } from \"web-tree-sitter\"\nimport type { Edit, QueryCapture, Range } from \"web-tree-sitter\"\nimport { mkdir } from \"fs/promises\"\nimport * as path from \"path\"\nimport type {\n HighlightRange,\n HighlightResponse,\n SimpleHighlight,\n FiletypeParserOptions,\n PerformanceStats,\n} from \"./types\"\nimport { DownloadUtils } from \"./download-utils\"\nimport { isMainThread } from \"worker_threads\"\n\nconst self = globalThis\n\ntype ParserState = {\n parser: Parser\n tree: Tree\n queries: {\n highlights: Query\n }\n}\n\ninterface FiletypeParser {\n filetype: string\n queries: {\n highlights: Query\n }\n language: Language\n}\n\ninterface ReusableParserState {\n parser: Parser\n filetypeParser: FiletypeParser\n}\n\nclass ParserWorker {\n private bufferParsers: Map<number, ParserState> = new Map()\n private filetypeParserOptions: Map<string, FiletypeParserOptions> = new Map()\n private filetypeParsers: Map<string, FiletypeParser> = new Map()\n private filetypeParserPromises: Map<string, Promise<FiletypeParser | undefined>> = new Map()\n private reusableParsers: Map<string, ReusableParserState> = new Map()\n private reusableParserPromises: Map<string, Promise<ReusableParserState | undefined>> = new Map()\n private initializePromise: Promise<void> | undefined\n public performance: PerformanceStats\n private dataPath: string | undefined\n private initialized: boolean = false\n\n constructor() {\n this.performance = {\n averageParseTime: 0,\n parseTimes: [],\n averageQueryTime: 0,\n queryTimes: [],\n }\n }\n\n private async fetchHighlightQueries(sources: string[], filetype: string): Promise<string> {\n if (!this.dataPath) {\n return \"\"\n }\n return DownloadUtils.fetchHighlightQueries(sources, this.dataPath, filetype)\n }\n\n async initialize({ dataPath }: { dataPath: string }) {\n if (this.initializePromise) {\n return this.initializePromise\n }\n this.initializePromise = new Promise(async (resolve, reject) => {\n this.dataPath = dataPath\n\n try {\n await mkdir(path.join(dataPath, \"languages\"), { recursive: true })\n await mkdir(path.join(dataPath, \"queries\"), { recursive: true })\n\n let { default: treeWasm } = await import(\"web-tree-sitter/web-tree-sitter.wasm\" as string, {\n with: { type: \"wasm\" },\n })\n\n if (/\\$bunfs/.test(treeWasm)) {\n treeWasm = \"/$bunfs/root/\" + path.parse(treeWasm).base\n }\n\n await Parser.init({\n locateFile() {\n return treeWasm\n },\n })\n\n this.initialized = true\n resolve()\n } catch (error) {\n reject(error)\n }\n })\n return this.initializePromise\n }\n\n public addFiletypeParser(filetypeParser: FiletypeParserOptions) {\n this.filetypeParserOptions.set(filetypeParser.filetype, filetypeParser)\n }\n\n private async createQueries(\n filetypeParser: FiletypeParserOptions,\n language: Language,\n ): Promise<\n | {\n highlights: Query\n }\n | undefined\n > {\n try {\n // Fetch all highlight queries from URLs/paths and concatenate them\n const highlightQueryContent = await this.fetchHighlightQueries(\n filetypeParser.queries.highlights,\n filetypeParser.filetype,\n )\n if (!highlightQueryContent) {\n console.error(\"Failed to fetch highlight queries for:\", filetypeParser.filetype)\n return undefined\n }\n\n const query = new Query(language, highlightQueryContent)\n return {\n highlights: query,\n }\n } catch (error) {\n console.error(error)\n return undefined\n }\n }\n\n private async loadLanguage(languageSource: string): Promise<Language | undefined> {\n if (!this.initialized || !this.dataPath) {\n return undefined\n }\n\n const result = await DownloadUtils.downloadOrLoad(languageSource, this.dataPath, \"languages\", \".wasm\", false)\n\n if (result.error) {\n console.error(`Error loading language ${languageSource}:`, result.error)\n return undefined\n }\n\n if (!result.filePath) {\n return undefined\n }\n\n try {\n const language = await Language.load(result.filePath)\n return language\n } catch (error) {\n console.error(`Error loading language from ${result.filePath}:`, error)\n return undefined\n }\n }\n\n private async resolveFiletypeParser(filetype: string): Promise<FiletypeParser | undefined> {\n if (this.filetypeParsers.has(filetype)) {\n return this.filetypeParsers.get(filetype)\n }\n\n if (this.filetypeParserPromises.has(filetype)) {\n return this.filetypeParserPromises.get(filetype)\n }\n\n const loadingPromise = this.loadFiletypeParser(filetype)\n this.filetypeParserPromises.set(filetype, loadingPromise)\n\n try {\n const result = await loadingPromise\n if (result) {\n this.filetypeParsers.set(filetype, result)\n }\n return result\n } finally {\n this.filetypeParserPromises.delete(filetype)\n }\n }\n\n private async loadFiletypeParser(filetype: string): Promise<FiletypeParser | undefined> {\n const filetypeParserOptions = this.filetypeParserOptions.get(filetype)\n if (!filetypeParserOptions) {\n return undefined\n }\n const language = await this.loadLanguage(filetypeParserOptions.wasm)\n if (!language) {\n return undefined\n }\n const queries = await this.createQueries(filetypeParserOptions, language)\n if (!queries) {\n console.error(\"Failed to create queries for:\", filetype)\n return undefined\n }\n const filetypeParser: FiletypeParser = {\n ...filetypeParserOptions,\n queries,\n language,\n }\n return filetypeParser\n }\n\n public async preloadParser(filetype: string) {\n return this.resolveFiletypeParser(filetype)\n }\n\n private async getReusableParser(filetype: string): Promise<ReusableParserState | undefined> {\n if (this.reusableParsers.has(filetype)) {\n return this.reusableParsers.get(filetype)\n }\n\n if (this.reusableParserPromises.has(filetype)) {\n return this.reusableParserPromises.get(filetype)\n }\n\n const creationPromise = this.createReusableParser(filetype)\n this.reusableParserPromises.set(filetype, creationPromise)\n\n try {\n const result = await creationPromise\n if (result) {\n this.reusableParsers.set(filetype, result)\n }\n return result\n } finally {\n this.reusableParserPromises.delete(filetype)\n }\n }\n\n private async createReusableParser(filetype: string): Promise<ReusableParserState | undefined> {\n const filetypeParser = await this.resolveFiletypeParser(filetype)\n if (!filetypeParser) {\n return undefined\n }\n\n const parser = new Parser()\n parser.setLanguage(filetypeParser.language)\n\n const reusableState: ReusableParserState = {\n parser,\n filetypeParser,\n }\n\n return reusableState\n }\n\n async handleInitializeParser(\n bufferId: number,\n version: number,\n content: string,\n filetype: string,\n messageId: string,\n ) {\n const filetypeParser = await this.resolveFiletypeParser(filetype)\n\n if (!filetypeParser) {\n self.postMessage({\n type: \"PARSER_INIT_RESPONSE\",\n bufferId,\n messageId,\n hasParser: false,\n warning: `No parser available for filetype ${filetype}`,\n })\n return\n }\n\n const parser = new Parser()\n parser.setLanguage(filetypeParser.language)\n const tree = parser.parse(content)\n if (!tree) {\n self.postMessage({\n type: \"PARSER_INIT_RESPONSE\",\n bufferId,\n messageId,\n hasParser: false,\n error: \"Failed to parse buffer\",\n })\n return\n }\n\n const parserState = { parser, tree, queries: filetypeParser.queries }\n this.bufferParsers.set(bufferId, parserState)\n\n self.postMessage({\n type: \"PARSER_INIT_RESPONSE\",\n bufferId,\n messageId,\n hasParser: true,\n })\n const highlights = this.initialQuery(parserState)\n self.postMessage({\n type: \"HIGHLIGHT_RESPONSE\",\n bufferId,\n version,\n ...highlights,\n })\n }\n\n private initialQuery(parserState: ParserState) {\n const query = parserState.queries.highlights\n const matches: QueryCapture[] = query.captures(parserState.tree.rootNode)\n return this.getHighlights(parserState, matches)\n }\n\n private editToRange(edit: Edit): Range {\n return {\n startPosition: {\n column: edit.startPosition.column,\n row: edit.startPosition.row,\n },\n endPosition: {\n column: edit.newEndPosition.column,\n row: edit.newEndPosition.row,\n },\n startIndex: edit.startIndex,\n endIndex: edit.newEndIndex,\n }\n }\n\n async handleEdits(\n bufferId: number,\n content: string,\n edits: Edit[],\n ): Promise<{ highlights?: HighlightResponse[]; warning?: string; error?: string }> {\n const parserState = this.bufferParsers.get(bufferId)\n if (!parserState) {\n return { warning: \"No parser state found for buffer\" }\n }\n\n for (const edit of edits) {\n parserState.tree.edit(edit)\n }\n\n // Parse the buffer\n const startParse = performance.now()\n\n const newTree = parserState.parser.parse(content, parserState.tree)\n\n const endParse = performance.now()\n const parseTime = endParse - startParse\n this.performance.parseTimes.push(parseTime)\n if (this.performance.parseTimes.length > 10) {\n this.performance.parseTimes.shift()\n }\n this.performance.averageParseTime =\n this.performance.parseTimes.reduce((acc, time) => acc + time, 0) / this.performance.parseTimes.length\n\n if (!newTree) {\n return { error: \"Failed to parse buffer\" }\n }\n\n const changedRanges = parserState.tree.getChangedRanges(newTree)\n parserState.tree = newTree\n\n const startQuery = performance.now()\n const matches: QueryCapture[] = []\n\n // If no changed ranges detected, use the edit ranges as fallback\n if (changedRanges.length === 0) {\n edits.forEach((edit) => {\n const range = this.editToRange(edit)\n changedRanges.push(range)\n })\n }\n\n for (const range of changedRanges) {\n let node = parserState.tree.rootNode.descendantForPosition(range.startPosition, range.endPosition)\n\n if (!node) {\n continue\n }\n\n // If we got the root node, query with range to limit scope\n if (node.equals(parserState.tree.rootNode)) {\n // WHY ARE RANGES NOT WORKING!?\n // The changed ranges are not returning anything in some cases\n // Even this shit somehow returns many lines before the actual range,\n // and even though expanded by 1000 bytes it does not capture much beyond the actual range.\n // So freaking weird.\n const rangeCaptures = parserState.queries.highlights.captures(\n node,\n // WTF!?\n {\n startIndex: range.startIndex - 100,\n endIndex: range.endIndex + 1000,\n },\n )\n matches.push(...rangeCaptures)\n continue\n }\n\n // For smaller nodes, walk up until we find a node that fully contains the range\n while (node && !this.nodeContainsRange(node, range)) {\n node = node.parent\n }\n\n if (!node) {\n node = parserState.tree.rootNode\n }\n\n const nodeCaptures = parserState.queries.highlights.captures(node)\n matches.push(...nodeCaptures)\n }\n\n const endQuery = performance.now()\n const queryTime = endQuery - startQuery\n this.performance.queryTimes.push(queryTime)\n if (this.performance.queryTimes.length > 10) {\n this.performance.queryTimes.shift()\n }\n this.performance.averageQueryTime =\n this.performance.queryTimes.reduce((acc, time) => acc + time, 0) / this.performance.queryTimes.length\n\n return this.getHighlights(parserState, matches)\n }\n\n private nodeContainsRange(node: any, range: any): boolean {\n return (\n node.startPosition.row <= range.startPosition.row &&\n node.endPosition.row >= range.endPosition.row &&\n (node.startPosition.row < range.startPosition.row || node.startPosition.column <= range.startPosition.column) &&\n (node.endPosition.row > range.endPosition.row || node.endPosition.column >= range.endPosition.column)\n )\n }\n\n private getHighlights(parserState: ParserState, matches: QueryCapture[]): { highlights: HighlightResponse[] } {\n const lineHighlights: Map<number, Map<number, HighlightRange>> = new Map()\n const droppedHighlights: Map<number, Map<number, HighlightRange>> = new Map()\n\n for (const match of matches) {\n const node = match.node\n const startLine = node.startPosition.row\n const endLine = node.endPosition.row\n\n const highlight = {\n startCol: node.startPosition.column,\n endCol: node.endPosition.column,\n group: match.name,\n }\n\n if (!lineHighlights.has(startLine)) {\n lineHighlights.set(startLine, new Map())\n droppedHighlights.set(startLine, new Map())\n }\n if (lineHighlights.get(startLine)?.has(node.id)) {\n droppedHighlights.get(startLine)?.set(node.id, lineHighlights.get(startLine)?.get(node.id)!)\n }\n lineHighlights.get(startLine)?.set(node.id, highlight)\n\n if (startLine !== endLine) {\n for (let line = startLine + 1; line <= endLine; line++) {\n if (!lineHighlights.has(line)) {\n lineHighlights.set(line, new Map())\n }\n const hl: HighlightRange = {\n startCol: 0,\n endCol: node.endPosition.column,\n group: match.name,\n }\n lineHighlights.get(line)?.set(node.id, hl)\n }\n }\n }\n\n return {\n highlights: Array.from(lineHighlights.entries()).map(([line, lineHighlights]) => ({\n line,\n highlights: Array.from(lineHighlights.values()),\n droppedHighlights: droppedHighlights.get(line) ? Array.from(droppedHighlights.get(line)!.values()) : [],\n })),\n }\n }\n\n private getSimpleHighlights(matches: QueryCapture[]): SimpleHighlight[] {\n const highlights: SimpleHighlight[] = []\n\n for (const match of matches) {\n const node = match.node\n highlights.push([node.startIndex, node.endIndex, match.name])\n }\n\n return highlights\n }\n\n async handleResetBuffer(\n bufferId: number,\n version: number,\n content: string,\n ): Promise<{ highlights?: HighlightResponse[]; warning?: string; error?: string }> {\n const parserState = this.bufferParsers.get(bufferId)\n if (!parserState) {\n return { warning: \"No parser state found for buffer\" }\n }\n\n const newTree = parserState.parser.parse(content)\n\n if (!newTree) {\n return { error: \"Failed to parse buffer during reset\" }\n }\n\n parserState.tree = newTree\n const matches = parserState.queries.highlights.captures(parserState.tree.rootNode)\n\n return this.getHighlights(parserState, matches)\n }\n\n disposeBuffer(bufferId: number): void {\n const parserState = this.bufferParsers.get(bufferId)\n if (!parserState) {\n return\n }\n\n parserState.tree.delete()\n parserState.parser.delete()\n\n this.bufferParsers.delete(bufferId)\n }\n\n async handleOneShotHighlight(content: string, filetype: string, messageId: string): Promise<void> {\n const reusableState = await this.getReusableParser(filetype)\n\n if (!reusableState) {\n self.postMessage({\n type: \"ONESHOT_HIGHLIGHT_RESPONSE\",\n messageId,\n hasParser: false,\n warning: `No parser available for filetype ${filetype}`,\n })\n return\n }\n\n const tree = reusableState.parser.parse(content)\n\n if (!tree) {\n self.postMessage({\n type: \"ONESHOT_HIGHLIGHT_RESPONSE\",\n messageId,\n hasParser: false,\n error: \"Failed to parse content\",\n })\n return\n }\n\n try {\n const matches = reusableState.filetypeParser.queries.highlights.captures(tree.rootNode)\n const highlights = this.getSimpleHighlights(matches)\n\n self.postMessage({\n type: \"ONESHOT_HIGHLIGHT_RESPONSE\",\n messageId,\n hasParser: true,\n highlights,\n })\n } finally {\n tree.delete()\n }\n }\n\n async updateDataPath(dataPath: string): Promise<void> {\n this.dataPath = dataPath\n\n try {\n await mkdir(path.join(dataPath, \"languages\"), { recursive: true })\n await mkdir(path.join(dataPath, \"queries\"), { recursive: true })\n } catch (error) {\n throw new Error(`Failed to update data path: ${error}`)\n }\n }\n}\nif (!isMainThread) {\n const worker = new ParserWorker()\n\n function logMessage(type: \"log\" | \"error\", ...args: any[]) {\n self.postMessage({\n type: \"WORKER_LOG\",\n logType: type,\n data: args,\n })\n }\n console.log = (...args) => logMessage(\"log\", ...args)\n console.error = (...args) => logMessage(\"error\", ...args)\n\n // @ts-ignore - we'll fix this in the future for sure\n self.onmessage = async (e: MessageEvent) => {\n const { type, bufferId, version, content, filetype, edits, filetypeParser, messageId, dataPath } = e.data\n\n try {\n switch (type) {\n case \"INIT\":\n try {\n await worker.initialize({ dataPath })\n self.postMessage({ type: \"INIT_RESPONSE\" })\n } catch (error) {\n self.postMessage({\n type: \"INIT_RESPONSE\",\n error: error instanceof Error ? error.stack || error.message : String(error),\n })\n }\n break\n\n case \"ADD_FILETYPE_PARSER\":\n worker.addFiletypeParser(filetypeParser)\n break\n\n case \"PRELOAD_PARSER\":\n const maybeParser = await worker.preloadParser(filetype)\n self.postMessage({ type: \"PRELOAD_PARSER_RESPONSE\", messageId, hasParser: !!maybeParser })\n break\n\n case \"INITIALIZE_PARSER\":\n await worker.handleInitializeParser(bufferId, version, content, filetype, messageId)\n break\n\n case \"HANDLE_EDITS\":\n const response = await worker.handleEdits(bufferId, content, edits)\n if (response.highlights && response.highlights.length > 0) {\n self.postMessage({ type: \"HIGHLIGHT_RESPONSE\", bufferId, version, ...response })\n } else if (response.warning) {\n self.postMessage({ type: \"WARNING\", bufferId, warning: response.warning })\n } else if (response.error) {\n self.postMessage({ type: \"ERROR\", bufferId, error: response.error })\n }\n break\n\n case \"GET_PERFORMANCE\":\n self.postMessage({ type: \"PERFORMANCE_RESPONSE\", performance: worker.performance, messageId })\n break\n\n case \"RESET_BUFFER\":\n const resetResponse = await worker.handleResetBuffer(bufferId, version, content)\n if (resetResponse.highlights && resetResponse.highlights.length > 0) {\n self.postMessage({ type: \"HIGHLIGHT_RESPONSE\", bufferId, version, ...resetResponse })\n } else if (resetResponse.warning) {\n self.postMessage({ type: \"WARNING\", bufferId, warning: resetResponse.warning })\n } else if (resetResponse.error) {\n self.postMessage({ type: \"ERROR\", bufferId, error: resetResponse.error })\n }\n break\n\n case \"DISPOSE_BUFFER\":\n worker.disposeBuffer(bufferId)\n self.postMessage({ type: \"BUFFER_DISPOSED\", bufferId })\n break\n\n case \"ONESHOT_HIGHLIGHT\":\n await worker.handleOneShotHighlight(content, filetype, messageId)\n break\n\n case \"UPDATE_DATA_PATH\":\n try {\n await worker.updateDataPath(dataPath)\n self.postMessage({ type: \"UPDATE_DATA_PATH_RESPONSE\", messageId })\n } catch (error) {\n self.postMessage({\n type: \"UPDATE_DATA_PATH_RESPONSE\",\n messageId,\n error: error instanceof Error ? error.message : String(error),\n })\n }\n break\n\n default:\n self.postMessage({\n type: \"ERROR\",\n bufferId,\n error: `Unknown message type: ${type}`,\n })\n }\n } catch (error) {\n self.postMessage({\n type: \"ERROR\",\n bufferId,\n error: error instanceof Error ? error.stack || error.message : String(error),\n })\n }\n }\n}\n",
6
+ "import { mkdir, writeFile } from \"fs/promises\"\nimport * as path from \"path\"\n\nexport interface DownloadResult {\n content?: ArrayBuffer\n filePath?: string\n error?: string\n}\n\nexport class DownloadUtils {\n private static hashUrl(url: string): string {\n let hash = 0\n for (let i = 0; i < url.length; i++) {\n const char = url.charCodeAt(i)\n hash = (hash << 5) - hash + char\n hash = hash & hash\n }\n return Math.abs(hash).toString(16)\n }\n\n /**\n * Download a file from URL or load from local path, with caching support\n */\n static async downloadOrLoad(\n source: string,\n cacheDir: string,\n cacheSubdir: string,\n fileExtension: string,\n useHashForCache: boolean = true,\n filetype?: string,\n ): Promise<DownloadResult> {\n const isUrl = source.startsWith(\"http://\") || source.startsWith(\"https://\")\n\n if (isUrl) {\n let cacheFileName: string\n if (useHashForCache) {\n const hash = this.hashUrl(source)\n cacheFileName = filetype ? `${filetype}-${hash}${fileExtension}` : `${hash}${fileExtension}`\n } else {\n cacheFileName = path.basename(source)\n }\n const cacheFile = path.join(cacheDir, cacheSubdir, cacheFileName)\n\n // Ensure cache directory exists\n await mkdir(path.dirname(cacheFile), { recursive: true })\n\n try {\n const cachedContent = await Bun.file(cacheFile).arrayBuffer()\n if (cachedContent.byteLength > 0) {\n console.log(`Loaded from cache: ${cacheFile} (${source})`)\n return { content: cachedContent, filePath: cacheFile }\n }\n } catch (error) {\n // Cache miss, continue to fetch\n }\n\n try {\n console.log(`Downloading from URL: ${source}`)\n const response = await fetch(source)\n if (!response.ok) {\n return { error: `Failed to fetch from ${source}: ${response.statusText}` }\n }\n const content = await response.arrayBuffer()\n\n try {\n await writeFile(cacheFile, Buffer.from(content))\n console.log(`Cached: ${source}`)\n } catch (cacheError) {\n console.warn(`Failed to cache: ${cacheError}`)\n }\n\n return { content, filePath: cacheFile }\n } catch (error) {\n return { error: `Error downloading from ${source}: ${error}` }\n }\n } else {\n try {\n console.log(`Loading from local path: ${source}`)\n const content = await Bun.file(source).arrayBuffer()\n return { content, filePath: source }\n } catch (error) {\n return { error: `Error loading from local path ${source}: ${error}` }\n }\n }\n }\n\n /**\n * Download and save a file to a specific target path\n */\n static async downloadToPath(source: string, targetPath: string): Promise<DownloadResult> {\n const isUrl = source.startsWith(\"http://\") || source.startsWith(\"https://\")\n\n await mkdir(path.dirname(targetPath), { recursive: true })\n\n if (isUrl) {\n try {\n console.log(`Downloading from URL: ${source}`)\n const response = await fetch(source)\n if (!response.ok) {\n return { error: `Failed to fetch from ${source}: ${response.statusText}` }\n }\n const content = await response.arrayBuffer()\n\n await writeFile(targetPath, Buffer.from(content))\n console.log(`Downloaded: ${source} -> ${targetPath}`)\n\n return { content, filePath: targetPath }\n } catch (error) {\n return { error: `Error downloading from ${source}: ${error}` }\n }\n } else {\n try {\n console.log(`Copying from local path: ${source}`)\n const content = await Bun.file(source).arrayBuffer()\n await writeFile(targetPath, Buffer.from(content))\n return { content, filePath: targetPath }\n } catch (error) {\n return { error: `Error copying from local path ${source}: ${error}` }\n }\n }\n }\n\n /**\n * Fetch multiple highlight queries and concatenate them\n */\n static async fetchHighlightQueries(sources: string[], cacheDir: string, filetype: string): Promise<string> {\n const queryPromises = sources.map((source) => this.fetchHighlightQuery(source, cacheDir, filetype))\n const queryResults = await Promise.all(queryPromises)\n\n const validQueries = queryResults.filter((query) => query.trim().length > 0)\n return validQueries.join(\"\\n\")\n }\n\n private static async fetchHighlightQuery(source: string, cacheDir: string, filetype: string): Promise<string> {\n const result = await this.downloadOrLoad(source, cacheDir, \"queries\", \".scm\", true, filetype)\n\n if (result.error) {\n console.error(`Error fetching highlight query from ${source}:`, result.error)\n return \"\"\n }\n\n if (result.content) {\n return new TextDecoder().decode(result.content)\n }\n\n return \"\"\n }\n}\n"
7
+ ],
8
+ "mappings": "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",
9
+ "debugId": "E28996FCD9507DC064756E2164756E21",
10
+ "names": []
11
+ }
@@ -4,7 +4,7 @@ import { type fonts, type ASCIIFontName } from "../lib/ascii.font";
4
4
  import { RGBA } from "../lib/RGBA";
5
5
  import { FrameBufferRenderable } from "./FrameBuffer";
6
6
  import type { RenderContext } from "../types";
7
- export interface ASCIIFontOptions extends RenderableOptions<ASCIIFontRenderable> {
7
+ export interface ASCIIFontOptions extends Omit<RenderableOptions<ASCIIFontRenderable>, "width" | "height"> {
8
8
  text?: string;
9
9
  font?: ASCIIFontName;
10
10
  fg?: RGBA | RGBA[];
@@ -0,0 +1,31 @@
1
+ import { type RenderContext } from "../types";
2
+ import { SyntaxStyle } from "../lib/syntax-style";
3
+ import { TreeSitterClient } from "../lib/tree-sitter";
4
+ import { TextBufferRenderable, type TextBufferOptions } from "./TextBufferRenderable";
5
+ export interface CodeOptions extends TextBufferOptions {
6
+ content?: string;
7
+ filetype?: string;
8
+ syntaxStyle: SyntaxStyle;
9
+ treeSitterClient?: TreeSitterClient;
10
+ }
11
+ export declare class CodeRenderable extends TextBufferRenderable {
12
+ private _content;
13
+ private _filetype?;
14
+ private _syntaxStyle;
15
+ private _isHighlighting;
16
+ private _treeSitterClient;
17
+ private _pendingRehighlight;
18
+ protected _contentDefaultOptions: {
19
+ content: string;
20
+ };
21
+ constructor(ctx: RenderContext, options: CodeOptions);
22
+ get content(): string;
23
+ set content(value: string);
24
+ get filetype(): string | undefined;
25
+ set filetype(value: string);
26
+ get syntaxStyle(): SyntaxStyle;
27
+ set syntaxStyle(value: SyntaxStyle);
28
+ private updateContent;
29
+ private fallback;
30
+ private createFallbackStyledText;
31
+ }
@@ -1,5 +1,5 @@
1
1
  import { OptimizedBuffer } from "../buffer";
2
- import type { ParsedKey } from "../lib/parse.keypress";
2
+ import type { KeyEvent } from "../lib/KeyHandler";
3
3
  import { type ColorInput } from "../lib/RGBA";
4
4
  import { Renderable, type RenderableOptions } from "../Renderable";
5
5
  import type { RenderContext } from "../types";
@@ -54,9 +54,9 @@ export declare class InputRenderable extends Renderable {
54
54
  set placeholder(placeholder: string);
55
55
  get cursorPosition(): number;
56
56
  set cursorPosition(position: number);
57
- private insertText;
58
- private deleteCharacter;
59
- handleKeyPress(key: ParsedKey | string): boolean;
57
+ insertText(text: string): void;
58
+ deleteCharacter(direction: "backward" | "forward"): void;
59
+ handleKeyPress(key: KeyEvent | string): boolean;
60
60
  set maxLength(maxLength: number);
61
61
  set backgroundColor(value: ColorInput);
62
62
  set textColor(value: ColorInput);
@@ -1,6 +1,6 @@
1
1
  import type { OptimizedBuffer } from "../buffer";
2
2
  import { RGBA, type ColorInput } from "../lib";
3
- import type { ParsedKey } from "../lib/parse.keypress";
3
+ import type { KeyEvent } from "../lib/KeyHandler";
4
4
  import { Renderable, type RenderableOptions } from "../Renderable";
5
5
  import type { RenderContext } from "../types";
6
6
  import { SliderRenderable, type SliderOptions } from "./Slider";
@@ -42,7 +42,7 @@ export declare class ScrollBarRenderable extends Renderable {
42
42
  private updateSliderFromScrollState;
43
43
  scrollBy(delta: number, unit?: ScrollUnit): void;
44
44
  private recalculateVisibility;
45
- handleKeyPress(key: ParsedKey | string): boolean;
45
+ handleKeyPress(key: KeyEvent | string): boolean;
46
46
  }
47
47
  export interface ArrowOptions extends RenderableOptions<ArrowRenderable> {
48
48
  direction: "up" | "down" | "left" | "right";
@@ -1,4 +1,5 @@
1
- import { type ParsedKey } from "../lib";
1
+ import { type KeyEvent } from "../lib";
2
+ import { type ScrollAcceleration } from "../lib/scroll-acceleration";
2
3
  import type { Renderable, RenderableOptions } from "../Renderable";
3
4
  import type { MouseEvent } from "../renderer";
4
5
  import type { RenderContext } from "../types";
@@ -22,6 +23,7 @@ export interface ScrollBoxOptions extends BoxOptions<ScrollBoxRenderable> {
22
23
  stickyStart?: "bottom" | "top" | "left" | "right";
23
24
  scrollX?: boolean;
24
25
  scrollY?: boolean;
26
+ scrollAcceleration?: ScrollAcceleration;
25
27
  }
26
28
  export declare class ScrollBoxRenderable extends BoxRenderable {
27
29
  static idCounter: number;
@@ -51,6 +53,7 @@ export declare class ScrollBoxRenderable extends BoxRenderable {
51
53
  private _stickyScrollRight;
52
54
  private _stickyStart?;
53
55
  private _hasManualScroll;
56
+ private scrollAccel;
54
57
  get stickyScroll(): boolean;
55
58
  set stickyScroll(value: boolean);
56
59
  get stickyStart(): "bottom" | "top" | "left" | "right" | undefined;
@@ -63,7 +66,7 @@ export declare class ScrollBoxRenderable extends BoxRenderable {
63
66
  get scrollHeight(): number;
64
67
  private updateStickyState;
65
68
  private applyStickyStart;
66
- constructor(ctx: RenderContext, { wrapperOptions, viewportOptions, contentOptions, rootOptions, scrollbarOptions, verticalScrollbarOptions, horizontalScrollbarOptions, stickyScroll, stickyStart, scrollX, scrollY, ...options }: ScrollBoxOptions);
69
+ constructor(ctx: RenderContext, { wrapperOptions, viewportOptions, contentOptions, rootOptions, scrollbarOptions, verticalScrollbarOptions, horizontalScrollbarOptions, stickyScroll, stickyStart, scrollX, scrollY, scrollAcceleration, ...options }: ScrollBoxOptions);
67
70
  protected onUpdate(deltaTime: number): void;
68
71
  scrollBy(delta: number | {
69
72
  x: number;
@@ -74,10 +77,11 @@ export declare class ScrollBoxRenderable extends BoxRenderable {
74
77
  y: number;
75
78
  }): void;
76
79
  add(obj: Renderable | VNode<any, any[]>, index?: number): number;
80
+ insertBefore(obj: Renderable | VNode<any, any[]> | unknown, anchor?: Renderable | unknown): number;
77
81
  remove(id: string): void;
78
82
  getChildren(): Renderable[];
79
83
  protected onMouseEvent(event: MouseEvent): void;
80
- handleKeyPress(key: ParsedKey | string): boolean;
84
+ handleKeyPress(key: KeyEvent | string): boolean;
81
85
  startAutoScroll(mouseX: number, mouseY: number): void;
82
86
  updateAutoScroll(mouseX: number, mouseY: number): void;
83
87
  stopAutoScroll(): void;
@@ -1,6 +1,6 @@
1
1
  import { OptimizedBuffer } from "../buffer";
2
2
  import { fonts } from "../lib/ascii.font";
3
- import type { ParsedKey } from "../lib/parse.keypress";
3
+ import type { KeyEvent } from "../lib/KeyHandler";
4
4
  import { type ColorInput } from "../lib/RGBA";
5
5
  import { Renderable, type RenderableOptions } from "../Renderable";
6
6
  import type { RenderContext } from "../types";
@@ -81,7 +81,7 @@ export declare class SelectRenderable extends Renderable {
81
81
  setSelectedIndex(index: number): void;
82
82
  private updateScrollOffset;
83
83
  protected onResize(width: number, height: number): void;
84
- handleKeyPress(key: ParsedKey | string): boolean;
84
+ handleKeyPress(key: KeyEvent | string): boolean;
85
85
  get showScrollIndicator(): boolean;
86
86
  set showScrollIndicator(show: boolean);
87
87
  get showDescription(): boolean;
@@ -1,7 +1,7 @@
1
1
  import { Renderable, type RenderableOptions } from "../Renderable";
2
2
  import { OptimizedBuffer } from "../buffer";
3
3
  import { type ColorInput } from "../lib/RGBA";
4
- import type { ParsedKey } from "../lib/parse.keypress";
4
+ import type { KeyEvent } from "../lib/KeyHandler";
5
5
  import type { RenderContext } from "../types";
6
6
  export interface TabSelectOption {
7
7
  name: string;
@@ -63,7 +63,7 @@ export declare class TabSelectRenderable extends Renderable {
63
63
  protected onResize(width: number, height: number): void;
64
64
  setTabWidth(tabWidth: number): void;
65
65
  getTabWidth(): number;
66
- handleKeyPress(key: ParsedKey | string): boolean;
66
+ handleKeyPress(key: KeyEvent | string): boolean;
67
67
  get options(): TabSelectOption[];
68
68
  set options(options: TabSelectOption[]);
69
69
  set backgroundColor(color: ColorInput);
@@ -1,93 +1,39 @@
1
- import { BaseRenderable, Renderable, type RenderableOptions } from "../Renderable";
2
- import { Selection } from "../lib/selection";
1
+ import { BaseRenderable } from "../Renderable";
3
2
  import { StyledText } from "../lib/styled-text";
4
3
  import { type TextChunk } from "../text-buffer";
5
4
  import { RGBA } from "../lib/RGBA";
6
5
  import { type RenderContext } from "../types";
7
- import type { OptimizedBuffer } from "../buffer";
8
6
  import { RootTextNodeRenderable, TextNodeRenderable } from "./TextNode";
9
- export interface TextOptions extends RenderableOptions<TextRenderable> {
7
+ import { TextBufferRenderable, type TextBufferOptions } from "./TextBufferRenderable";
8
+ export interface TextOptions extends TextBufferOptions {
10
9
  content?: StyledText | string;
11
- fg?: string | RGBA;
12
- bg?: string | RGBA;
13
- selectionBg?: string | RGBA;
14
- selectionFg?: string | RGBA;
15
- selectable?: boolean;
16
- attributes?: number;
17
- wrap?: boolean;
18
- wrapMode?: "char" | "word";
19
10
  }
20
- export declare class TextRenderable extends Renderable {
21
- selectable: boolean;
11
+ export declare class TextRenderable extends TextBufferRenderable {
22
12
  private _text;
23
- private _defaultFg;
24
- private _defaultBg;
25
- private _defaultAttributes;
26
- private _selectionBg;
27
- private _selectionFg;
28
- private _wrap;
29
- private _wrapMode;
30
- private lastLocalSelection;
31
- private textBuffer;
32
- private _lineInfo;
13
+ private _hasManualStyledText;
33
14
  protected rootTextNode: RootTextNodeRenderable;
34
- protected _defaultOptions: {
15
+ protected _contentDefaultOptions: {
35
16
  content: string;
36
- fg: RGBA;
37
- bg: RGBA;
38
- selectionBg: undefined;
39
- selectionFg: undefined;
40
- selectable: true;
41
- attributes: number;
42
- wrap: true;
43
- wrapMode: "char" | "word";
44
17
  };
45
18
  constructor(ctx: RenderContext, options: TextOptions);
46
19
  private updateTextBuffer;
47
20
  private clearChunks;
48
21
  get content(): StyledText;
49
- get plainText(): string;
50
- get textLength(): number;
51
22
  get chunks(): TextChunk[];
52
23
  get textNode(): RootTextNodeRenderable;
53
24
  set content(value: StyledText | string);
54
- get fg(): RGBA;
55
- set fg(value: RGBA | string | undefined);
56
- get selectionBg(): RGBA | undefined;
57
- set selectionBg(value: RGBA | string | undefined);
58
- get selectionFg(): RGBA | undefined;
59
- set selectionFg(value: RGBA | string | undefined);
60
- get bg(): RGBA;
61
- set bg(value: RGBA | string | undefined);
62
- get attributes(): number;
63
- set attributes(value: number);
64
- get wrap(): boolean;
65
- set wrap(value: boolean);
66
- get wrapMode(): "char" | "word";
67
- set wrapMode(value: "char" | "word");
68
- protected onResize(width: number, height: number): void;
69
- private updateLocalSelection;
70
- private updateTextInfo;
71
- private setupMeasureFunc;
72
25
  insertChunk(chunk: TextChunk, index?: number): void;
73
- removeChunk(chunk: TextChunk): void;
74
- replaceChunk(chunk: TextChunk, oldChunk: TextChunk): void;
26
+ removeChunkByObject(chunk: TextChunk): void;
27
+ replaceChunkByObject(chunk: TextChunk, oldChunk: TextChunk): void;
75
28
  private updateTextFromNodes;
76
29
  add(obj: TextNodeRenderable | StyledText | string, index?: number): number;
77
30
  remove(id: string): void;
78
31
  insertBefore(obj: BaseRenderable | any, anchor?: TextNodeRenderable): number;
79
32
  getTextChildren(): BaseRenderable[];
80
33
  clear(): void;
81
- shouldStartSelection(x: number, y: number): boolean;
82
- onSelectionChanged(selection: Selection | null): boolean;
83
- getSelectedText(): string;
84
- hasSelection(): boolean;
85
- getSelection(): {
86
- start: number;
87
- end: number;
88
- } | null;
89
34
  onLifecyclePass: () => void;
90
- render(buffer: OptimizedBuffer, deltaTime: number): void;
91
- protected renderSelf(buffer: OptimizedBuffer): void;
35
+ protected onFgChanged(newColor: RGBA): void;
36
+ protected onBgChanged(newColor: RGBA): void;
37
+ protected onAttributesChanged(newAttributes: number): void;
92
38
  destroy(): void;
93
39
  }
@@ -0,0 +1,81 @@
1
+ import { Renderable, type RenderableOptions } from "../Renderable";
2
+ import { Selection, type LocalSelectionBounds } from "../lib/selection";
3
+ import { TextBuffer, type TextChunk } from "../text-buffer";
4
+ import { RGBA } from "../lib/RGBA";
5
+ import { type RenderContext } from "../types";
6
+ import type { OptimizedBuffer } from "../buffer";
7
+ import type { LineInfo } from "../zig";
8
+ export interface TextBufferOptions extends RenderableOptions<TextBufferRenderable> {
9
+ fg?: string | RGBA;
10
+ bg?: string | RGBA;
11
+ selectionBg?: string | RGBA;
12
+ selectionFg?: string | RGBA;
13
+ selectable?: boolean;
14
+ attributes?: number;
15
+ wrap?: boolean;
16
+ wrapMode?: "char" | "word";
17
+ }
18
+ export declare abstract class TextBufferRenderable extends Renderable {
19
+ selectable: boolean;
20
+ protected _defaultFg: RGBA;
21
+ protected _defaultBg: RGBA;
22
+ protected _defaultAttributes: number;
23
+ protected _selectionBg: RGBA | undefined;
24
+ protected _selectionFg: RGBA | undefined;
25
+ protected _wrap: boolean;
26
+ protected _wrapMode: "char" | "word";
27
+ protected lastLocalSelection: LocalSelectionBounds | null;
28
+ protected textBuffer: TextBuffer;
29
+ protected _lineInfo: LineInfo;
30
+ protected _defaultOptions: {
31
+ fg: RGBA;
32
+ bg: RGBA;
33
+ selectionBg: undefined;
34
+ selectionFg: undefined;
35
+ selectable: true;
36
+ attributes: number;
37
+ wrap: true;
38
+ wrapMode: "char" | "word";
39
+ };
40
+ constructor(ctx: RenderContext, options: TextBufferOptions);
41
+ get plainText(): string;
42
+ get textLength(): number;
43
+ get fg(): RGBA;
44
+ set fg(value: RGBA | string | undefined);
45
+ get selectionBg(): RGBA | undefined;
46
+ set selectionBg(value: RGBA | string | undefined);
47
+ get selectionFg(): RGBA | undefined;
48
+ set selectionFg(value: RGBA | string | undefined);
49
+ get bg(): RGBA;
50
+ set bg(value: RGBA | string | undefined);
51
+ get attributes(): number;
52
+ set attributes(value: number);
53
+ get wrap(): boolean;
54
+ set wrap(value: boolean);
55
+ get wrapMode(): "char" | "word";
56
+ set wrapMode(value: "char" | "word");
57
+ protected onResize(width: number, height: number): void;
58
+ protected refreshLocalSelection(): boolean;
59
+ private updateLocalSelection;
60
+ protected updateTextInfo(): void;
61
+ private updateLineInfo;
62
+ private updateWrapWidth;
63
+ private setupMeasureFunc;
64
+ insertChunk(chunk: TextChunk, index?: number): void;
65
+ removeChunk(index: number): void;
66
+ replaceChunk(index: number, chunk: TextChunk): void;
67
+ shouldStartSelection(x: number, y: number): boolean;
68
+ onSelectionChanged(selection: Selection | null): boolean;
69
+ getSelectedText(): string;
70
+ hasSelection(): boolean;
71
+ getSelection(): {
72
+ start: number;
73
+ end: number;
74
+ } | null;
75
+ render(buffer: OptimizedBuffer, deltaTime: number): void;
76
+ protected renderSelf(buffer: OptimizedBuffer): void;
77
+ destroy(): void;
78
+ protected onFgChanged(newColor: RGBA): void;
79
+ protected onBgChanged(newColor: RGBA): void;
80
+ protected onAttributesChanged(newAttributes: number): void;
81
+ }
@@ -57,6 +57,7 @@ export declare class TextNodeRenderable extends BaseRenderable {
57
57
  get bg(): RGBA | undefined;
58
58
  set attributes(attributes: number);
59
59
  get attributes(): number;
60
+ findDescendantById(id: string): BaseRenderable | undefined;
60
61
  }
61
62
  export declare class RootTextNodeRenderable extends TextNodeRenderable {
62
63
  private readonly ctx;
@@ -1,5 +1,7 @@
1
1
  export * from "./Box";
2
+ export * from "./Code";
2
3
  export * from "./FrameBuffer";
4
+ export * from "./TextBufferRenderable";
3
5
  export * from "./Text";
4
6
  export * from "./TextNode";
5
7
  export * from "./ASCIIFont";
package/renderer.d.ts CHANGED
@@ -8,7 +8,7 @@ import { TerminalConsole, type ConsoleOptions } from "./console";
8
8
  import { type MouseEventType, type RawMouseEvent, type ScrollInfo } from "./lib/parse.mouse";
9
9
  import { Selection } from "./lib/selection";
10
10
  import { EventEmitter } from "events";
11
- import { KeyHandler } from "./lib/KeyHandler";
11
+ import { KeyHandler, InternalKeyHandler } from "./lib/KeyHandler";
12
12
  export interface CliRendererConfig {
13
13
  stdin?: NodeJS.ReadStream;
14
14
  stdout?: NodeJS.WriteStream;
@@ -75,7 +75,7 @@ export declare class CliRenderer extends EventEmitter implements RenderContext {
75
75
  stdin: NodeJS.ReadStream;
76
76
  private stdout;
77
77
  private exitOnCtrlC;
78
- private isDestroyed;
78
+ private _isDestroyed;
79
79
  nextRenderBuffer: OptimizedBuffer;
80
80
  currentRenderBuffer: OptimizedBuffer;
81
81
  private _isRunning;
@@ -141,9 +141,11 @@ export declare class CliRenderer extends EventEmitter implements RenderContext {
141
141
  private _currentFocusedRenderable;
142
142
  private lifecyclePasses;
143
143
  private handleError;
144
+ private dumpOutputCache;
144
145
  private exitHandler;
145
146
  private warningHandler;
146
147
  constructor(lib: RenderLib, rendererPtr: Pointer, stdin: NodeJS.ReadStream, stdout: NodeJS.WriteStream, width: number, height: number, config?: CliRendererConfig);
148
+ get isDestroyed(): boolean;
147
149
  registerLifecyclePass(renderable: Renderable): void;
148
150
  unregisterLifecyclePass(renderable: Renderable): void;
149
151
  getLifecyclePasses(): Set<Renderable>;
@@ -159,6 +161,7 @@ export declare class CliRenderer extends EventEmitter implements RenderContext {
159
161
  get resolution(): PixelResolution | null;
160
162
  get console(): TerminalConsole;
161
163
  get keyInput(): KeyHandler;
164
+ get _internalKeyInput(): InternalKeyHandler;
162
165
  get terminalWidth(): number;
163
166
  get terminalHeight(): number;
164
167
  get useThread(): boolean;
@@ -194,7 +197,6 @@ export declare class CliRenderer extends EventEmitter implements RenderContext {
194
197
  enabled?: boolean;
195
198
  corner?: DebugOverlayCorner;
196
199
  }): void;
197
- clearTerminal(): void;
198
200
  setTerminalTitle(title: string): void;
199
201
  dumpHitGrid(): void;
200
202
  dumpBuffers(timestamp?: number): void;
@@ -64,4 +64,5 @@ export declare function createMockKeys(renderer: CliRenderer): {
64
64
  pressBackspace: () => void;
65
65
  pressArrow: (direction: "up" | "down" | "left" | "right") => void;
66
66
  pressCtrlC: () => void;
67
+ pasteBracketedText: (text: string) => Promise<void>;
67
68
  };
@@ -0,0 +1,7 @@
1
+ export declare function createSpy(): {
2
+ (...args: any[]): void;
3
+ calls: any[][];
4
+ callCount(): number;
5
+ calledWith(...expected: any[]): boolean;
6
+ reset(): number;
7
+ };
@@ -15,4 +15,5 @@ export declare function createTestRenderer(options: TestRendererOptions): Promis
15
15
  mockMouse: MockMouse;
16
16
  renderOnce: () => Promise<void>;
17
17
  captureCharFrame: () => string;
18
+ resize: (width: number, height: number) => void;
18
19
  }>;
package/testing.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./testing/test-renderer";
2
2
  export * from "./testing/mock-keys";
3
3
  export * from "./testing/mock-mouse";
4
+ export * from "./testing/spy";
package/testing.js CHANGED
@@ -1,8 +1,9 @@
1
1
  // @bun
2
2
  import {
3
+ ANSI,
3
4
  CliRenderer,
4
5
  resolveRenderLib
5
- } from "./index-0yx9rnxg.js";
6
+ } from "./index-pxa2sv92.js";
6
7
 
7
8
  // src/testing/mock-keys.ts
8
9
  var KeyCodes = {
@@ -126,6 +127,9 @@ function createMockKeys(renderer) {
126
127
  const pressCtrlC = () => {
127
128
  pressKey(KeyCodes.CTRL_C);
128
129
  };
130
+ const pasteBracketedText = (text) => {
131
+ return pressKeys([ANSI.bracketedPasteStart, text, ANSI.bracketedPasteEnd]);
132
+ };
129
133
  return {
130
134
  pressKeys,
131
135
  pressKey,
@@ -135,7 +139,8 @@ function createMockKeys(renderer) {
135
139
  pressTab,
136
140
  pressBackspace,
137
141
  pressArrow,
138
- pressCtrlC
142
+ pressCtrlC,
143
+ pasteBracketedText
139
144
  };
140
145
  }
141
146
 
@@ -288,6 +293,7 @@ function createMockMouse(renderer) {
288
293
  // src/testing/test-renderer.ts
289
294
  var decoder = new TextDecoder;
290
295
  async function createTestRenderer(options) {
296
+ process.env.OTUI_USE_CONSOLE = "false";
291
297
  const renderer = await setupTestRenderer({
292
298
  ...options,
293
299
  useAlternateScreen: false,
@@ -296,17 +302,21 @@ async function createTestRenderer(options) {
296
302
  renderer.disableStdoutInterception();
297
303
  const mockInput = createMockKeys(renderer);
298
304
  const mockMouse = createMockMouse(renderer);
305
+ const renderOnce = async () => {
306
+ await renderer.loop();
307
+ };
299
308
  return {
300
309
  renderer,
301
310
  mockInput,
302
311
  mockMouse,
303
- renderOnce: async () => {
304
- await renderer.loop();
305
- },
312
+ renderOnce,
306
313
  captureCharFrame: () => {
307
314
  const currentBuffer = renderer.currentRenderBuffer;
308
315
  const frameBytes = currentBuffer.getRealCharBytes(true);
309
316
  return decoder.decode(frameBytes);
317
+ },
318
+ resize: (width, height) => {
319
+ renderer.processResize(width, height);
310
320
  }
311
321
  };
312
322
  }
@@ -331,13 +341,28 @@ async function setupTestRenderer(config) {
331
341
  const renderer = new CliRenderer(ziglib, rendererPtr, stdin, stdout, width, height, config);
332
342
  return renderer;
333
343
  }
344
+ // src/testing/spy.ts
345
+ function createSpy() {
346
+ const calls = [];
347
+ const spy = (...args) => {
348
+ calls.push(args);
349
+ };
350
+ spy.calls = calls;
351
+ spy.callCount = () => calls.length;
352
+ spy.calledWith = (...expected) => {
353
+ return calls.some((call) => JSON.stringify(call) === JSON.stringify(expected));
354
+ };
355
+ spy.reset = () => calls.length = 0;
356
+ return spy;
357
+ }
334
358
  export {
335
359
  createTestRenderer,
360
+ createSpy,
336
361
  createMockMouse,
337
362
  createMockKeys,
338
363
  MouseButtons,
339
364
  KeyCodes
340
365
  };
341
366
 
342
- //# debugId=8F861C9D239D4E3664756E2164756E21
367
+ //# debugId=6748818851F0715164756E2164756E21
343
368
  //# sourceMappingURL=testing.js.map