@zaly/tui 0.1.0 → 0.1.1
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.
- package/dist/{actions-DEIKF2ts.mjs → actions-AY6avfEV.mjs} +2 -3
- package/dist/{actions-DEIKF2ts.mjs.map → actions-AY6avfEV.mjs.map} +1 -1
- package/dist/{actions--ODlgCQ5.d.mts → actions-B0yyZ-Ww.d.mts} +4 -6
- package/dist/actions-B0yyZ-Ww.d.mts.map +1 -0
- package/dist/{ansi-CMv71xVr.mjs → ansi-CxgRPLA2.mjs} +3 -4
- package/dist/{ansi-CMv71xVr.mjs.map → ansi-CxgRPLA2.mjs.map} +1 -1
- package/dist/ansi.d.mts +1 -3
- package/dist/ansi.d.mts.map +1 -1
- package/dist/ansi.mjs +1 -1
- package/dist/{autocomplete-CD30kSe_.d.mts → autocomplete-wgceuhLr.d.mts} +5 -7
- package/dist/autocomplete-wgceuhLr.d.mts.map +1 -0
- package/dist/{box-C_N_7ChP.mjs → box-DToDoXlU.mjs} +8 -10
- package/dist/{box-C_N_7ChP.mjs.map → box-DToDoXlU.mjs.map} +1 -1
- package/dist/{builder-Chwtk0nQ.mjs → builder-BdYlK1Ew.mjs} +5 -6
- package/dist/{builder-Chwtk0nQ.mjs.map → builder-BdYlK1Ew.mjs.map} +1 -1
- package/dist/{callbacks-DLecWn7G.mjs → callbacks-DW8XKYKy.mjs} +8 -12
- package/dist/{callbacks-DLecWn7G.mjs.map → callbacks-DW8XKYKy.mjs.map} +1 -1
- package/dist/{client-D7qz4TZt.mjs → client-BWm6dNZF.mjs} +4 -5
- package/dist/{client-D7qz4TZt.mjs.map → client-BWm6dNZF.mjs.map} +1 -1
- package/dist/client-C69qWhMG.mjs +1 -0
- package/dist/{clipboard-CNPBTX7j.mjs → clipboard-UEoX9sup.mjs} +2 -3
- package/dist/{clipboard-CNPBTX7j.mjs.map → clipboard-UEoX9sup.mjs.map} +1 -1
- package/dist/clipboard.d.mts +0 -2
- package/dist/clipboard.d.mts.map +1 -1
- package/dist/clipboard.mjs +1 -1
- package/dist/{color-DBMQLv4Y.mjs → color-Cr1VoL49.mjs} +2 -3
- package/dist/{color-DBMQLv4Y.mjs.map → color-Cr1VoL49.mjs.map} +1 -1
- package/dist/ctx-CYEzzH-7.mjs +1 -0
- package/dist/{ctx-BaQ2hP5u.mjs → ctx-DBeFcZt6.mjs} +4 -5
- package/dist/{ctx-BaQ2hP5u.mjs.map → ctx-DBeFcZt6.mjs.map} +1 -1
- package/dist/{divider-BlNNN2OS.mjs → divider-qEj5prKE.mjs} +3 -4
- package/dist/{divider-BlNNN2OS.mjs.map → divider-qEj5prKE.mjs.map} +1 -1
- package/dist/{files-BvThQpOf.mjs → files-C3ZnFpvq.mjs} +3 -4
- package/dist/{files-BvThQpOf.mjs.map → files-C3ZnFpvq.mjs.map} +1 -1
- package/dist/{files-B_5HDBPp.d.mts → files-CdiDnwA_.d.mts} +3 -5
- package/dist/files-CdiDnwA_.d.mts.map +1 -0
- package/dist/{flex-Bguo-fUe.mjs → flex-CYp4etqn.mjs} +3 -4
- package/dist/{flex-Bguo-fUe.mjs.map → flex-CYp4etqn.mjs.map} +1 -1
- package/dist/{github-Cy2hfWJ7.mjs → github-CLveT9mq.mjs} +2 -3
- package/dist/{github-Cy2hfWJ7.mjs.map → github-CLveT9mq.mjs.map} +1 -1
- package/dist/{github-CyRwUQ3y.d.mts → github-DC0XemKa.d.mts} +3 -5
- package/dist/github-DC0XemKa.d.mts.map +1 -0
- package/dist/{image-BLls2F4t.d.mts → image-DdRDv7q6.d.mts} +2 -4
- package/dist/image-DdRDv7q6.d.mts.map +1 -0
- package/dist/{image-Cqtj3yRA.mjs → image-M--Bw4bs.mjs} +6 -7
- package/dist/{image-Cqtj3yRA.mjs.map → image-M--Bw4bs.mjs.map} +1 -1
- package/dist/image.d.mts +1 -3
- package/dist/image.d.mts.map +1 -1
- package/dist/image.mjs +1 -1
- package/dist/index.d.mts +3 -15
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +11 -14
- package/dist/index.mjs.map +1 -1
- package/dist/{input-ET2YEMcl.mjs → input-BkE4EpBw.mjs} +6 -7
- package/dist/{input-ET2YEMcl.mjs.map → input-BkE4EpBw.mjs.map} +1 -1
- package/dist/{input-NuD8TH8N.d.mts → input-C3kfYoEJ.d.mts} +3 -5
- package/dist/input-C3kfYoEJ.d.mts.map +1 -0
- package/dist/{inspect-Cxzs-W0g.mjs → inspect-Cli1beu8.mjs} +3 -4
- package/dist/{inspect-Cxzs-W0g.mjs.map → inspect-Cli1beu8.mjs.map} +1 -1
- package/dist/{inspect-B1uXxdKC.d.mts → inspect-hSl3U2BD.d.mts} +2 -6
- package/dist/inspect-hSl3U2BD.d.mts.map +1 -0
- package/dist/kitty-0sJ8axU_.mjs +1 -0
- package/dist/{kitty-JbCJC0iQ.mjs → kitty-BH_eK6lz.mjs} +2 -3
- package/dist/{kitty-JbCJC0iQ.mjs.map → kitty-BH_eK6lz.mjs.map} +1 -1
- package/dist/{log-B4djzy2m.mjs → log-96b1_J6G.mjs} +6 -7
- package/dist/{log-B4djzy2m.mjs.map → log-96b1_J6G.mjs.map} +1 -1
- package/dist/{logger-CvJCITzP.mjs → logger-DwfXp8LF.mjs} +5 -6
- package/dist/{logger-CvJCITzP.mjs.map → logger-DwfXp8LF.mjs.map} +1 -1
- package/dist/{markdown-D3ZtRn6C.mjs → markdown-CgRZBhIX.mjs} +11 -12
- package/dist/{markdown-D3ZtRn6C.mjs.map → markdown-CgRZBhIX.mjs.map} +1 -1
- package/dist/markdown.d.mts +2 -4
- package/dist/markdown.d.mts.map +1 -1
- package/dist/markdown.mjs +1 -1
- package/dist/math-Dk8hxbmz.mjs +1 -0
- package/dist/{math-Dd7a1irv.mjs → math-VPuwFCid.mjs} +1 -2
- package/dist/{math-Dd7a1irv.mjs.map → math-VPuwFCid.mjs.map} +1 -1
- package/dist/md.bun.d.mts +1 -3
- package/dist/md.bun.d.mts.map +1 -1
- package/dist/md.bun.mjs +2 -3
- package/dist/md.node.d.mts +1 -3
- package/dist/md.node.d.mts.map +1 -1
- package/dist/md.node.mjs +2 -3
- package/dist/{node-BZ7f6HzU.mjs → node-CXNobGaP.mjs} +3 -4
- package/dist/{node-BZ7f6HzU.mjs.map → node-CXNobGaP.mjs.map} +1 -1
- package/dist/{oklch-Bsh5swbC.mjs → oklch-Boh4YHEc.mjs} +3 -4
- package/dist/{oklch-Bsh5swbC.mjs.map → oklch-Boh4YHEc.mjs.map} +1 -1
- package/dist/{overlay-LvOjG7kn.mjs → overlay-CevDWgSF.mjs} +3 -4
- package/dist/{overlay-LvOjG7kn.mjs.map → overlay-CevDWgSF.mjs.map} +1 -1
- package/dist/{picker-f6xjgACX.mjs → picker-D9WrE3zF.mjs} +11 -16
- package/dist/{picker-f6xjgACX.mjs.map → picker-D9WrE3zF.mjs.map} +1 -1
- package/dist/{picker-B-OxKKnD.d.mts → picker-DsB6--GN.d.mts} +6 -8
- package/dist/picker-DsB6--GN.d.mts.map +1 -0
- package/dist/{queries-BUkBxkuM.mjs → queries-BIniKnLL.mjs} +3 -5
- package/dist/{queries-BUkBxkuM.mjs.map → queries-BIniKnLL.mjs.map} +1 -1
- package/dist/{queries-C75-wG1B.d.mts → queries-Dmd3IjSd.d.mts} +3 -51
- package/dist/queries-Dmd3IjSd.d.mts.map +1 -0
- package/dist/{reactive-f7NpAi69.mjs → reactive-DkP75TPk.mjs} +2 -3
- package/dist/{reactive-f7NpAi69.mjs.map → reactive-DkP75TPk.mjs.map} +1 -1
- package/dist/{registry-DUWpSPoo.mjs → registry-CQU0VwpM.mjs} +9 -14
- package/dist/{registry-DUWpSPoo.mjs.map → registry-CQU0VwpM.mjs.map} +1 -1
- package/dist/{render-B7LfNM5K.mjs → render-Bp2N2i6J.mjs} +4 -5
- package/dist/{render-B7LfNM5K.mjs.map → render-Bp2N2i6J.mjs.map} +1 -1
- package/dist/{renderer-BLsd-wrG.mjs → renderer-B9sAMA10.mjs} +25 -38
- package/dist/{renderer-BLsd-wrG.mjs.map → renderer-B9sAMA10.mjs.map} +1 -1
- package/dist/{renderer-aAtkFgll.mjs → renderer-BYl2pbdx.mjs} +3 -4
- package/dist/{renderer-aAtkFgll.mjs.map → renderer-BYl2pbdx.mjs.map} +1 -1
- package/dist/renderer-Ctz0hv5o.mjs +1 -0
- package/dist/{search-FvGnswRl.d.mts → search-DsHzamic.d.mts} +1 -9
- package/dist/search-DsHzamic.d.mts.map +1 -0
- package/dist/{select-BKE5LzdN.d.mts → select-BZCFXdjp.d.mts} +3 -5
- package/dist/select-BZCFXdjp.d.mts.map +1 -0
- package/dist/{select-m7NE6Rwa.mjs → select-CUmAFKJh.mjs} +5 -6
- package/dist/{select-m7NE6Rwa.mjs.map → select-CUmAFKJh.mjs.map} +1 -1
- package/dist/services/logger.d.mts +1 -1
- package/dist/services/logger.mjs +1 -1
- package/dist/services/notifier.d.mts +1 -3
- package/dist/services/notifier.d.mts.map +1 -1
- package/dist/services/notifier.mjs +3 -4
- package/dist/services/picker.d.mts +5 -7
- package/dist/services/picker.d.mts.map +1 -1
- package/dist/services/picker.mjs +8 -9
- package/dist/services/prompt.d.mts +4 -6
- package/dist/services/prompt.d.mts.map +1 -1
- package/dist/services/prompt.mjs +7 -8
- package/dist/shiki/server.mjs +6 -8
- package/dist/shiki/server.mjs.map +1 -1
- package/dist/{shiki-CJauRusM.mjs → shiki-BAf9PdIc.mjs} +4 -5
- package/dist/{shiki-CJauRusM.mjs.map → shiki-BAf9PdIc.mjs.map} +1 -1
- package/dist/{shiki-B4U0s8jT.mjs → shiki-DUUAIE6f.mjs} +4 -7
- package/dist/{shiki-B4U0s8jT.mjs.map → shiki-DUUAIE6f.mjs.map} +1 -1
- package/dist/{show-DR2x1YFc.mjs → show-D5XNXgZf.mjs} +4 -5
- package/dist/{show-DR2x1YFc.mjs.map → show-D5XNXgZf.mjs.map} +1 -1
- package/dist/{size-D8JogYLy.mjs → size-BHRJuRk9.mjs} +2 -3
- package/dist/{size-D8JogYLy.mjs.map → size-BHRJuRk9.mjs.map} +1 -1
- package/dist/{style-DslRHzI4.mjs → style-Cw_EuszU.mjs} +5 -6
- package/dist/{style-DslRHzI4.mjs.map → style-Cw_EuszU.mjs.map} +1 -1
- package/dist/style.d.mts +2 -4
- package/dist/style.d.mts.map +1 -1
- package/dist/style.mjs +3 -3
- package/dist/{text-BoJdKXLU.mjs → text-4arC3odI.mjs} +3 -4
- package/dist/{text-BoJdKXLU.mjs.map → text-4arC3odI.mjs.map} +1 -1
- package/dist/{text-DPrhma4x.mjs → text-BArwVVkg.mjs} +5 -6
- package/dist/{text-DPrhma4x.mjs.map → text-BArwVVkg.mjs.map} +1 -1
- package/dist/{text-CmxbA8lk.d.mts → text-DdkJXgoC.d.mts} +3 -5
- package/dist/text-DdkJXgoC.d.mts.map +1 -0
- package/dist/text.d.mts +1 -1
- package/dist/text.mjs +1 -1
- package/dist/{theme-C8LkcoaK.mjs → theme-B8hb1lPU.mjs} +3 -4
- package/dist/{theme-C8LkcoaK.mjs.map → theme-B8hb1lPU.mjs.map} +1 -1
- package/dist/{theme-DVX8dvGG.mjs → theme-BeSaXGNY.mjs} +3 -5
- package/dist/{theme-DVX8dvGG.mjs.map → theme-BeSaXGNY.mjs.map} +1 -1
- package/dist/themes.d.mts +1 -7
- package/dist/themes.d.mts.map +1 -1
- package/dist/themes.mjs +1 -1
- package/dist/{tree-CTvSpF9b.d.mts → tree-Berzv8Rz.d.mts} +3 -5
- package/dist/tree-Berzv8Rz.d.mts.map +1 -0
- package/dist/{tree-Bo1afYhe.mjs → tree-D6NvMQx8.mjs} +5 -6
- package/dist/{tree-Bo1afYhe.mjs.map → tree-D6NvMQx8.mjs.map} +1 -1
- package/dist/{types-C9ceMsbJ.d.mts → types-ByMHEdCF.d.mts} +1 -7
- package/dist/types-ByMHEdCF.d.mts.map +1 -0
- package/dist/{types-D3jk1rtk.d.mts → types-CUVUJPz6.d.mts} +1 -3
- package/dist/types-CUVUJPz6.d.mts.map +1 -0
- package/dist/{utils-3M4D_AXZ.mjs → utils-DHXAegVW.mjs} +1 -2
- package/dist/{utils-3M4D_AXZ.mjs.map → utils-DHXAegVW.mjs.map} +1 -1
- package/dist/{widget-BkMwhY2p.mjs → widget-sFveyrZE.mjs} +3 -4
- package/dist/{widget-BkMwhY2p.mjs.map → widget-sFveyrZE.mjs.map} +1 -1
- package/dist/{widget-DlF32PRp.d.mts → widget-sPJaKVU2.d.mts} +2 -4
- package/dist/widget-sPJaKVU2.d.mts.map +1 -0
- package/dist/widgets/autocomplete.d.mts +1 -1
- package/dist/widgets/autocomplete.mjs +5 -6
- package/dist/widgets/box.d.mts +1 -1
- package/dist/widgets/box.mjs +1 -1
- package/dist/widgets/code.d.mts +3 -5
- package/dist/widgets/code.d.mts.map +1 -1
- package/dist/widgets/code.mjs +10 -11
- package/dist/widgets/completions/actions.d.mts +1 -1
- package/dist/widgets/completions/actions.mjs +1 -1
- package/dist/widgets/completions/files.d.mts +1 -1
- package/dist/widgets/completions/files.mjs +1 -1
- package/dist/widgets/completions/github.d.mts +1 -1
- package/dist/widgets/completions/github.mjs +1 -1
- package/dist/widgets/completions/index.d.mts +3 -3
- package/dist/widgets/completions/index.mjs +3 -3
- package/dist/widgets/diff.d.mts +2 -4
- package/dist/widgets/diff.d.mts.map +1 -1
- package/dist/widgets/diff.mjs +7 -8
- package/dist/widgets/divider.d.mts +2 -4
- package/dist/widgets/divider.d.mts.map +1 -1
- package/dist/widgets/divider.mjs +1 -1
- package/dist/widgets/image.d.mts +1 -1
- package/dist/widgets/image.mjs +5 -6
- package/dist/widgets/input.d.mts +1 -1
- package/dist/widgets/input.mjs +1 -1
- package/dist/widgets/log.d.mts +1 -1
- package/dist/widgets/log.mjs +1 -1
- package/dist/widgets/markdown.d.mts +5 -7
- package/dist/widgets/markdown.d.mts.map +1 -1
- package/dist/widgets/markdown.mjs +1 -1
- package/dist/widgets/overlay.d.mts +1 -1
- package/dist/widgets/overlay.mjs +1 -1
- package/dist/widgets/picker.d.mts +1 -1
- package/dist/widgets/picker.mjs +1 -1
- package/dist/widgets/progress.d.mts +2 -4
- package/dist/widgets/progress.d.mts.map +1 -1
- package/dist/widgets/progress.mjs +4 -5
- package/dist/widgets/select.d.mts +1 -1
- package/dist/widgets/select.mjs +1 -1
- package/dist/widgets/show.d.mts +1 -3
- package/dist/widgets/show.d.mts.map +1 -1
- package/dist/widgets/show.mjs +1 -1
- package/dist/widgets/spinner.d.mts +2 -4
- package/dist/widgets/spinner.d.mts.map +1 -1
- package/dist/widgets/spinner.mjs +3 -4
- package/dist/widgets/text.d.mts +1 -1
- package/dist/widgets/text.mjs +1 -1
- package/dist/widgets/tree.d.mts +1 -1
- package/dist/widgets/tree.mjs +1 -1
- package/dist/widgets/widget.d.mts +1 -1
- package/dist/widgets/widget.mjs +1 -1
- package/dist/{worker-T6SdPzUH.mjs → worker-CtEowucz.mjs} +2 -3
- package/dist/{worker-T6SdPzUH.mjs.map → worker-CtEowucz.mjs.map} +1 -1
- package/dist/worker-Mqi380Et.mjs +1 -0
- package/package.json +3 -3
- package/dist/actions--ODlgCQ5.d.mts.map +0 -1
- package/dist/autocomplete-CD30kSe_.d.mts.map +0 -1
- package/dist/client-CNGt-dOt.mjs +0 -1
- package/dist/ctx-CndlTp1T.mjs +0 -1
- package/dist/files-B_5HDBPp.d.mts.map +0 -1
- package/dist/github-CyRwUQ3y.d.mts.map +0 -1
- package/dist/image-BLls2F4t.d.mts.map +0 -1
- package/dist/input-NuD8TH8N.d.mts.map +0 -1
- package/dist/inspect-B1uXxdKC.d.mts.map +0 -1
- package/dist/kitty-DKQYsQfH.mjs +0 -1
- package/dist/math-CU0wmC9N.mjs +0 -1
- package/dist/picker-B-OxKKnD.d.mts.map +0 -1
- package/dist/queries-C75-wG1B.d.mts.map +0 -1
- package/dist/renderer-YHbR7JZ4.mjs +0 -1
- package/dist/search-FvGnswRl.d.mts.map +0 -1
- package/dist/select-BKE5LzdN.d.mts.map +0 -1
- package/dist/text-CmxbA8lk.d.mts.map +0 -1
- package/dist/tree-CTvSpF9b.d.mts.map +0 -1
- package/dist/types-C9ceMsbJ.d.mts.map +0 -1
- package/dist/types-D3jk1rtk.d.mts.map +0 -1
- package/dist/widget-DlF32PRp.d.mts.map +0 -1
- package/dist/worker-C01jK2Ip.mjs +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-ET2YEMcl.mjs","names":[],"sources":["../src/widgets/input.ts"],"sourcesContent":["import type { MaybePromise } from \"@zaly/shared\"\nimport type { DetectedFile } from \"@zaly/shared/detect\"\nimport type { RenderCtx } from \"../core/ctx.ts\"\nimport type { BaseEvents } from \"../core/node.ts\"\nimport type { Reactive } from \"../core/reactive.ts\"\nimport type { StyleState } from \"../core/state.ts\"\nimport type { NodeActionMap } from \"../input/actions.ts\"\nimport type { RoutedKey } from \"../input/router.ts\"\nimport type { Size } from \"../layout/size.ts\"\nimport type { StyleBuilder } from \"../style/builder.ts\"\n\nimport { hash, isPromiseLike } from \"@zaly/shared\"\nimport { sliceAnsi, splitAnsi, stringWidth } from \"@zaly/shared/ansi\"\nimport { fileDetect } from \"@zaly/shared/detect\"\nimport { basename } from \"pathe\"\nimport { Node } from \"../core/node.ts\"\nimport { untrack, unwrap } from \"../core/reactive.ts\"\nimport { clipboard } from \"../input/clipboard.ts\"\nimport { formatText } from \"../layout/text.ts\"\n\nexport interface InputState extends StyleState {\n /** Current text content. May include `\\n` for multi-line input. */\n value?: string\n /** Shown dim when `value` is empty. */\n placeholder?: Reactive<string | undefined>\n /** Cursor position as a char index in `value`. Clamped to `[0, value.length]`. */\n cursor?: number\n /** Render width. Defaults to `fill`. */\n width?: Size\n /** Submitted input history, newest last. */\n history?: readonly string[]\n /** Threshold for showing pasted content as an attachment rather than raw text */\n pasteMaxLines?: number\n pasteMaxChars?: number\n canAttach?: (file: InputAttachment) => boolean\n format?: (value: string, ctx: { style: StyleBuilder }) => MaybePromise<string>\n validate?: (value: string) => boolean\n}\n\nexport type InputValue = { value: string; attachments: InputAttachment[] }\n\nconst PASTE_MAX_LINES = 5\nconst PASTE_MAX_CHARS = 1000\nconst graphemes = new Intl.Segmenter(undefined, { granularity: \"grapheme\" })\n\n/** A clipboard or bracketed paste that exceeds the `pasteMax*` thresholds. **/\ntype Paste = { type: \"paste\"; text: string }\n\n/** A file or image attachment detected from the clipboard. */\nexport type InputAttachment = DetectedFile & { path: string }\n\nexport type InputEvents = BaseEvents & {\n /** Fired when the submitted history changes. */\n history: { history: string[]; added: string }\n /** Fired when plain Enter is pressed. Payload is the current value. */\n submit: { value: string; attachments: InputAttachment[] }\n /** Fired when the user pastes a non-text resource via the\n * `input.paste` action. Images and file references both land here,\n * discriminated by `attachment.kind`. One event fires per image\n * paste; one per file in a multi-file paste.\n *\n * Wrapped under `attachment` because `InputAttachment` carries its\n * own `type` field (MIME) that would shadow the envelope's `type`\n * discriminator if spread directly. */\n attach: { attachment: InputAttachment }\n}\n\ntype FormatEntry = { promise?: Promise<void>; result?: string; input: string }\n\n/**\n * Multi-line text input with auto-grow.\n *\n * Editing commands (`cursorLeft`, `deleteWordBack`, `submit`, …) live on\n * `this.actions` as zero-arg methods. The input router maps keymap\n * bindings like `\"input.cursorLeft\"` onto those methods — users bind\n * different keys by configuring the keymap, not by patching the class.\n * The methods are also callable directly (`input.actions.submit()`),\n * which is handy in tests or for higher-level macros.\n *\n * What this class *still* handles via its `key` event listener:\n * - **Printable character insertion.** An unbound keystroke whose\n * `text` is set and has no ctrl/alt/meta modifier becomes a literal\n * insert at the cursor. There's no action for every printable char\n * in the keymap; the raw-key fallback handles them.\n * - **Paste events.** Whole payload inserted at cursor; always.\n *\n * Everything else (navigation, editing, submit/newline) goes through\n * the router → actions pipeline. Unbound non-printable keys fall back\n * to `emit(\"key\", …)` and bubble to the parent chain.\n *\n * Rendering word-wraps each logical line to `ctx.width`, so long\n * messages naturally grow vertically. The UI surface resizes its\n * reserved footer when the Input's row count changes, so the stream\n * above shifts accordingly.\n */\nexport class Input extends Node<InputState, InputEvents> {\n /** Class-level scope tag used by the input router to bind keymaps. */\n static readonly type = \"input\"\n\n override readonly type = Input.type\n #focused = false\n #history: string[] = []\n #historyDraft = \"\"\n #historyIndex: number | undefined\n #preferredCol: number | undefined\n #staged: ((InputAttachment | Paste) & { id: number; marker: string })[] = []\n #formatCache: Map<string, FormatEntry> & { version?: number } = new Map<string, FormatEntry>()\n #formatGen = 0\n\n /**\n * Editing actions. Parameterless — they close over `this` — so both\n * the router (via keymap dispatch) and application code can invoke\n * them. Add to the keymap in `src/input/actions.ts` to give them\n * default key bindings.\n */\n override actions = {\n \"input.cursorDown\": (): void => {\n const v = this.state.value ?? \"\"\n const { col, line } = posToLineCol(v, this.#cursor())\n if (line >= countLines(v) - 1) {\n this.#historyNext()\n return\n }\n this.#preferredCol ??= col\n this.state.cursor = lineColToPos(v, line + 1, this.#preferredCol)\n },\n \"input.cursorLeft\": (): void => {\n const c = this.#cursor()\n this.#preferredCol = undefined\n this.state.cursor = c > 0 ? c - 1 : c\n },\n \"input.cursorLineEnd\": (): void => {\n const v = this.state.value ?? \"\"\n this.#preferredCol = undefined\n this.state.cursor = lineEndPos(v, this.#cursor())\n },\n \"input.cursorLineStart\": (): void => {\n const v = this.state.value ?? \"\"\n const { line } = posToLineCol(v, this.#cursor())\n this.#preferredCol = undefined\n this.state.cursor = lineColToPos(v, line, 0)\n },\n \"input.cursorRight\": (): void => {\n const v = this.state.value ?? \"\"\n const c = this.#cursor()\n this.#preferredCol = undefined\n this.state.cursor = c < v.length ? c + 1 : c\n },\n \"input.cursorUp\": (): void => {\n const v = this.state.value ?? \"\"\n const { col, line } = posToLineCol(v, this.#cursor())\n if (line === 0) {\n this.#historyPrev()\n return\n }\n this.#preferredCol ??= col\n this.state.cursor = lineColToPos(v, line - 1, this.#preferredCol)\n },\n \"input.deleteCharBack\": (): void => {\n const v = this.state.value ?? \"\"\n const c = this.#cursor()\n this.#preferredCol = undefined\n if (c === 0) return\n this.#historyEdit()\n const marker = this.#markerRange(c, \"back\")\n if (marker) return this.#deleteRange(marker.start, marker.end)\n this.state.set({ cursor: c - 1, value: v.slice(0, c - 1) + v.slice(c) })\n },\n \"input.deleteCharForward\": (): void => {\n const v = this.state.value ?? \"\"\n const c = this.#cursor()\n this.#preferredCol = undefined\n if (c >= v.length) return\n this.#historyEdit()\n const marker = this.#markerRange(c, \"forward\")\n if (marker) return this.#deleteRange(marker.start, marker.end)\n this.state.value = v.slice(0, c) + v.slice(c + 1)\n },\n \"input.deleteWordBack\": (): void => {\n const v = this.state.value ?? \"\"\n const c = this.#cursor()\n this.#preferredCol = undefined\n let i = c\n while (i > 0 && isWhitespace(v[i - 1])) i--\n while (i > 0 && !isWhitespace(v[i - 1])) i--\n if (i === c) return\n this.#historyEdit()\n this.state.set({ cursor: i, value: v.slice(0, i) + v.slice(c) })\n },\n \"input.insertNewline\": (): void => {\n // Smart indent: copy the leading whitespace of the current\n // logical line onto the new line so continuations stay aligned\n // with the bullet / quote / prefix the user typed.\n const v = this.state.value ?? \"\"\n const c = this.#cursor()\n this.#preferredCol = undefined\n let lineStart = c\n while (lineStart > 0 && v[lineStart - 1] !== \"\\n\") lineStart--\n let indent = \"\"\n for (let i = lineStart; i < c; i++) {\n const ch = v[i]\n if (ch === \" \" || ch === \"\\t\") indent += ch\n else break\n }\n const insert = `\\n${indent}`\n this.#historyEdit()\n this.state.set({\n cursor: c + insert.length,\n value: v.slice(0, c) + insert + v.slice(c),\n })\n },\n \"input.insertTab\": (): void => {\n // Two spaces rather than `\\t` — terminal tab stops are\n // unpredictable (often 8 cells) and play badly with our per-row\n // layout. Soft tabs are the safer default; users wanting real\n // tabs can override the action.\n const v = this.state.value ?? \"\"\n const c = this.#cursor()\n this.#preferredCol = undefined\n const tab = \" \"\n this.#historyEdit()\n this.state.set({ cursor: c + tab.length, value: v.slice(0, c) + tab + v.slice(c) })\n },\n // `ctrl-v` queries the OS clipboard (via xclip / wl-paste / pbpaste /\n // PowerShell depending on platform). The richest content wins:\n //\n // - **image bytes** → one `attach` event with a temp PNG path.\n // - **file references** → one `attach` event per file.\n // - **plain text** → inserted at the cursor like a regular paste.\n //\n // Fire-and-forget async — we await the probe and commit the\n // result in a microtask.\n \"input.paste\": (): void => {\n void (async (): Promise<void> => {\n const content = await clipboard.read()\n if (!content) return\n\n // Route through the regular paste handler\n if (content.kind === \"text\") {\n void this.emit(\"paste\", {\n paste: {\n stop: () => void 0,\n stopped: false,\n text: content.text,\n },\n })\n return\n }\n\n const paths: string[] = content.kind === \"image\" ? [content.path] : content.paths\n const files = await Promise.all(paths.map((path) => fileDetect({ path })))\n for (let i = 0; i < paths.length; i++) {\n const path = paths[i]\n const file = files[i]\n if (!file) continue\n this.attach({ ...file, path })\n }\n })()\n },\n \"input.submit\": (): void => {\n const value = this.state.value ?? \"\"\n if (this.state.validate?.(value) === false) return\n const ret = this.consume()\n this.#historyAdd(ret.value)\n void this.emit(\"submit\", ret)\n },\n } satisfies NodeActionMap\n\n constructor(initial: InputState = {}) {\n const value = initial.value ?? \"\"\n super({ cursor: value.length, value, ...initial })\n this.#history = [...(initial.history ?? [])]\n this.on(\"key\", ({ key }) => {\n this.#handleKey(key)\n })\n this.on(\"paste\", ({ paste }) => {\n this.paste(paste.text)\n paste.stop()\n })\n this.on(\"focus\", () => {\n this.#focused = true\n this.invalidate()\n })\n this.on(\"blur\", () => {\n this.#focused = false\n this.invalidate()\n })\n\n this.on(\"mount\", () => {\n this.ctx?.input.events.on(\"terminal-focus\", () => this.invalidate(), {\n signal: this.mountSignal,\n })\n })\n }\n\n get history(): readonly string[] {\n return this.#history\n }\n\n set history(v: readonly string[]) {\n this.#history = [...v]\n this.#historyIndex = undefined\n }\n\n attach(att: InputAttachment | Paste): void {\n if (att.type !== \"paste\" && this.state.canAttach?.(att) === false) {\n // Caller doesn't want this attachment (e.g. model doesn't support it) — fall\n // back to pasting the path as plain text\n return this.insert(att.path)\n }\n\n const id = this.#staged.length + 1\n let prefix = att.type[0].toUpperCase() + att.type.slice(1)\n let suffix = \"\"\n if (att.type === \"paste\") {\n prefix = \"Pasted text\"\n suffix = ` +${countLines(att.text)} lines`\n } else if (![\"image\", \"pdf\"].includes(att.type)) suffix = ` ${basename(att.path)}`\n const marker = `[${prefix} #${id}${suffix}]`\n this.#staged.push({ ...att, id, marker })\n this.insert(marker)\n\n if (att.type !== \"paste\") void this.emit(\"attach\", { attachment: att })\n }\n\n paste(text: string): void {\n if (\n countLines(text) > (this.state.pasteMaxLines ?? PASTE_MAX_LINES) ||\n stringWidth(text) > (this.state.pasteMaxChars ?? PASTE_MAX_CHARS)\n )\n return this.attach({ text, type: \"paste\" })\n this.insert(text)\n }\n\n insert(text: string): void {\n const v = this.state.value ?? \"\"\n const c = this.#cursor()\n this.#historyEdit()\n this.#preferredCol = undefined\n this.state.set({\n cursor: c + text.length,\n value: v.slice(0, c) + text + v.slice(c),\n })\n }\n\n replace(text: string): void {\n this.state.value = \"\"\n this.insert(text)\n }\n\n /** Consume the input's current value and attachments.\n * Pastes are replaced inline with their text; file/image\n * attachments are returned in the `attachments` array and removed from the value. */\n consume(): InputValue {\n let value = this.state.value ?? \"\"\n const atts: InputAttachment[] = []\n for (const att of this.#staged) {\n if (!value.includes(att.marker)) continue\n if (att.type === \"paste\") {\n value = value.replace(att.marker, att.text)\n } else atts.push(att)\n }\n this.#staged = []\n this.#preferredCol = undefined\n this.state.set({ cursor: 0, value: \"\" })\n return { attachments: atts, value }\n }\n\n #cursor(): number {\n const v = this.state.value ?? \"\"\n return Math.max(0, Math.min(v.length, this.state.cursor ?? 0))\n }\n\n #deleteRange(start: number, end: number): void {\n const v = this.state.value ?? \"\"\n this.#historyEdit()\n this.#preferredCol = undefined\n this.state.set({ cursor: start, value: v.slice(0, start) + v.slice(end) })\n }\n\n historyAdd(value: string): void {\n this.#historyAdd(value)\n }\n\n #historyAdd(value: string): void {\n if (value.trim() === \"\") return\n if (this.#history.at(-1) !== value) {\n this.#history.push(value)\n void this.emit(\"history\", { added: value, history: [...this.#history] })\n }\n this.#historyDraft = \"\"\n this.#historyIndex = undefined\n }\n\n #historyEdit(): void {\n this.#historyDraft = \"\"\n this.#historyIndex = undefined\n }\n\n #historyNext(): void {\n if (this.#historyIndex === undefined) return\n const next = this.#historyIndex + 1\n if (next >= this.#history.length) {\n this.#historySet(this.#historyDraft)\n this.#historyDraft = \"\"\n this.#historyIndex = undefined\n return\n }\n this.#historyIndex = next\n this.#historySet(this.#history[next])\n }\n\n #historyPrev(): void {\n if (this.#history.length === 0) return\n if (this.#historyIndex === undefined) {\n this.#historyDraft = this.state.value ?? \"\"\n this.#historyIndex = this.#history.length - 1\n } else if (this.#historyIndex > 0) this.#historyIndex--\n this.#historySet(this.#history[this.#historyIndex])\n }\n\n #historySet(value: string): void {\n this.#preferredCol = undefined\n this.state.set({ cursor: value.length, value })\n }\n\n #markerRange(pos: number, dir: \"back\" | \"forward\"): { start: number; end: number } | undefined {\n const value = this.state.value ?? \"\"\n for (const att of this.#staged) {\n const start = value.indexOf(att.marker)\n if (start === -1) continue\n const end = start + att.marker.length\n if (dir === \"back\" && pos > start && pos <= end) return { end, start }\n if (dir === \"forward\" && pos >= start && pos < end) return { end, start }\n }\n }\n\n // Fallback path for anything the router couldn't resolve to a named\n // action: printable characters go straight into the value. Any other\n // unbound key (f7, unclaimed ctrl-combos, etc.) bubbles untouched.\n #handleKey(ev: RoutedKey): void {\n if (ev.text === undefined || ev.ctrl || ev.alt || ev.meta) return\n this.insert(ev.text)\n ev.stop()\n }\n\n #format(value: string, ctx: RenderCtx): string {\n const format = this.state.format\n if (!format) return value\n\n if (ctx.version !== this.#formatCache.version) {\n this.#formatCache.clear()\n this.#formatCache.version = ctx.version\n }\n\n const key = hash(value)\n const cached = this.#formatCache.get(key)\n if (cached?.result !== undefined) return cached.result\n const streaming = this.#streamingFormat(value)\n if (cached?.promise) return streaming ?? value\n\n const ret = format(value, { style: ctx.style })\n if (!isPromiseLike(ret)) return ret\n\n const gen = ++this.#formatGen\n const entry: FormatEntry = { input: value }\n entry.promise = ret.then(\n (result) => {\n if (this.#formatCache.get(key) !== entry) return\n entry.result = result\n entry.promise = undefined\n if (this.#formatGen === gen && result !== value) untrack(() => this.invalidate())\n },\n () => {\n if (this.#formatCache.get(key) === entry) this.#formatCache.delete(key)\n }\n )\n this.#formatCache.set(key, entry)\n while (this.#formatCache.size > 100)\n this.#formatCache.delete(this.#formatCache.keys().next().value!)\n return streaming ?? value\n }\n\n /** Reuse a highlighted prefix while async formatting catches up. */\n #streamingFormat(value: string): string | undefined {\n let ret: [string, FormatEntry] | undefined\n for (const [key, cached] of this.#formatCache) {\n if (cached.result === undefined) continue\n if (value.startsWith(cached.input) && cached.input.length > (ret?.[1].input.length ?? 0))\n ret = [key, cached]\n }\n if (ret === undefined) return\n this.#formatCache.delete(ret[0])\n this.#formatCache.set(ret[0], ret[1]) // bump to end of LRU\n return ret[1].result + value.slice(ret[1].input.length)\n }\n\n protected async _render(ctx: RenderCtx): Promise<string[]> {\n const value = this.state.value ?? \"\"\n const placeholder = this.state.placeholder ?? \"\"\n const cursor = this.#cursor()\n const focused = this.#focused\n\n // Build the styled content string. Layout (word-wrap, split into\n // rows, pad to width) is delegated to `Text` below — wrap-ansi knows\n // how to close+reopen SGR across line breaks, so the inverse-cursor\n // span survives wrapping.\n let content: string\n if (value === \"\") {\n const ph = unwrap(placeholder)\n content = ph ? ` ${ctx.style.quiet(ph)}` : \"\"\n } else {\n content = value\n for (const att of this.#staged) {\n if (!content.includes(att.marker)) continue\n content = content.replace(att.marker, ctx.style.accent(att.marker))\n }\n content = this.#format(content, ctx)\n }\n\n // Fake cursor. `cursor` is an absolute index in the raw value, while\n // rendering is line-oriented: newlines consume string indices but not\n // cells in any rendered row. Project the cursor to line/column before\n // slicing the formatted line.\n if (focused && this.ctx?.input.terminalFocus) {\n const { col, line } = posToLineCol(value, cursor)\n const lines = splitAnsi(content)\n const target = Math.max(0, Math.min(line, lines.length - 1))\n const row = lines[target] ?? \"\"\n const head = sliceAnsi(row, 0, col)\n const at = sliceAnsi(row, col, col + 1) || \" \"\n const tail = sliceAnsi(row, col + 1)\n lines[target] = head + ctx.style.inverse(at) + tail\n content = lines.join(\"\\n\")\n }\n\n return formatText(content, {\n style: ctx.style.add(this.state),\n width: ctx.width,\n wrap: \"word\",\n })\n }\n}\n\n/**\n * Factory for `Input`. All fields optional; default is an empty,\n * focusable input that fills `ctx.width` and has no placeholder.\n *\n * ```ts\n * input({ placeholder: \"type a message…\" })\n * const i = input({ value: \"draft\" })\n * i.on(\"submit\", (text) => console.log(\"user typed\", text))\n * ```\n */\nexport function input(state: InputState = {}): Input {\n return new Input(state)\n}\n\n// ---------- helpers ----------\n\nfunction isWhitespace(ch: string | undefined): boolean {\n return ch !== undefined && (ch === \" \" || ch === \"\\t\" || ch === \"\\n\")\n}\n\nfunction posToLineCol(value: string, cursor: number): { line: number; col: number } {\n const prefix = value.slice(0, cursor)\n const lineStart = prefix.lastIndexOf(\"\\n\") + 1\n return {\n col: stringWidth(prefix.slice(lineStart)),\n line: prefix.split(\"\\n\").length - 1,\n }\n}\n\nfunction lineColToPos(value: string, line: number, col: number): number {\n const lines = value.split(\"\\n\")\n const clampLine = Math.max(0, Math.min(line, lines.length - 1))\n let abs = 0\n for (let i = 0; i < clampLine; i++) abs += lines[i].length + 1\n\n let cells = 0\n let offset = 0\n for (const { segment } of graphemes.segment(lines[clampLine])) {\n const width = stringWidth(segment)\n if (cells + width > col) break\n cells += width\n offset += segment.length\n }\n return abs + offset\n}\n\nfunction lineEndPos(value: string, cursor: number): number {\n let i = cursor\n while (i < value.length && value[i] !== \"\\n\") i++\n return i\n}\n\nfunction countLines(value: string): number {\n let n = 1\n for (const ch of value) if (ch === \"\\n\") n++\n return n\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"input-BkE4EpBw.mjs","names":[],"sources":["../src/widgets/input.ts"],"sourcesContent":["import type { MaybePromise } from \"@zaly/shared\"\nimport type { DetectedFile } from \"@zaly/shared/detect\"\nimport type { RenderCtx } from \"../core/ctx.ts\"\nimport type { BaseEvents } from \"../core/node.ts\"\nimport type { Reactive } from \"../core/reactive.ts\"\nimport type { StyleState } from \"../core/state.ts\"\nimport type { NodeActionMap } from \"../input/actions.ts\"\nimport type { RoutedKey } from \"../input/router.ts\"\nimport type { Size } from \"../layout/size.ts\"\nimport type { StyleBuilder } from \"../style/builder.ts\"\n\nimport { hash, isPromiseLike } from \"@zaly/shared\"\nimport { sliceAnsi, splitAnsi, stringWidth } from \"@zaly/shared/ansi\"\nimport { fileDetect } from \"@zaly/shared/detect\"\nimport { basename } from \"pathe\"\nimport { Node } from \"../core/node.ts\"\nimport { untrack, unwrap } from \"../core/reactive.ts\"\nimport { clipboard } from \"../input/clipboard.ts\"\nimport { formatText } from \"../layout/text.ts\"\n\nexport interface InputState extends StyleState {\n /** Current text content. May include `\\n` for multi-line input. */\n value?: string\n /** Shown dim when `value` is empty. */\n placeholder?: Reactive<string | undefined>\n /** Cursor position as a char index in `value`. Clamped to `[0, value.length]`. */\n cursor?: number\n /** Render width. Defaults to `fill`. */\n width?: Size\n /** Submitted input history, newest last. */\n history?: readonly string[]\n /** Threshold for showing pasted content as an attachment rather than raw text */\n pasteMaxLines?: number\n pasteMaxChars?: number\n canAttach?: (file: InputAttachment) => boolean\n format?: (value: string, ctx: { style: StyleBuilder }) => MaybePromise<string>\n validate?: (value: string) => boolean\n}\n\nexport type InputValue = { value: string; attachments: InputAttachment[] }\n\nconst PASTE_MAX_LINES = 5\nconst PASTE_MAX_CHARS = 1000\nconst graphemes = new Intl.Segmenter(undefined, { granularity: \"grapheme\" })\n\n/** A clipboard or bracketed paste that exceeds the `pasteMax*` thresholds. **/\ntype Paste = { type: \"paste\"; text: string }\n\n/** A file or image attachment detected from the clipboard. */\nexport type InputAttachment = DetectedFile & { path: string }\n\nexport type InputEvents = BaseEvents & {\n /** Fired when the submitted history changes. */\n history: { history: string[]; added: string }\n /** Fired when plain Enter is pressed. Payload is the current value. */\n submit: { value: string; attachments: InputAttachment[] }\n /** Fired when the user pastes a non-text resource via the\n * `input.paste` action. Images and file references both land here,\n * discriminated by `attachment.kind`. One event fires per image\n * paste; one per file in a multi-file paste.\n *\n * Wrapped under `attachment` because `InputAttachment` carries its\n * own `type` field (MIME) that would shadow the envelope's `type`\n * discriminator if spread directly. */\n attach: { attachment: InputAttachment }\n}\n\ntype FormatEntry = { promise?: Promise<void>; result?: string; input: string }\n\n/**\n * Multi-line text input with auto-grow.\n *\n * Editing commands (`cursorLeft`, `deleteWordBack`, `submit`, …) live on\n * `this.actions` as zero-arg methods. The input router maps keymap\n * bindings like `\"input.cursorLeft\"` onto those methods — users bind\n * different keys by configuring the keymap, not by patching the class.\n * The methods are also callable directly (`input.actions.submit()`),\n * which is handy in tests or for higher-level macros.\n *\n * What this class *still* handles via its `key` event listener:\n * - **Printable character insertion.** An unbound keystroke whose\n * `text` is set and has no ctrl/alt/meta modifier becomes a literal\n * insert at the cursor. There's no action for every printable char\n * in the keymap; the raw-key fallback handles them.\n * - **Paste events.** Whole payload inserted at cursor; always.\n *\n * Everything else (navigation, editing, submit/newline) goes through\n * the router → actions pipeline. Unbound non-printable keys fall back\n * to `emit(\"key\", …)` and bubble to the parent chain.\n *\n * Rendering word-wraps each logical line to `ctx.width`, so long\n * messages naturally grow vertically. The UI surface resizes its\n * reserved footer when the Input's row count changes, so the stream\n * above shifts accordingly.\n */\nexport class Input extends Node<InputState, InputEvents> {\n /** Class-level scope tag used by the input router to bind keymaps. */\n static readonly type = \"input\"\n\n override readonly type = Input.type\n #focused = false\n #history: string[] = []\n #historyDraft = \"\"\n #historyIndex: number | undefined\n #preferredCol: number | undefined\n #staged: ((InputAttachment | Paste) & { id: number; marker: string })[] = []\n #formatCache: Map<string, FormatEntry> & { version?: number } = new Map<string, FormatEntry>()\n #formatGen = 0\n\n /**\n * Editing actions. Parameterless — they close over `this` — so both\n * the router (via keymap dispatch) and application code can invoke\n * them. Add to the keymap in `src/input/actions.ts` to give them\n * default key bindings.\n */\n override actions = {\n \"input.cursorDown\": (): void => {\n const v = this.state.value ?? \"\"\n const { col, line } = posToLineCol(v, this.#cursor())\n if (line >= countLines(v) - 1) {\n this.#historyNext()\n return\n }\n this.#preferredCol ??= col\n this.state.cursor = lineColToPos(v, line + 1, this.#preferredCol)\n },\n \"input.cursorLeft\": (): void => {\n const c = this.#cursor()\n this.#preferredCol = undefined\n this.state.cursor = c > 0 ? c - 1 : c\n },\n \"input.cursorLineEnd\": (): void => {\n const v = this.state.value ?? \"\"\n this.#preferredCol = undefined\n this.state.cursor = lineEndPos(v, this.#cursor())\n },\n \"input.cursorLineStart\": (): void => {\n const v = this.state.value ?? \"\"\n const { line } = posToLineCol(v, this.#cursor())\n this.#preferredCol = undefined\n this.state.cursor = lineColToPos(v, line, 0)\n },\n \"input.cursorRight\": (): void => {\n const v = this.state.value ?? \"\"\n const c = this.#cursor()\n this.#preferredCol = undefined\n this.state.cursor = c < v.length ? c + 1 : c\n },\n \"input.cursorUp\": (): void => {\n const v = this.state.value ?? \"\"\n const { col, line } = posToLineCol(v, this.#cursor())\n if (line === 0) {\n this.#historyPrev()\n return\n }\n this.#preferredCol ??= col\n this.state.cursor = lineColToPos(v, line - 1, this.#preferredCol)\n },\n \"input.deleteCharBack\": (): void => {\n const v = this.state.value ?? \"\"\n const c = this.#cursor()\n this.#preferredCol = undefined\n if (c === 0) return\n this.#historyEdit()\n const marker = this.#markerRange(c, \"back\")\n if (marker) return this.#deleteRange(marker.start, marker.end)\n this.state.set({ cursor: c - 1, value: v.slice(0, c - 1) + v.slice(c) })\n },\n \"input.deleteCharForward\": (): void => {\n const v = this.state.value ?? \"\"\n const c = this.#cursor()\n this.#preferredCol = undefined\n if (c >= v.length) return\n this.#historyEdit()\n const marker = this.#markerRange(c, \"forward\")\n if (marker) return this.#deleteRange(marker.start, marker.end)\n this.state.value = v.slice(0, c) + v.slice(c + 1)\n },\n \"input.deleteWordBack\": (): void => {\n const v = this.state.value ?? \"\"\n const c = this.#cursor()\n this.#preferredCol = undefined\n let i = c\n while (i > 0 && isWhitespace(v[i - 1])) i--\n while (i > 0 && !isWhitespace(v[i - 1])) i--\n if (i === c) return\n this.#historyEdit()\n this.state.set({ cursor: i, value: v.slice(0, i) + v.slice(c) })\n },\n \"input.insertNewline\": (): void => {\n // Smart indent: copy the leading whitespace of the current\n // logical line onto the new line so continuations stay aligned\n // with the bullet / quote / prefix the user typed.\n const v = this.state.value ?? \"\"\n const c = this.#cursor()\n this.#preferredCol = undefined\n let lineStart = c\n while (lineStart > 0 && v[lineStart - 1] !== \"\\n\") lineStart--\n let indent = \"\"\n for (let i = lineStart; i < c; i++) {\n const ch = v[i]\n if (ch === \" \" || ch === \"\\t\") indent += ch\n else break\n }\n const insert = `\\n${indent}`\n this.#historyEdit()\n this.state.set({\n cursor: c + insert.length,\n value: v.slice(0, c) + insert + v.slice(c),\n })\n },\n \"input.insertTab\": (): void => {\n // Two spaces rather than `\\t` — terminal tab stops are\n // unpredictable (often 8 cells) and play badly with our per-row\n // layout. Soft tabs are the safer default; users wanting real\n // tabs can override the action.\n const v = this.state.value ?? \"\"\n const c = this.#cursor()\n this.#preferredCol = undefined\n const tab = \" \"\n this.#historyEdit()\n this.state.set({ cursor: c + tab.length, value: v.slice(0, c) + tab + v.slice(c) })\n },\n // `ctrl-v` queries the OS clipboard (via xclip / wl-paste / pbpaste /\n // PowerShell depending on platform). The richest content wins:\n //\n // - **image bytes** → one `attach` event with a temp PNG path.\n // - **file references** → one `attach` event per file.\n // - **plain text** → inserted at the cursor like a regular paste.\n //\n // Fire-and-forget async — we await the probe and commit the\n // result in a microtask.\n \"input.paste\": (): void => {\n void (async (): Promise<void> => {\n const content = await clipboard.read()\n if (!content) return\n\n // Route through the regular paste handler\n if (content.kind === \"text\") {\n void this.emit(\"paste\", {\n paste: {\n stop: () => void 0,\n stopped: false,\n text: content.text,\n },\n })\n return\n }\n\n const paths: string[] = content.kind === \"image\" ? [content.path] : content.paths\n const files = await Promise.all(paths.map((path) => fileDetect({ path })))\n for (let i = 0; i < paths.length; i++) {\n const path = paths[i]\n const file = files[i]\n if (!file) continue\n this.attach({ ...file, path })\n }\n })()\n },\n \"input.submit\": (): void => {\n const value = this.state.value ?? \"\"\n if (this.state.validate?.(value) === false) return\n const ret = this.consume()\n this.#historyAdd(ret.value)\n void this.emit(\"submit\", ret)\n },\n } satisfies NodeActionMap\n\n constructor(initial: InputState = {}) {\n const value = initial.value ?? \"\"\n super({ cursor: value.length, value, ...initial })\n this.#history = [...(initial.history ?? [])]\n this.on(\"key\", ({ key }) => {\n this.#handleKey(key)\n })\n this.on(\"paste\", ({ paste }) => {\n this.paste(paste.text)\n paste.stop()\n })\n this.on(\"focus\", () => {\n this.#focused = true\n this.invalidate()\n })\n this.on(\"blur\", () => {\n this.#focused = false\n this.invalidate()\n })\n\n this.on(\"mount\", () => {\n this.ctx?.input.events.on(\"terminal-focus\", () => this.invalidate(), {\n signal: this.mountSignal,\n })\n })\n }\n\n get history(): readonly string[] {\n return this.#history\n }\n\n set history(v: readonly string[]) {\n this.#history = [...v]\n this.#historyIndex = undefined\n }\n\n attach(att: InputAttachment | Paste): void {\n if (att.type !== \"paste\" && this.state.canAttach?.(att) === false) {\n // Caller doesn't want this attachment (e.g. model doesn't support it) — fall\n // back to pasting the path as plain text\n return this.insert(att.path)\n }\n\n const id = this.#staged.length + 1\n let prefix = att.type[0].toUpperCase() + att.type.slice(1)\n let suffix = \"\"\n if (att.type === \"paste\") {\n prefix = \"Pasted text\"\n suffix = ` +${countLines(att.text)} lines`\n } else if (![\"image\", \"pdf\"].includes(att.type)) suffix = ` ${basename(att.path)}`\n const marker = `[${prefix} #${id}${suffix}]`\n this.#staged.push({ ...att, id, marker })\n this.insert(marker)\n\n if (att.type !== \"paste\") void this.emit(\"attach\", { attachment: att })\n }\n\n paste(text: string): void {\n if (\n countLines(text) > (this.state.pasteMaxLines ?? PASTE_MAX_LINES) ||\n stringWidth(text) > (this.state.pasteMaxChars ?? PASTE_MAX_CHARS)\n )\n return this.attach({ text, type: \"paste\" })\n this.insert(text)\n }\n\n insert(text: string): void {\n const v = this.state.value ?? \"\"\n const c = this.#cursor()\n this.#historyEdit()\n this.#preferredCol = undefined\n this.state.set({\n cursor: c + text.length,\n value: v.slice(0, c) + text + v.slice(c),\n })\n }\n\n replace(text: string): void {\n this.state.value = \"\"\n this.insert(text)\n }\n\n /** Consume the input's current value and attachments.\n * Pastes are replaced inline with their text; file/image\n * attachments are returned in the `attachments` array and removed from the value. */\n consume(): InputValue {\n let value = this.state.value ?? \"\"\n const atts: InputAttachment[] = []\n for (const att of this.#staged) {\n if (!value.includes(att.marker)) continue\n if (att.type === \"paste\") {\n value = value.replace(att.marker, att.text)\n } else atts.push(att)\n }\n this.#staged = []\n this.#preferredCol = undefined\n this.state.set({ cursor: 0, value: \"\" })\n return { attachments: atts, value }\n }\n\n #cursor(): number {\n const v = this.state.value ?? \"\"\n return Math.max(0, Math.min(v.length, this.state.cursor ?? 0))\n }\n\n #deleteRange(start: number, end: number): void {\n const v = this.state.value ?? \"\"\n this.#historyEdit()\n this.#preferredCol = undefined\n this.state.set({ cursor: start, value: v.slice(0, start) + v.slice(end) })\n }\n\n historyAdd(value: string): void {\n this.#historyAdd(value)\n }\n\n #historyAdd(value: string): void {\n if (value.trim() === \"\") return\n if (this.#history.at(-1) !== value) {\n this.#history.push(value)\n void this.emit(\"history\", { added: value, history: [...this.#history] })\n }\n this.#historyDraft = \"\"\n this.#historyIndex = undefined\n }\n\n #historyEdit(): void {\n this.#historyDraft = \"\"\n this.#historyIndex = undefined\n }\n\n #historyNext(): void {\n if (this.#historyIndex === undefined) return\n const next = this.#historyIndex + 1\n if (next >= this.#history.length) {\n this.#historySet(this.#historyDraft)\n this.#historyDraft = \"\"\n this.#historyIndex = undefined\n return\n }\n this.#historyIndex = next\n this.#historySet(this.#history[next])\n }\n\n #historyPrev(): void {\n if (this.#history.length === 0) return\n if (this.#historyIndex === undefined) {\n this.#historyDraft = this.state.value ?? \"\"\n this.#historyIndex = this.#history.length - 1\n } else if (this.#historyIndex > 0) this.#historyIndex--\n this.#historySet(this.#history[this.#historyIndex])\n }\n\n #historySet(value: string): void {\n this.#preferredCol = undefined\n this.state.set({ cursor: value.length, value })\n }\n\n #markerRange(pos: number, dir: \"back\" | \"forward\"): { start: number; end: number } | undefined {\n const value = this.state.value ?? \"\"\n for (const att of this.#staged) {\n const start = value.indexOf(att.marker)\n if (start === -1) continue\n const end = start + att.marker.length\n if (dir === \"back\" && pos > start && pos <= end) return { end, start }\n if (dir === \"forward\" && pos >= start && pos < end) return { end, start }\n }\n }\n\n // Fallback path for anything the router couldn't resolve to a named\n // action: printable characters go straight into the value. Any other\n // unbound key (f7, unclaimed ctrl-combos, etc.) bubbles untouched.\n #handleKey(ev: RoutedKey): void {\n if (ev.text === undefined || ev.ctrl || ev.alt || ev.meta) return\n this.insert(ev.text)\n ev.stop()\n }\n\n #format(value: string, ctx: RenderCtx): string {\n const format = this.state.format\n if (!format) return value\n\n if (ctx.version !== this.#formatCache.version) {\n this.#formatCache.clear()\n this.#formatCache.version = ctx.version\n }\n\n const key = hash(value)\n const cached = this.#formatCache.get(key)\n if (cached?.result !== undefined) return cached.result\n const streaming = this.#streamingFormat(value)\n if (cached?.promise) return streaming ?? value\n\n const ret = format(value, { style: ctx.style })\n if (!isPromiseLike(ret)) return ret\n\n const gen = ++this.#formatGen\n const entry: FormatEntry = { input: value }\n entry.promise = ret.then(\n (result) => {\n if (this.#formatCache.get(key) !== entry) return\n entry.result = result\n entry.promise = undefined\n if (this.#formatGen === gen && result !== value) untrack(() => this.invalidate())\n },\n () => {\n if (this.#formatCache.get(key) === entry) this.#formatCache.delete(key)\n }\n )\n this.#formatCache.set(key, entry)\n while (this.#formatCache.size > 100)\n this.#formatCache.delete(this.#formatCache.keys().next().value!)\n return streaming ?? value\n }\n\n /** Reuse a highlighted prefix while async formatting catches up. */\n #streamingFormat(value: string): string | undefined {\n let ret: [string, FormatEntry] | undefined\n for (const [key, cached] of this.#formatCache) {\n if (cached.result === undefined) continue\n if (value.startsWith(cached.input) && cached.input.length > (ret?.[1].input.length ?? 0))\n ret = [key, cached]\n }\n if (ret === undefined) return\n this.#formatCache.delete(ret[0])\n this.#formatCache.set(ret[0], ret[1]) // bump to end of LRU\n return ret[1].result + value.slice(ret[1].input.length)\n }\n\n protected async _render(ctx: RenderCtx): Promise<string[]> {\n const value = this.state.value ?? \"\"\n const placeholder = this.state.placeholder ?? \"\"\n const cursor = this.#cursor()\n const focused = this.#focused\n\n // Build the styled content string. Layout (word-wrap, split into\n // rows, pad to width) is delegated to `Text` below — wrap-ansi knows\n // how to close+reopen SGR across line breaks, so the inverse-cursor\n // span survives wrapping.\n let content: string\n if (value === \"\") {\n const ph = unwrap(placeholder)\n content = ph ? ` ${ctx.style.quiet(ph)}` : \"\"\n } else {\n content = value\n for (const att of this.#staged) {\n if (!content.includes(att.marker)) continue\n content = content.replace(att.marker, ctx.style.accent(att.marker))\n }\n content = this.#format(content, ctx)\n }\n\n // Fake cursor. `cursor` is an absolute index in the raw value, while\n // rendering is line-oriented: newlines consume string indices but not\n // cells in any rendered row. Project the cursor to line/column before\n // slicing the formatted line.\n if (focused && this.ctx?.input.terminalFocus) {\n const { col, line } = posToLineCol(value, cursor)\n const lines = splitAnsi(content)\n const target = Math.max(0, Math.min(line, lines.length - 1))\n const row = lines[target] ?? \"\"\n const head = sliceAnsi(row, 0, col)\n const at = sliceAnsi(row, col, col + 1) || \" \"\n const tail = sliceAnsi(row, col + 1)\n lines[target] = head + ctx.style.inverse(at) + tail\n content = lines.join(\"\\n\")\n }\n\n return formatText(content, {\n style: ctx.style.add(this.state),\n width: ctx.width,\n wrap: \"word\",\n })\n }\n}\n\n/**\n * Factory for `Input`. All fields optional; default is an empty,\n * focusable input that fills `ctx.width` and has no placeholder.\n *\n * ```ts\n * input({ placeholder: \"type a message…\" })\n * const i = input({ value: \"draft\" })\n * i.on(\"submit\", (text) => console.log(\"user typed\", text))\n * ```\n */\nexport function input(state: InputState = {}): Input {\n return new Input(state)\n}\n\n// ---------- helpers ----------\n\nfunction isWhitespace(ch: string | undefined): boolean {\n return ch !== undefined && (ch === \" \" || ch === \"\\t\" || ch === \"\\n\")\n}\n\nfunction posToLineCol(value: string, cursor: number): { line: number; col: number } {\n const prefix = value.slice(0, cursor)\n const lineStart = prefix.lastIndexOf(\"\\n\") + 1\n return {\n col: stringWidth(prefix.slice(lineStart)),\n line: prefix.split(\"\\n\").length - 1,\n }\n}\n\nfunction lineColToPos(value: string, line: number, col: number): number {\n const lines = value.split(\"\\n\")\n const clampLine = Math.max(0, Math.min(line, lines.length - 1))\n let abs = 0\n for (let i = 0; i < clampLine; i++) abs += lines[i].length + 1\n\n let cells = 0\n let offset = 0\n for (const { segment } of graphemes.segment(lines[clampLine])) {\n const width = stringWidth(segment)\n if (cells + width > col) break\n cells += width\n offset += segment.length\n }\n return abs + offset\n}\n\nfunction lineEndPos(value: string, cursor: number): number {\n let i = cursor\n while (i < value.length && value[i] !== \"\\n\") i++\n return i\n}\n\nfunction countLines(value: string): number {\n let n = 1\n for (const ch of value) if (ch === \"\\n\") n++\n return n\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { $ as StyleState, Ft as Size, I as RenderCtx, h as Node, it as Reactive, m as BaseEvents } from "./queries-
|
|
2
|
-
import { a as StyleBuilder } from "./inspect-
|
|
1
|
+
import { $ as StyleState, Ft as Size, I as RenderCtx, h as Node, it as Reactive, m as BaseEvents } from "./queries-Dmd3IjSd.mjs";
|
|
2
|
+
import { a as StyleBuilder } from "./inspect-hSl3U2BD.mjs";
|
|
3
3
|
import { MaybePromise } from "@zaly/shared";
|
|
4
4
|
import { DetectedFile } from "@zaly/shared/detect";
|
|
5
|
-
//#region src/widgets/input.d.ts
|
|
6
5
|
interface InputState extends StyleState {
|
|
7
6
|
/** Current text content. May include `\n` for multi-line input. */
|
|
8
7
|
value?: string;
|
|
@@ -136,6 +135,5 @@ declare class Input extends Node<InputState, InputEvents> {
|
|
|
136
135
|
* ```
|
|
137
136
|
*/
|
|
138
137
|
declare function input(state?: InputState): Input;
|
|
139
|
-
//#endregion
|
|
140
138
|
export { InputValue as a, InputState as i, InputAttachment as n, input as o, InputEvents as r, Input as t };
|
|
141
|
-
//# sourceMappingURL=input-
|
|
139
|
+
//# sourceMappingURL=input-C3kfYoEJ.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-C3kfYoEJ.d.mts","names":[],"sources":["../src/widgets/input.ts"],"mappings":";;;;UAoBiB,mBAAmB;;EAElC;;EAEA,cAAc;;EAEd;;EAEA,QAAQ;;EAER;;EAEA;EACA;EACA,aAAa,MAAM;EACnB,UAAU,eAAe;IAAO,OAAO;QAAmB;EAC1D,YAAY;;KAGF;EAAe;EAAe,aAAa;;;KAOlD;EAAU;EAAe;;;KAGlB,kBAAkB;EAAiB;;KAEnC,cAAc;;EAExB;IAAW;IAAmB;;;EAE9B;IAAU;IAAe,aAAa;;;;;;;;;;EAStC;IAAU,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA+BX,cAAc,KAAK,YAAY;;;kBAE1B;WAEE;;;;;;;EAgBT;IACiB;IAUA;IAKG;IAKE;IAMJ;IAMH;IAUM;IAUG;IAUH;IAWD;IAsBJ;IAqBJ;IA2BC;;EAStB,YAAY,UAAS;MA2BjB;MAIA,QAAQ;EAKZ,OAAO,KAAK,kBAAkB;EAqB9B,MAAM;EASN,OAAO;EAWP,QAAQ;;;;EAQR,WAAW;EA2BX,WAAW;YAqHK,QAAQ,KAAK,YAAY;;;;;;;;;;;;iBAyD3B,MAAM,QAAO,aAAkB"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { t as styleBuilder } from "./builder-
|
|
1
|
+
import { t as styleBuilder } from "./builder-BdYlK1Ew.mjs";
|
|
2
2
|
import { hasAnsi } from "@zaly/shared/ansi";
|
|
3
3
|
import { hasColors } from "@zaly/shared/env";
|
|
4
4
|
import { formatWithOptions, inspect } from "node:util";
|
|
5
|
-
|
|
5
|
+
// src/style/inspect.ts
|
|
6
6
|
const MD_RE = /[`*_#[\]\->~|]/;
|
|
7
7
|
const JSON_RE = /^\s*[{[]/;
|
|
8
8
|
const FORMAT_RE = /%[sdifjoOc%]/;
|
|
@@ -95,7 +95,6 @@ function inspect$1(value, opts = {}) {
|
|
|
95
95
|
};
|
|
96
96
|
return $inspect(value, 1);
|
|
97
97
|
}
|
|
98
|
-
//#endregion
|
|
99
98
|
export { inspectFormat as n, isMarkdown as r, inspect$1 as t };
|
|
100
99
|
|
|
101
|
-
//# sourceMappingURL=inspect-
|
|
100
|
+
//# sourceMappingURL=inspect-Cli1beu8.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspect-
|
|
1
|
+
{"version":3,"file":"inspect-Cli1beu8.mjs","names":["inspect","nodeInspect"],"sources":["../src/style/inspect.ts"],"sourcesContent":["import type { StyleBuilder } from \"./builder.ts\"\n\nimport { hasAnsi } from \"@zaly/shared/ansi\"\nimport { hasColors } from \"@zaly/shared/env\"\nimport { formatWithOptions, inspect as nodeInspect } from \"node:util\"\nimport { styleBuilder } from \"./builder.ts\"\n\nexport interface InspectOpts {\n style?: StyleBuilder\n indent?: number\n undefined?: boolean\n null?: boolean\n /** When `true`, preserve Error stack traces. Default: `false` — Error\n * values are reduced to their `.message` so logs stay compact. */\n stacktrace?: boolean\n colors?: boolean\n}\n\n// Markdown-ish characters. Matches rekal's skip regex.\nconst MD_RE = /[`*_#[\\]\\->~|]/\nconst JSON_RE = /^\\s*[{[]/\n\n// `util.format` placeholder tokens (`%s`, `%d`, …).\nconst FORMAT_RE = /%[sdifjoOc%]/\n\n/** True when `s` looks like markdown we should render — contains MD\n * markers and isn't already ANSI-styled. Mirrors rekal's `Formatter.markdown`\n * skip test so we avoid double-rendering pre-styled strings. */\nexport function isMarkdown(s: string): boolean {\n return MD_RE.test(s) && !hasAnsi(s) && !JSON_RE.test(s)\n}\n\nconst isFormatString = (v: unknown): v is string =>\n typeof v === \"string\" && FORMAT_RE.test(v) && !hasAnsi(v)\n\n/**\n * Inspect a list of args the way `console.log` does, returning a single\n * string. Collapses `util.format` placeholders right-to-left, unwraps\n * `Error` values to their message (unless `stacktrace: true`), and falls\n * back to `util.formatWithOptions` for mixed values.\n */\nexport function inspectFormat(msg: unknown[], opts: InspectOpts = {}): string {\n const data = opts.stacktrace ? msg : msg.map((v) => (v instanceof Error ? v.message : v))\n opts = { colors: hasColors, ...opts }\n\n let ret: unknown[] = []\n // oxlint-disable-next-line oxc/no-accumulating-spread\n for (let i = data.length - 1; i >= 0; i--) {\n const item = data[i]\n if (isFormatString(item)) ret = [formatWithOptions(opts, item, ...ret)]\n else ret.unshift(item)\n }\n\n if (ret.length > 1 && isFormatString(ret[0])) return formatWithOptions(opts, ...ret)\n return ret.map((v) => (typeof v === \"string\" ? v : inspect(v, opts))).join(\" \")\n}\n\nfunction inspectNumber(value: number): string {\n return new Intl.NumberFormat(\"en-US\", {\n notation: \"standard\",\n useGrouping: true,\n })\n .format(value)\n .replace(/,/g, \"_\")\n}\n\nfunction inspectField(key: string, s: StyleBuilder): string {\n if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key)) return s.syntaxField(key)\n return s.syntaxString(JSON.stringify(key))\n}\n\nexport function inspect(value: unknown, opts: InspectOpts = {}): string {\n opts = { colors: hasColors, null: true, undefined: true, ...opts }\n const indent = opts.indent ?? 2\n const s = opts.colors ? (opts.style ?? styleBuilder()) : styleBuilder(false)\n const sym = {\n \",\": s.syntaxDelimiter(\",\"),\n \":\": s.syntaxDelimiter(\":\"),\n \"[\": s.syntaxBracket(\"[\"),\n \"]\": s.syntaxBracket(\"]\"),\n \"{\": s.syntaxBracket(\"{\"),\n \"}\": s.syntaxBracket(\"}\"),\n }\n const seen = new Set()\n\n const $inspect = (v: unknown, depth: number): string => {\n if (seen.has(v)) return s.bold(\"[Circular]\")\n if (typeof v === \"object\" && v !== null) seen.add(v)\n if (v === null) return s.syntaxConstant(\"null\")\n switch (typeof v) {\n case \"boolean\": {\n return s.syntaxBoolean(String(v))\n }\n case \"bigint\": {\n return s.syntaxNumber(`${v}n`)\n }\n case \"number\": {\n return s.syntaxNumber(inspectNumber(v))\n }\n case \"string\": {\n return s.syntaxString(JSON.stringify(v))\n }\n case \"symbol\": {\n return s.syntaxSpecial(String(v))\n }\n case \"function\": {\n return s.syntaxFunction(`[Function${v.name ? `: ${v.name}` : \"\"}]`)\n }\n case \"undefined\": {\n return s.syntaxConstant(\"undefined\")\n }\n case \"object\": {\n if (Array.isArray(v)) {\n const items = v.map((item) => $inspect(item, depth + 1))\n return `${sym[\"[\"]} ${items.join(`${sym[\",\"]} `)} ${sym[\"]\"]}`\n }\n const isPlainObject = Object.getPrototypeOf(v) === Object.prototype\n if (!isPlainObject) break\n const entries = Object.entries(v)\n .filter(\n ([, val]) => !((val === undefined && !opts.undefined) || (val === null && !opts.null))\n )\n .map(([key, val]) => `${inspectField(key, s)}: ${$inspect(val, depth + 1)}`)\n if (indent) {\n const padding = \" \".repeat(indent * depth)\n return `${sym[\"{\"]}\\n${padding}${entries.join(`${sym[\",\"]}\\n${padding}`)}\\n${\" \".repeat(indent * (depth - 1))}${sym[\"}\"]}`\n }\n return `${sym[\"{\"]} ${entries.join(`${sym[\",\"]} `)} ${sym[\"}\"]}`\n }\n }\n return nodeInspect(v, { colors: true, compact: true })\n }\n return $inspect(value, 1)\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { a as BrightAnsiColorName, d as ThemeKey, f as Theme, i as AnyStyle, n as AnsiColorName, o as Color } from "./types-
|
|
2
|
-
//#region src/style/builder.d.ts
|
|
1
|
+
import { a as BrightAnsiColorName, d as ThemeKey, f as Theme, i as AnyStyle, n as AnsiColorName, o as Color } from "./types-ByMHEdCF.mjs";
|
|
3
2
|
type AttrName = "bold" | "dim" | "italic" | "underline" | "inverse" | "strikethrough";
|
|
4
3
|
type ChainSlot<Ansi extends boolean = true> = Exclude<ThemeKey, "fg" | "bg" | AttrName> | (Ansi extends true ? AnsiColorName : never) | (Ansi extends true ? BrightAnsiColorName : never);
|
|
5
4
|
type StyleBuilder<Ansi extends boolean = false> = {
|
|
@@ -34,8 +33,6 @@ type StyleBuilder<Ansi extends boolean = false> = {
|
|
|
34
33
|
* Calling an empty builder is a no-op: `styleBuilder()("x")` returns `"x"` unchanged.
|
|
35
34
|
*/
|
|
36
35
|
declare function styleBuilder<Ansi extends boolean = false>(theme?: Theme | false): StyleBuilder<Ansi>;
|
|
37
|
-
//#endregion
|
|
38
|
-
//#region src/style/inspect.d.ts
|
|
39
36
|
interface InspectOpts {
|
|
40
37
|
style?: StyleBuilder;
|
|
41
38
|
indent?: number;
|
|
@@ -58,6 +55,5 @@ declare function isMarkdown(s: string): boolean;
|
|
|
58
55
|
*/
|
|
59
56
|
declare function inspectFormat(msg: unknown[], opts?: InspectOpts): string;
|
|
60
57
|
declare function inspect(value: unknown, opts?: InspectOpts): string;
|
|
61
|
-
//#endregion
|
|
62
58
|
export { StyleBuilder as a, isMarkdown as i, inspect as n, styleBuilder as o, inspectFormat as r, InspectOpts as t };
|
|
63
|
-
//# sourceMappingURL=inspect-
|
|
59
|
+
//# sourceMappingURL=inspect-hSl3U2BD.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect-hSl3U2BD.d.mts","names":[],"sources":["../src/style/builder.ts","../src/style/inspect.ts"],"mappings":";KAcK;KAKA,UAAU,+BACX,QAAQ,wBAAwB,aAC/B,oBAAoB,0BACpB,oBAAoB;KAEb,aAAa;EACvB,OAAO;GACN;EACD,KAAK,OAAO,MAAM,UAAU,aAAa;EACzC,KAAK,OAAO,MAAM,UAAU,aAAa;EACzC,MAAM,OAAO,WAAW,aAAa,aAAa;EAClD,UAAU,cAAc,aAAa;EACrC,SAAS,cAAc,aAAa;gBAIlC,KACI,WACA,UAAU,aACL,WAAW,UAAU,gBACrB,WAAW,UAAU,WAC7B,aAAa;;;;;;;;;;;;;;;;;;;;;;;iBAyBF,aAAa,8BAC3B,QAAO,gBACN,aAAa;UC5DC;EACf,QAAQ;EACR;EACA;EACA;;;EAGA;EACA;;;;;iBAac,WAAW;;;;;;;iBAaX,cAAc,gBAAgB,OAAM;iBA8BpC,QAAQ,gBAAgB,OAAM"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { s as loadKittyGraphics } from "./kitty-BH_eK6lz.mjs";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isSSH } from "@zaly/shared/env";
|
|
2
|
-
|
|
2
|
+
// src/image/kitty.ts
|
|
3
3
|
const DIACRITICS = [
|
|
4
4
|
773,
|
|
5
5
|
781,
|
|
@@ -667,7 +667,6 @@ function loadKittyGraphics(tq) {
|
|
|
667
667
|
prom ??= (async () => kitty = new Kitty(await detect(tq)))();
|
|
668
668
|
return prom;
|
|
669
669
|
}
|
|
670
|
-
//#endregion
|
|
671
670
|
export { allocatePlacementId as a, resetKittyGraphics as c, allocateImageId as i, resetTransmitCache as l, Kitty as n, bumpPlacements as o, PLACEHOLDER as r, loadKittyGraphics as s, DIACRITICS as t };
|
|
672
671
|
|
|
673
|
-
//# sourceMappingURL=kitty-
|
|
672
|
+
//# sourceMappingURL=kitty-BH_eK6lz.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kitty-JbCJC0iQ.mjs","names":[],"sources":["../src/image/kitty.ts"],"sourcesContent":["/**\n * Kitty Graphics Protocol — local-file transmission + native placements.\n *\n * Flow:\n * 1. Transmit once per src via `transmitFile(id, path)` (t=f). The\n * terminal loads the image bytes from the file path; nothing of the\n * image is transmitted over the wire beyond the path itself.\n * 2. On every render, emit `placement(imgId, placeId, { cols, rows })`\n * at the target cursor position. Re-sending a placement with the\n * same (image id, placement id) moves/resizes the existing placement\n * without flicker — ideal for re-renders.\n *\n * Reference: https://sw.kovidgoyal.net/kitty/graphics-protocol/\n */\n\nimport type { MaybePromise } from \"@zaly/shared\"\nimport type { ImageInfo } from \"@zaly/shared/image\"\nimport type { TerminalQueries, TerminalQuery } from \"../input/queries.ts\"\n\nimport { isSSH } from \"@zaly/shared/env\"\n\nexport type KittyPlacement = {\n imageId: number\n /** Placement ID. Omitted when this is an inline placement (U=1) */\n placementId?: number\n /** inline: placement using unicode placeholder (U=1) */\n inline?: boolean\n /** The KGP escape sequence to place the image */\n seq: string\n /** Rows to render (excluding the placement escape sequence) */\n data: string[]\n}\n\nexport type ImageSupport = {\n terminal?: { name: string; version?: string }\n remote?: boolean\n wrap?: (seq: string) => string\n tmux?: boolean\n} & (\n | {\n ok: false\n error: string\n terminal?: { name: string; version?: string }\n }\n | {\n ok: true\n error?: never\n terminal: { name: string; version?: string }\n inline?: boolean\n }\n)\n\nexport type KittyResponse =\n | {\n attrs: Record<string, string | number>\n ok: true\n }\n | {\n attrs: Record<string, string | number>\n ok: false\n error: { code: string; message: string }\n }\n\nexport type PlacementDims = {\n /** Display width in terminal cells. */\n cols: number\n /** Display height in terminal cells. */\n rows: number\n}\n\n// Per-src transmit cache. The first caller gets the full transmit sequence;\n// subsequent callers get undefined since the terminal already has the bytes.\ntype CacheEntry = {\n imageId: number\n seq: string\n sent: boolean\n}\n\n// oxfmt-ignore\n// oxlint-disable-next-line unicorn/numeric-separators-style\nexport const DIACRITICS = [ 0x0305, 0x030d, 0x030e, 0x0310, 0x0312, 0x033d, 0x033e, 0x033f, 0x0346, 0x034a, 0x034b, 0x034c, 0x0350, 0x0351, 0x0352, 0x0357, 0x035b, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0592, 0x0593, 0x0594, 0x0595, 0x0597, 0x0598, 0x0599, 0x059c, 0x059d, 0x059e, 0x059f, 0x05a0, 0x05a1, 0x05a8, 0x05a9, 0x05ab, 0x05ac, 0x05af, 0x05c4, 0x0610, 0x0611, 0x0612, 0x0613, 0x0614, 0x0615, 0x0616, 0x0617, 0x0657, 0x0658, 0x0659, 0x065a, 0x065b, 0x065d, 0x065e, 0x06d6, 0x06d7, 0x06d8, 0x06d9, 0x06da, 0x06db, 0x06dc, 0x06df, 0x06e0, 0x06e1, 0x06e2, 0x06e4, 0x06e7, 0x06e8, 0x06eb, 0x06ec, 0x0730, 0x0732, 0x0733, 0x0735, 0x0736, 0x073a, 0x073d, 0x073f, 0x0740, 0x0741, 0x0743, 0x0745, 0x0747, 0x0749, 0x074a, 0x07eb, 0x07ec, 0x07ed, 0x07ee, 0x07ef, 0x07f0, 0x07f1, 0x07f3, 0x0816, 0x0817, 0x0818, 0x0819, 0x081b, 0x081c, 0x081d, 0x081e, 0x081f, 0x0820, 0x0821, 0x0822, 0x0823, 0x0825, 0x0826, 0x0827, 0x0829, 0x082a, 0x082b, 0x082c, 0x082d, 0x0951, 0x0953, 0x0954, 0x0f82, 0x0f83, 0x0f86, 0x0f87, 0x135d, 0x135e, 0x135f, 0x17dd, 0x193a, 0x1a17, 0x1a75, 0x1a76, 0x1a77, 0x1a78, 0x1a79, 0x1a7a, 0x1a7b, 0x1a7c, 0x1b6b, 0x1b6d, 0x1b6e, 0x1b6f, 0x1b70, 0x1b71, 0x1b72, 0x1b73, 0x1cd0, 0x1cd1, 0x1cd2, 0x1cda, 0x1cdb, 0x1ce0, 0x1dc0, 0x1dc1, 0x1dc3, 0x1dc4, 0x1dc5, 0x1dc6, 0x1dc7, 0x1dc8, 0x1dc9, 0x1dcb, 0x1dcc, 0x1dd1, 0x1dd2, 0x1dd3, 0x1dd4, 0x1dd5, 0x1dd6, 0x1dd7, 0x1dd8, 0x1dd9, 0x1dda, 0x1ddb, 0x1ddc, 0x1ddd, 0x1dde, 0x1ddf, 0x1de0, 0x1de1, 0x1de2, 0x1de3, 0x1de4, 0x1de5, 0x1de6, 0x1dfe, 0x20d0, 0x20d1, 0x20d4, 0x20d5, 0x20d6, 0x20d7, 0x20db, 0x20dc, 0x20e1, 0x20e7, 0x20e9, 0x20f0, 0x2cef, 0x2cf0, 0x2cf1, 0x2de0, 0x2de1, 0x2de2, 0x2de3, 0x2de4, 0x2de5, 0x2de6, 0x2de7, 0x2de8, 0x2de9, 0x2dea, 0x2deb, 0x2dec, 0x2ded, 0x2dee, 0x2def, 0x2df0, 0x2df1, 0x2df2, 0x2df3, 0x2df4, 0x2df5, 0x2df6, 0x2df7, 0x2df8, 0x2df9, 0x2dfa, 0x2dfb, 0x2dfc, 0x2dfd, 0x2dfe, 0x2dff, 0xa66f, 0xa67c, 0xa67d, 0xa6f0, 0xa6f1, 0xa8e0, 0xa8e1, 0xa8e2, 0xa8e3, 0xa8e4, 0xa8e5, 0xa8e6, 0xa8e7, 0xa8e8, 0xa8e9, 0xa8ea, 0xa8eb, 0xa8ec, 0xa8ed, 0xa8ee, 0xa8ef, 0xa8f0, 0xa8f1, 0xaab0, 0xaab2, 0xaab3, 0xaab7, 0xaab8, 0xaabe, 0xaabf, 0xaac1, 0xfe20, 0xfe21, 0xfe22, 0xfe23, 0xfe24, 0xfe25, 0xfe26, 0x10a0f, 0x10a38, 0x1d185, 0x1d186, 0x1d187, 0x1d188, 0x1d189, 0x1d1aa, 0x1d1ab, 0x1d1ac, 0x1d1ad, 0x1d242, 0x1d243, 0x1d244 ].map((c) => String.fromCodePoint(c))\nexport const PLACEHOLDER = String.fromCodePoint(0x10_ee_ee)\nconst CHUNK_SIZE = 4096\nconst transmitCache = new Map<string, CacheEntry>()\n\nconst known: Record<string, { inline?: boolean } | false | undefined> = {\n ghostty: { inline: true },\n kitty: { inline: true },\n rio: { inline: false },\n wezterm: { inline: false },\n}\n\nlet prom: Promise<Kitty> | undefined = undefined\nlet kitty: Kitty | undefined = undefined\nconst wrapTmux = (seq: string): string => `\\x1bPtmux;${seq.replaceAll(\"\\x1b\", \"\\x1b\\x1b\")}\\x1b\\\\`\n\n/** Allocate a fresh 24-bit image id (1..0xFFFFFFFE). */\nexport function allocateImageId(): number {\n return Math.floor(Math.random() * 0xff_ff_fd) + 1\n}\n\n/** Allocate a fresh 24-bit placement id. */\nexport function allocatePlacementId(): number {\n return Math.floor(Math.random() * 0xff_ff_fd) + 1\n}\n\nexport class Kitty {\n #support: ImageSupport\n #wrap: (seq: string) => string = (s) => s\n\n constructor(support: ImageSupport) {\n this.#support = support\n this.#wrap = support.wrap ?? ((s) => s)\n }\n\n get supported(): boolean {\n return this.#support.ok\n }\n\n get inline(): boolean {\n return this.#support.ok && this.#support.inline === true\n }\n\n /** Create a KGP request escape sequence */\n request(\n attrs: Record<string, string | number>,\n data?: string | Uint8Array,\n opts: { base64?: boolean } = {}\n ): string {\n const params = Object.entries(attrs)\n .map(([k, v]) => `${k}=${v}`)\n .join(\",\")\n let encoded: string | undefined\n if (opts.base64 === false && typeof data === \"string\") encoded = data\n else if (data)\n encoded = toBase64(typeof data === \"string\" ? new TextEncoder().encode(data) : data)\n const payload = encoded ? `;${encoded}` : \"\"\n return this.#wrap(`\\x1b_G${params}${payload}\\x1b\\\\`)\n }\n\n /** Create a TerminalQuery that requests a KGP operation and parses the response. */\n query(\n attrs: Record<string, string | number>,\n data?: string | Uint8Array,\n opts: { base64?: boolean } = {}\n ): TerminalQuery {\n return {\n match: (ev) => {\n if (ev.kind !== \"apc\") return\n const kr = this.parse(ev.sequence)\n if (!kr) return\n return { ...ev, ...kr }\n },\n request: this.request(attrs, data, opts),\n }\n }\n\n /** Probe the terminal for KGP support. Should return an error response. */\n probe(): string {\n return this.request({ i: 4_294_967_290, s: 10, t: \"s\", v: 2 }, \"<error>\")\n }\n\n /** Parse a KGP response escape sequence into a structured object. */\n parse(res: string): KittyResponse | undefined {\n if (!res.startsWith(\"\\x1b_G\") || !res.endsWith(\"\\x1b\\\\\")) return undefined\n const body = res.slice(3, -2)\n const m = body.match(/^([^;]+);(.*)?$/)\n if (!m) return undefined\n const [_, params, data] = m as [string, string, string | undefined]\n const attrs: Record<string, string | number> = {}\n for (const pair of params.split(\",\")) {\n const [k, v] = pair.split(\"=\", 2)\n if (k && v) attrs[k] = /^\\d+$/.test(v) ? parseInt(v, 10) : v\n }\n if (data === \"OK\") return { attrs, ok: true }\n const error = data?.match(/^([A-Z]+):\\s*(.*)$/)\n return {\n attrs,\n error: error\n ? { code: error[1], message: error[2] }\n : { code: \"UNKNOWN\", message: data ?? \"\" },\n ok: false,\n }\n }\n\n placement(imageId: number, dims: PlacementDims): KittyPlacement | undefined {\n if (!this.#support.ok) return\n if (this.#support.inline)\n return {\n data: unicodePlaceholder(imageId, dims),\n imageId,\n inline: true,\n seq: this.request({ U: 1, a: \"p\", c: dims.cols, i: imageId, q: 2, r: dims.rows }),\n }\n const blank = \" \".repeat(dims.cols)\n const placementId = allocatePlacementId()\n // NOTE: never sort this, since we need a deterministic order for bumping placements\n // oxlint-disable-next-line sort-keys\n const seq = this.request({\n a: \"p\",\n i: imageId,\n p: placementId,\n C: 1,\n c: dims.cols,\n q: 2,\n r: dims.rows,\n })\n return {\n data: Array.from<string>({ length: dims.rows }).fill(blank),\n imageId,\n placementId,\n seq,\n }\n }\n\n /** Delete an image and all its placements, or ALL images if `imageId` is omitted. */\n deleteImage(imageId?: number): string {\n return imageId === undefined\n ? this.request({ a: \"d\", d: \"A\", q: 2 })\n : this.request({ a: \"d\", d: \"I\", i: imageId, q: 2 })\n }\n\n /** Delete a placement (keeps image data so it can be re-placed cheaply). */\n deletePlacement(imageId: number, placementId: number): string {\n return this.request({ a: \"d\", d: \"i\", i: imageId, p: placementId, q: 2 })\n }\n\n /**\n * Ensure an image has been transmitted to the terminal at least once.\n * On the first call per `src`, returns the full `a=t,t=f` escape to be\n * prepended to the caller's first row — the APC payload has zero display\n * width, so layout sees through it. Subsequent calls return `transmit:\n * \"\"` since the terminal already has the bytes under `imageId`.\n *\n * The caller is expected to combine this with `placement(...)` on every\n * render to actually paint the image at the right cell rectangle.\n */\n async transmitOnce(info: ImageInfo): Promise<{ imageId: number; transmit?: string } | undefined> {\n if (!this.#support.ok) return undefined\n const { fileHash } = await import(\"@zaly/shared/detect\")\n const key = fileHash(info)\n let entry = transmitCache.get(key)\n if (entry === undefined) {\n const { imageConvert } = await import(\"@zaly/shared/image\")\n const png = await imageConvert(info, \"png\")\n if (!png) return undefined\n const id = allocateImageId()\n // Under SSH the terminal can't read files on the local side, so\n // fall back to bytes-in-band (`t=d`). Locally we pass a path and\n // the transmit payload stays under 1KB.\n entry = {\n imageId: id,\n sent: false,\n seq:\n this.#support.remote || !png.path\n ? this.transmitBytes(id, png.data)\n : this.transmitFile(id, png.path),\n }\n transmitCache.set(key, entry)\n }\n if (entry.sent) {\n entry.seq = \"\" // Clear the transmit memory\n return { imageId: entry.imageId }\n }\n entry.sent = true\n return { imageId: entry.imageId, transmit: entry.seq }\n }\n\n /**\n * Transmit an image to the terminal by file path (`t=f`). Near-zero cost\n * on the wire — the terminal opens and reads the file itself. `path`\n * must be absolute and must point to a regular file; symlinks are\n * followed by the terminal.\n */\n transmitFile(id: number, path: string): string {\n return this.request({ a: \"t\", f: 100, i: id, q: 2, t: \"f\" }, path)\n }\n\n /**\n * Remote/bytes transmission fallback (`t=d`) for when the terminal can't\n * read local files — typical of SSH sessions. Base64-encodes and chunks\n * the PNG payload at 4KB boundaries per the protocol.\n */\n transmitBytes(id: number, png: Uint8Array): string {\n const base64 = toBase64(png)\n const params = { a: \"t\", f: 100, i: id, q: 2, t: \"d\" }\n if (base64.length <= CHUNK_SIZE) return this.request(params, base64, { base64: false })\n\n const out: string[] = []\n let offset = 0\n let first = true\n while (offset < base64.length) {\n const chunk = base64.slice(offset, offset + CHUNK_SIZE)\n offset += CHUNK_SIZE\n const more = offset < base64.length ? 1 : 0\n out.push(this.request(first ? { ...params, m: more } : { m: more }, chunk, { base64: false }))\n first = false\n }\n return out.join(\"\")\n }\n}\n\n/** Drop the per-src transmit cache. Mostly for tests. */\nexport function resetTransmitCache(): void {\n transmitCache.clear()\n}\n\nexport function resetKittyGraphics(): void {\n resetTransmitCache()\n prom = undefined\n kitty = undefined\n}\n\nfunction intToRgb(color24bit: number): { r: number; g: number; b: number } {\n const r = (color24bit >> 16) & 0xff\n const g = (color24bit >> 8) & 0xff\n const b = color24bit & 0xff\n return { b, g, r }\n}\n\nfunction unicodePlaceholder(id: number, dims: PlacementDims): string[] {\n const rgb = intToRgb(id)\n const rows = Math.min(DIACRITICS.length, dims.rows)\n const cols = Math.min(DIACRITICS.length, dims.cols)\n const fg = `\\x1b[38;2;${rgb.r};${rgb.g};${rgb.b}m`\n const img: string[] = []\n for (let r = 0; r < rows; r++) {\n const line: string[] = []\n for (let c = 0; c < cols; c++) {\n line.push(fg)\n line.push(PLACEHOLDER)\n line.push(DIACRITICS[r])\n line.push(DIACRITICS[c])\n }\n line.push(\"\\x1b[39m\")\n img.push(line.join(\"\"))\n }\n return img\n}\n\nfunction toBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== \"undefined\") return Buffer.from(bytes).toString(\"base64\")\n let binary = \"\"\n for (const b of bytes) binary += String.fromCharCode(b)\n return btoa(binary)\n}\n\nexport function bumpPlacements(\n rows: string[]\n): undefined | { delete: () => string; rows: string[] } {\n // We only need to bump placements when:\n // - kitty graphics are loaded (when not loaded, there can't be any placements yet)\n // - we're not using inline placements (when using inline, the placement is part of the row and doesn't need to be bumped)\n if (!kitty || kitty.inline) return\n\n const placements: { i: number; p: number }[] = []\n const ret = rows.map((row) =>\n row.replace(/\\x1b_Ga=p,i=(\\d+),p=(\\d+)/g, (_, i) => {\n const imageId = parseInt(i, 10)\n const placementId = allocatePlacementId()\n placements.push({ i: imageId, p: placementId })\n return `\\x1b_Ga=p,i=${imageId},p=${placementId}`\n })\n )\n if (!placements.length) return\n const k = kitty\n return {\n delete: () => placements.map((p) => k.deletePlacement(p.i, p.p)).join(\"\"),\n rows: ret,\n }\n}\n\nasync function detect(tq: TerminalQueries): Promise<ImageSupport> {\n const support: Omit<ImageSupport, \"ok\" | \"error\"> = {\n remote: isSSH,\n tmux: !!process.env.TMUX,\n // Escape sequences must be wrapped in a special way for tmux to pass them\n // through to the underlying terminal.\n wrap: process.env.TMUX ? wrapTmux : undefined,\n }\n if (support.tmux) {\n try {\n const { spawnCmd } = await import(\"@zaly/shared/process\")\n // TMUX needs to have allow-passthrough set to all images to work properly\n await spawnCmd(\"tmux\", \"set\", \"-p\", \"allow-passthrough\", \"on\")\n support.wrap = wrapTmux\n } catch (error) {\n return {\n ...support,\n error: `Failed to set allow-passthrough in tmux: ${error instanceof Error ? error.message : String(error)}`,\n ok: false,\n }\n }\n }\n\n const v = await tq.xtVersion({ wrap: support.wrap })\n if (!v) return { error: \"Failed to query terminal name & version\", ok: false, ...support }\n\n support.terminal = { name: v.name, version: v.version }\n\n const kgp = known[v.name.toLowerCase()]\n if (kgp === false)\n return { error: `Terminal ${v.name} does not support KGP`, ok: false, ...support }\n\n if (kgp === undefined) {\n // Probe KGP support\n // Create a tmp Kitty instance to probe the terminal for KGP support.\n const k = new Kitty({ ...support, error: \"\", ok: false })\n const res = await tq.query({\n match: (ev) => {\n if (ev.kind === \"apc\" && ev.payload.startsWith(\"G\")) return { kgp: true, ...ev }\n if (ev.kind === \"csi\" && ev.final === \"c\" && ev.params.startsWith(\"?\"))\n return { kgp: false, ...ev }\n return\n },\n request: `${k.probe()}\\x1b[c`,\n timeout: 200,\n })\n if (res?.kgp !== true)\n return { error: \"Failed to query kitty graphics protocol\", ok: false, ...support }\n }\n\n return {\n ...support,\n inline: kgp?.inline,\n ok: true,\n terminal: { name: v.name, version: v.version },\n }\n}\n\nexport function loadKittyGraphics(tq: TerminalQueries): MaybePromise<Kitty> {\n if (kitty) return kitty\n prom ??= (async () => (kitty = new Kitty(await detect(tq))))()\n return prom\n}\n"],"mappings":";;AAgFA,MAAa,aAAa;CAAE;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CA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"}
|
|
1
|
+
{"version":3,"file":"kitty-BH_eK6lz.mjs","names":[],"sources":["../src/image/kitty.ts"],"sourcesContent":["/**\n * Kitty Graphics Protocol — local-file transmission + native placements.\n *\n * Flow:\n * 1. Transmit once per src via `transmitFile(id, path)` (t=f). The\n * terminal loads the image bytes from the file path; nothing of the\n * image is transmitted over the wire beyond the path itself.\n * 2. On every render, emit `placement(imgId, placeId, { cols, rows })`\n * at the target cursor position. Re-sending a placement with the\n * same (image id, placement id) moves/resizes the existing placement\n * without flicker — ideal for re-renders.\n *\n * Reference: https://sw.kovidgoyal.net/kitty/graphics-protocol/\n */\n\nimport type { MaybePromise } from \"@zaly/shared\"\nimport type { ImageInfo } from \"@zaly/shared/image\"\nimport type { TerminalQueries, TerminalQuery } from \"../input/queries.ts\"\n\nimport { isSSH } from \"@zaly/shared/env\"\n\nexport type KittyPlacement = {\n imageId: number\n /** Placement ID. Omitted when this is an inline placement (U=1) */\n placementId?: number\n /** inline: placement using unicode placeholder (U=1) */\n inline?: boolean\n /** The KGP escape sequence to place the image */\n seq: string\n /** Rows to render (excluding the placement escape sequence) */\n data: string[]\n}\n\nexport type ImageSupport = {\n terminal?: { name: string; version?: string }\n remote?: boolean\n wrap?: (seq: string) => string\n tmux?: boolean\n} & (\n | {\n ok: false\n error: string\n terminal?: { name: string; version?: string }\n }\n | {\n ok: true\n error?: never\n terminal: { name: string; version?: string }\n inline?: boolean\n }\n)\n\nexport type KittyResponse =\n | {\n attrs: Record<string, string | number>\n ok: true\n }\n | {\n attrs: Record<string, string | number>\n ok: false\n error: { code: string; message: string }\n }\n\nexport type PlacementDims = {\n /** Display width in terminal cells. */\n cols: number\n /** Display height in terminal cells. */\n rows: number\n}\n\n// Per-src transmit cache. The first caller gets the full transmit sequence;\n// subsequent callers get undefined since the terminal already has the bytes.\ntype CacheEntry = {\n imageId: number\n seq: string\n sent: boolean\n}\n\n// oxfmt-ignore\n// oxlint-disable-next-line unicorn/numeric-separators-style\nexport const DIACRITICS = [ 0x0305, 0x030d, 0x030e, 0x0310, 0x0312, 0x033d, 0x033e, 0x033f, 0x0346, 0x034a, 0x034b, 0x034c, 0x0350, 0x0351, 0x0352, 0x0357, 0x035b, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0592, 0x0593, 0x0594, 0x0595, 0x0597, 0x0598, 0x0599, 0x059c, 0x059d, 0x059e, 0x059f, 0x05a0, 0x05a1, 0x05a8, 0x05a9, 0x05ab, 0x05ac, 0x05af, 0x05c4, 0x0610, 0x0611, 0x0612, 0x0613, 0x0614, 0x0615, 0x0616, 0x0617, 0x0657, 0x0658, 0x0659, 0x065a, 0x065b, 0x065d, 0x065e, 0x06d6, 0x06d7, 0x06d8, 0x06d9, 0x06da, 0x06db, 0x06dc, 0x06df, 0x06e0, 0x06e1, 0x06e2, 0x06e4, 0x06e7, 0x06e8, 0x06eb, 0x06ec, 0x0730, 0x0732, 0x0733, 0x0735, 0x0736, 0x073a, 0x073d, 0x073f, 0x0740, 0x0741, 0x0743, 0x0745, 0x0747, 0x0749, 0x074a, 0x07eb, 0x07ec, 0x07ed, 0x07ee, 0x07ef, 0x07f0, 0x07f1, 0x07f3, 0x0816, 0x0817, 0x0818, 0x0819, 0x081b, 0x081c, 0x081d, 0x081e, 0x081f, 0x0820, 0x0821, 0x0822, 0x0823, 0x0825, 0x0826, 0x0827, 0x0829, 0x082a, 0x082b, 0x082c, 0x082d, 0x0951, 0x0953, 0x0954, 0x0f82, 0x0f83, 0x0f86, 0x0f87, 0x135d, 0x135e, 0x135f, 0x17dd, 0x193a, 0x1a17, 0x1a75, 0x1a76, 0x1a77, 0x1a78, 0x1a79, 0x1a7a, 0x1a7b, 0x1a7c, 0x1b6b, 0x1b6d, 0x1b6e, 0x1b6f, 0x1b70, 0x1b71, 0x1b72, 0x1b73, 0x1cd0, 0x1cd1, 0x1cd2, 0x1cda, 0x1cdb, 0x1ce0, 0x1dc0, 0x1dc1, 0x1dc3, 0x1dc4, 0x1dc5, 0x1dc6, 0x1dc7, 0x1dc8, 0x1dc9, 0x1dcb, 0x1dcc, 0x1dd1, 0x1dd2, 0x1dd3, 0x1dd4, 0x1dd5, 0x1dd6, 0x1dd7, 0x1dd8, 0x1dd9, 0x1dda, 0x1ddb, 0x1ddc, 0x1ddd, 0x1dde, 0x1ddf, 0x1de0, 0x1de1, 0x1de2, 0x1de3, 0x1de4, 0x1de5, 0x1de6, 0x1dfe, 0x20d0, 0x20d1, 0x20d4, 0x20d5, 0x20d6, 0x20d7, 0x20db, 0x20dc, 0x20e1, 0x20e7, 0x20e9, 0x20f0, 0x2cef, 0x2cf0, 0x2cf1, 0x2de0, 0x2de1, 0x2de2, 0x2de3, 0x2de4, 0x2de5, 0x2de6, 0x2de7, 0x2de8, 0x2de9, 0x2dea, 0x2deb, 0x2dec, 0x2ded, 0x2dee, 0x2def, 0x2df0, 0x2df1, 0x2df2, 0x2df3, 0x2df4, 0x2df5, 0x2df6, 0x2df7, 0x2df8, 0x2df9, 0x2dfa, 0x2dfb, 0x2dfc, 0x2dfd, 0x2dfe, 0x2dff, 0xa66f, 0xa67c, 0xa67d, 0xa6f0, 0xa6f1, 0xa8e0, 0xa8e1, 0xa8e2, 0xa8e3, 0xa8e4, 0xa8e5, 0xa8e6, 0xa8e7, 0xa8e8, 0xa8e9, 0xa8ea, 0xa8eb, 0xa8ec, 0xa8ed, 0xa8ee, 0xa8ef, 0xa8f0, 0xa8f1, 0xaab0, 0xaab2, 0xaab3, 0xaab7, 0xaab8, 0xaabe, 0xaabf, 0xaac1, 0xfe20, 0xfe21, 0xfe22, 0xfe23, 0xfe24, 0xfe25, 0xfe26, 0x10a0f, 0x10a38, 0x1d185, 0x1d186, 0x1d187, 0x1d188, 0x1d189, 0x1d1aa, 0x1d1ab, 0x1d1ac, 0x1d1ad, 0x1d242, 0x1d243, 0x1d244 ].map((c) => String.fromCodePoint(c))\nexport const PLACEHOLDER = String.fromCodePoint(0x10_ee_ee)\nconst CHUNK_SIZE = 4096\nconst transmitCache = new Map<string, CacheEntry>()\n\nconst known: Record<string, { inline?: boolean } | false | undefined> = {\n ghostty: { inline: true },\n kitty: { inline: true },\n rio: { inline: false },\n wezterm: { inline: false },\n}\n\nlet prom: Promise<Kitty> | undefined = undefined\nlet kitty: Kitty | undefined = undefined\nconst wrapTmux = (seq: string): string => `\\x1bPtmux;${seq.replaceAll(\"\\x1b\", \"\\x1b\\x1b\")}\\x1b\\\\`\n\n/** Allocate a fresh 24-bit image id (1..0xFFFFFFFE). */\nexport function allocateImageId(): number {\n return Math.floor(Math.random() * 0xff_ff_fd) + 1\n}\n\n/** Allocate a fresh 24-bit placement id. */\nexport function allocatePlacementId(): number {\n return Math.floor(Math.random() * 0xff_ff_fd) + 1\n}\n\nexport class Kitty {\n #support: ImageSupport\n #wrap: (seq: string) => string = (s) => s\n\n constructor(support: ImageSupport) {\n this.#support = support\n this.#wrap = support.wrap ?? ((s) => s)\n }\n\n get supported(): boolean {\n return this.#support.ok\n }\n\n get inline(): boolean {\n return this.#support.ok && this.#support.inline === true\n }\n\n /** Create a KGP request escape sequence */\n request(\n attrs: Record<string, string | number>,\n data?: string | Uint8Array,\n opts: { base64?: boolean } = {}\n ): string {\n const params = Object.entries(attrs)\n .map(([k, v]) => `${k}=${v}`)\n .join(\",\")\n let encoded: string | undefined\n if (opts.base64 === false && typeof data === \"string\") encoded = data\n else if (data)\n encoded = toBase64(typeof data === \"string\" ? new TextEncoder().encode(data) : data)\n const payload = encoded ? `;${encoded}` : \"\"\n return this.#wrap(`\\x1b_G${params}${payload}\\x1b\\\\`)\n }\n\n /** Create a TerminalQuery that requests a KGP operation and parses the response. */\n query(\n attrs: Record<string, string | number>,\n data?: string | Uint8Array,\n opts: { base64?: boolean } = {}\n ): TerminalQuery {\n return {\n match: (ev) => {\n if (ev.kind !== \"apc\") return\n const kr = this.parse(ev.sequence)\n if (!kr) return\n return { ...ev, ...kr }\n },\n request: this.request(attrs, data, opts),\n }\n }\n\n /** Probe the terminal for KGP support. Should return an error response. */\n probe(): string {\n return this.request({ i: 4_294_967_290, s: 10, t: \"s\", v: 2 }, \"<error>\")\n }\n\n /** Parse a KGP response escape sequence into a structured object. */\n parse(res: string): KittyResponse | undefined {\n if (!res.startsWith(\"\\x1b_G\") || !res.endsWith(\"\\x1b\\\\\")) return undefined\n const body = res.slice(3, -2)\n const m = body.match(/^([^;]+);(.*)?$/)\n if (!m) return undefined\n const [_, params, data] = m as [string, string, string | undefined]\n const attrs: Record<string, string | number> = {}\n for (const pair of params.split(\",\")) {\n const [k, v] = pair.split(\"=\", 2)\n if (k && v) attrs[k] = /^\\d+$/.test(v) ? parseInt(v, 10) : v\n }\n if (data === \"OK\") return { attrs, ok: true }\n const error = data?.match(/^([A-Z]+):\\s*(.*)$/)\n return {\n attrs,\n error: error\n ? { code: error[1], message: error[2] }\n : { code: \"UNKNOWN\", message: data ?? \"\" },\n ok: false,\n }\n }\n\n placement(imageId: number, dims: PlacementDims): KittyPlacement | undefined {\n if (!this.#support.ok) return\n if (this.#support.inline)\n return {\n data: unicodePlaceholder(imageId, dims),\n imageId,\n inline: true,\n seq: this.request({ U: 1, a: \"p\", c: dims.cols, i: imageId, q: 2, r: dims.rows }),\n }\n const blank = \" \".repeat(dims.cols)\n const placementId = allocatePlacementId()\n // NOTE: never sort this, since we need a deterministic order for bumping placements\n // oxlint-disable-next-line sort-keys\n const seq = this.request({\n a: \"p\",\n i: imageId,\n p: placementId,\n C: 1,\n c: dims.cols,\n q: 2,\n r: dims.rows,\n })\n return {\n data: Array.from<string>({ length: dims.rows }).fill(blank),\n imageId,\n placementId,\n seq,\n }\n }\n\n /** Delete an image and all its placements, or ALL images if `imageId` is omitted. */\n deleteImage(imageId?: number): string {\n return imageId === undefined\n ? this.request({ a: \"d\", d: \"A\", q: 2 })\n : this.request({ a: \"d\", d: \"I\", i: imageId, q: 2 })\n }\n\n /** Delete a placement (keeps image data so it can be re-placed cheaply). */\n deletePlacement(imageId: number, placementId: number): string {\n return this.request({ a: \"d\", d: \"i\", i: imageId, p: placementId, q: 2 })\n }\n\n /**\n * Ensure an image has been transmitted to the terminal at least once.\n * On the first call per `src`, returns the full `a=t,t=f` escape to be\n * prepended to the caller's first row — the APC payload has zero display\n * width, so layout sees through it. Subsequent calls return `transmit:\n * \"\"` since the terminal already has the bytes under `imageId`.\n *\n * The caller is expected to combine this with `placement(...)` on every\n * render to actually paint the image at the right cell rectangle.\n */\n async transmitOnce(info: ImageInfo): Promise<{ imageId: number; transmit?: string } | undefined> {\n if (!this.#support.ok) return undefined\n const { fileHash } = await import(\"@zaly/shared/detect\")\n const key = fileHash(info)\n let entry = transmitCache.get(key)\n if (entry === undefined) {\n const { imageConvert } = await import(\"@zaly/shared/image\")\n const png = await imageConvert(info, \"png\")\n if (!png) return undefined\n const id = allocateImageId()\n // Under SSH the terminal can't read files on the local side, so\n // fall back to bytes-in-band (`t=d`). Locally we pass a path and\n // the transmit payload stays under 1KB.\n entry = {\n imageId: id,\n sent: false,\n seq:\n this.#support.remote || !png.path\n ? this.transmitBytes(id, png.data)\n : this.transmitFile(id, png.path),\n }\n transmitCache.set(key, entry)\n }\n if (entry.sent) {\n entry.seq = \"\" // Clear the transmit memory\n return { imageId: entry.imageId }\n }\n entry.sent = true\n return { imageId: entry.imageId, transmit: entry.seq }\n }\n\n /**\n * Transmit an image to the terminal by file path (`t=f`). Near-zero cost\n * on the wire — the terminal opens and reads the file itself. `path`\n * must be absolute and must point to a regular file; symlinks are\n * followed by the terminal.\n */\n transmitFile(id: number, path: string): string {\n return this.request({ a: \"t\", f: 100, i: id, q: 2, t: \"f\" }, path)\n }\n\n /**\n * Remote/bytes transmission fallback (`t=d`) for when the terminal can't\n * read local files — typical of SSH sessions. Base64-encodes and chunks\n * the PNG payload at 4KB boundaries per the protocol.\n */\n transmitBytes(id: number, png: Uint8Array): string {\n const base64 = toBase64(png)\n const params = { a: \"t\", f: 100, i: id, q: 2, t: \"d\" }\n if (base64.length <= CHUNK_SIZE) return this.request(params, base64, { base64: false })\n\n const out: string[] = []\n let offset = 0\n let first = true\n while (offset < base64.length) {\n const chunk = base64.slice(offset, offset + CHUNK_SIZE)\n offset += CHUNK_SIZE\n const more = offset < base64.length ? 1 : 0\n out.push(this.request(first ? { ...params, m: more } : { m: more }, chunk, { base64: false }))\n first = false\n }\n return out.join(\"\")\n }\n}\n\n/** Drop the per-src transmit cache. Mostly for tests. */\nexport function resetTransmitCache(): void {\n transmitCache.clear()\n}\n\nexport function resetKittyGraphics(): void {\n resetTransmitCache()\n prom = undefined\n kitty = undefined\n}\n\nfunction intToRgb(color24bit: number): { r: number; g: number; b: number } {\n const r = (color24bit >> 16) & 0xff\n const g = (color24bit >> 8) & 0xff\n const b = color24bit & 0xff\n return { b, g, r }\n}\n\nfunction unicodePlaceholder(id: number, dims: PlacementDims): string[] {\n const rgb = intToRgb(id)\n const rows = Math.min(DIACRITICS.length, dims.rows)\n const cols = Math.min(DIACRITICS.length, dims.cols)\n const fg = `\\x1b[38;2;${rgb.r};${rgb.g};${rgb.b}m`\n const img: string[] = []\n for (let r = 0; r < rows; r++) {\n const line: string[] = []\n for (let c = 0; c < cols; c++) {\n line.push(fg)\n line.push(PLACEHOLDER)\n line.push(DIACRITICS[r])\n line.push(DIACRITICS[c])\n }\n line.push(\"\\x1b[39m\")\n img.push(line.join(\"\"))\n }\n return img\n}\n\nfunction toBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== \"undefined\") return Buffer.from(bytes).toString(\"base64\")\n let binary = \"\"\n for (const b of bytes) binary += String.fromCharCode(b)\n return btoa(binary)\n}\n\nexport function bumpPlacements(\n rows: string[]\n): undefined | { delete: () => string; rows: string[] } {\n // We only need to bump placements when:\n // - kitty graphics are loaded (when not loaded, there can't be any placements yet)\n // - we're not using inline placements (when using inline, the placement is part of the row and doesn't need to be bumped)\n if (!kitty || kitty.inline) return\n\n const placements: { i: number; p: number }[] = []\n const ret = rows.map((row) =>\n row.replace(/\\x1b_Ga=p,i=(\\d+),p=(\\d+)/g, (_, i) => {\n const imageId = parseInt(i, 10)\n const placementId = allocatePlacementId()\n placements.push({ i: imageId, p: placementId })\n return `\\x1b_Ga=p,i=${imageId},p=${placementId}`\n })\n )\n if (!placements.length) return\n const k = kitty\n return {\n delete: () => placements.map((p) => k.deletePlacement(p.i, p.p)).join(\"\"),\n rows: ret,\n }\n}\n\nasync function detect(tq: TerminalQueries): Promise<ImageSupport> {\n const support: Omit<ImageSupport, \"ok\" | \"error\"> = {\n remote: isSSH,\n tmux: !!process.env.TMUX,\n // Escape sequences must be wrapped in a special way for tmux to pass them\n // through to the underlying terminal.\n wrap: process.env.TMUX ? wrapTmux : undefined,\n }\n if (support.tmux) {\n try {\n const { spawnCmd } = await import(\"@zaly/shared/process\")\n // TMUX needs to have allow-passthrough set to all images to work properly\n await spawnCmd(\"tmux\", \"set\", \"-p\", \"allow-passthrough\", \"on\")\n support.wrap = wrapTmux\n } catch (error) {\n return {\n ...support,\n error: `Failed to set allow-passthrough in tmux: ${error instanceof Error ? error.message : String(error)}`,\n ok: false,\n }\n }\n }\n\n const v = await tq.xtVersion({ wrap: support.wrap })\n if (!v) return { error: \"Failed to query terminal name & version\", ok: false, ...support }\n\n support.terminal = { name: v.name, version: v.version }\n\n const kgp = known[v.name.toLowerCase()]\n if (kgp === false)\n return { error: `Terminal ${v.name} does not support KGP`, ok: false, ...support }\n\n if (kgp === undefined) {\n // Probe KGP support\n // Create a tmp Kitty instance to probe the terminal for KGP support.\n const k = new Kitty({ ...support, error: \"\", ok: false })\n const res = await tq.query({\n match: (ev) => {\n if (ev.kind === \"apc\" && ev.payload.startsWith(\"G\")) return { kgp: true, ...ev }\n if (ev.kind === \"csi\" && ev.final === \"c\" && ev.params.startsWith(\"?\"))\n return { kgp: false, ...ev }\n return\n },\n request: `${k.probe()}\\x1b[c`,\n timeout: 200,\n })\n if (res?.kgp !== true)\n return { error: \"Failed to query kitty graphics protocol\", ok: false, ...support }\n }\n\n return {\n ...support,\n inline: kgp?.inline,\n ok: true,\n terminal: { name: v.name, version: v.version },\n }\n}\n\nexport function loadKittyGraphics(tq: TerminalQueries): MaybePromise<Kitty> {\n if (kitty) return kitty\n prom ??= (async () => (kitty = new Kitty(await detect(tq))))()\n return prom\n}\n"],"mappings":";;AAgFA,MAAa,aAAa;CAAE;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CAAQ;CA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"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { n as box } from "./box-
|
|
2
|
-
import { n as text } from "./text-
|
|
3
|
-
import { n as markdown } from "./markdown-
|
|
4
|
-
import { t as widget } from "./widget-
|
|
1
|
+
import { n as box } from "./box-DToDoXlU.mjs";
|
|
2
|
+
import { n as text } from "./text-BArwVVkg.mjs";
|
|
3
|
+
import { n as markdown } from "./markdown-CgRZBhIX.mjs";
|
|
4
|
+
import { t as widget } from "./widget-sFveyrZE.mjs";
|
|
5
5
|
import { stringWidth } from "@zaly/shared/ansi";
|
|
6
6
|
import { hasColors } from "@zaly/shared/env";
|
|
7
|
-
|
|
7
|
+
// src/widgets/log.ts
|
|
8
8
|
/** Per-level default prefix style + icon + color. Matches rekal's
|
|
9
9
|
* `defaultStyles` table, adapted to zaly's theme slots. */
|
|
10
10
|
const defaultLogStyles = {
|
|
@@ -124,7 +124,6 @@ const log = widget((state, ...children) => {
|
|
|
124
124
|
gap: 1
|
|
125
125
|
}, ...children));
|
|
126
126
|
});
|
|
127
|
-
//#endregion
|
|
128
127
|
export { log as t };
|
|
129
128
|
|
|
130
|
-
//# sourceMappingURL=log-
|
|
129
|
+
//# sourceMappingURL=log-96b1_J6G.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-
|
|
1
|
+
{"version":3,"file":"log-96b1_J6G.mjs","names":[],"sources":["../src/widgets/log.ts"],"sourcesContent":["import type { LogLevel } from \"@zaly/shared/logger\"\nimport type { RenderCtx } from \"../core/ctx.ts\"\nimport type { Node } from \"../core/node.ts\"\nimport type { State } from \"../core/state.ts\"\nimport type { Color } from \"../style/types.ts\"\nimport type { TextContent } from \"./text.ts\"\n\nimport { stringWidth } from \"@zaly/shared/ansi\"\nimport { hasColors } from \"@zaly/shared/env\"\nimport { box } from \"./box.ts\"\nimport { markdown } from \"./markdown.ts\"\nimport { text } from \"./text.ts\"\nimport { widget } from \"./widget.ts\"\n\nexport type LogStyle = \"badge\" | \"icon\" | \"prompt\" | \"title\" | \"text\" | \"notif\"\n\nexport interface LogState {\n level: LogLevel\n content: TextContent\n title?: string\n /** Rendering of the per-level prefix chunk. Defaults by level. */\n style?: LogStyle\n /** Single-glyph icon for `icon` / `prompt` styles. */\n icon?: string\n /** Theme slot or color name used to tint the prefix. */\n color?: Color<false>\n /** Extra plain text prepended to the auto prefix (unstyled). */\n prefix?: string\n /** Theme slot or color name for the body text. Defaults by level, except */\n textColor?: Color<false>\n markdown?: boolean\n}\n\ninterface LevelDefaults {\n style: LogStyle\n icon?: string\n color?: Color<false>\n textColor?: Color<false>\n}\n\n/** Per-level default prefix style + icon + color. Matches rekal's\n * `defaultStyles` table, adapted to zaly's theme slots. */\nconst defaultLogStyles: Record<LogLevel, LevelDefaults> = {\n cancel: { color: \"warn\", icon: \"✖ \", style: \"icon\" },\n debug: { color: \"info\", icon: \"⚙ \", style: \"prompt\" },\n error: { color: \"error\", icon: \"✖ \", style: \"badge\", textColor: \"error\" },\n fatal: { color: \"error\", icon: \"☢ \", style: \"badge\" },\n info: { color: \"info\", icon: \"ℹ \", style: \"icon\" },\n log: { color: \"muted\", icon: \"●\", style: \"icon\" },\n success: { color: \"success\", icon: \"✔ \", style: \"icon\" },\n trace: { color: \"muted\", icon: \"⠿\", style: \"icon\", textColor: \"muted\" },\n warn: { color: \"warn\", icon: \"⚠\", style: \"badge\", textColor: \"warn\" },\n}\n\nconst noColorStyles: Record<LogStyle, LogStyle> = {\n badge: \"title\",\n icon: \"text\",\n notif: \"text\",\n prompt: \"text\",\n text: \"text\",\n title: \"text\",\n}\n\nfunction renderPrefix(s: LogState, ctx: RenderCtx): string {\n const style = ctx.style\n\n const base = defaultLogStyles[s.level]\n let ls: LogStyle = s.style ?? base.style\n if (!hasColors) ls = noColorStyles[ls]\n\n let icon = s.icon ?? base.icon ?? \"\"\n icon = icon === \"\" ? \"\" : `${icon}${\" \".repeat(2 - stringWidth(icon))}`\n const color: Color<false> = s.color ?? base.color ?? \"inherit\"\n\n // text doesn't get a prefix\n let styledPrefix = \"\"\n if (ls === \"badge\") {\n styledPrefix = style.bg(color).bold(` ${s.level} `)\n } else if (ls === \"icon\") {\n styledPrefix = style.fg(color)(icon)\n } else if (ls === \"prompt\") {\n styledPrefix = style.fg(color).bold(`${icon} ${s.level}`)\n } else if (ls === \"title\") {\n styledPrefix = style.fg(color).bold(`${s.level}:`)\n } else if (ls === \"notif\") {\n styledPrefix = style.fg(color).bold(`${icon} ${s.title ?? s.level}`)\n }\n\n if (s.prefix) styledPrefix = s.prefix + styledPrefix\n if (s.title && ls !== \"notif\") styledPrefix += style.bold(` ${s.title}`)\n return styledPrefix\n}\n\n/**\n * A single log entry — level-styled prefix (icon / badge / prompt / title /\n * plain text) followed by the body content. The body can be any Node, so\n * callers can stack markdown, code, images, etc. inside a log line.\n *\n * ```ts\n * log({ level: \"info\", content: \"hello\" })\n * log({ level: \"error\", content: markdown(\"**boom**\") })\n * ```\n */\nexport const log = widget((state: State<LogState>, ...children: Node[]) => {\n const base = defaultLogStyles[state.level]\n const color: Color = state.color ?? base.color ?? \"inherit\"\n const s = state\n const textColor = state.textColor ?? (s.style === \"notif\" ? \"inherit\" : base.textColor)\n const style = {\n style: textColor\n ? {\n fg: textColor,\n }\n : undefined,\n width: \"fill\",\n } as const\n if (state.content !== \"\") {\n children = [\n (state.markdown ?? true) ? markdown(state.content, style) : text(state.content, style),\n ...children,\n ]\n }\n return box(\n {\n ...(s.style === \"notif\"\n ? {\n border: \"single\",\n borderStyle: { fg: color },\n borderTitle: (ctx) => renderPrefix(state, ctx),\n borderTitleAlign: \"center\",\n padding: [0, 1],\n //style: \"overlay\",\n width: \"fill\",\n }\n : undefined),\n flexDirection: \"row\",\n gap: 1,\n visible: state.visible,\n },\n s.style === \"notif\"\n ? undefined\n : text((ctx) => renderPrefix(state, ctx), { flexShrink: 0, wrap: \"none\" }),\n box({ flexDirection: \"column\", flexGrow: 1, gap: 1 }, ...children)\n )\n})\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { t as Node } from "./node-
|
|
2
|
-
import { n as inspectFormat, r as isMarkdown } from "./inspect-
|
|
3
|
-
import { t as log } from "./log-
|
|
4
|
-
|
|
1
|
+
import { t as Node } from "./node-CXNobGaP.mjs";
|
|
2
|
+
import { n as inspectFormat, r as isMarkdown } from "./inspect-Cli1beu8.mjs";
|
|
3
|
+
import { t as log } from "./log-96b1_J6G.mjs";
|
|
4
|
+
// src/services/logger.ts
|
|
5
5
|
const ERR_LEVELS = /* @__PURE__ */ new Set([
|
|
6
6
|
"error",
|
|
7
7
|
"fatal",
|
|
@@ -65,7 +65,6 @@ var TuiReporter = class {
|
|
|
65
65
|
(this.#opts.write ?? defaultWrite)(`${str}\n`, kind);
|
|
66
66
|
}
|
|
67
67
|
};
|
|
68
|
-
//#endregion
|
|
69
68
|
export { TuiReporter as t };
|
|
70
69
|
|
|
71
|
-
//# sourceMappingURL=logger-
|
|
70
|
+
//# sourceMappingURL=logger-DwfXp8LF.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger-
|
|
1
|
+
{"version":3,"file":"logger-DwfXp8LF.mjs","names":[],"sources":["../src/services/logger.ts"],"sourcesContent":["import type { LogEntry, LogLevel, LogReporter } from \"@zaly/shared/logger\"\nimport type { InspectOpts } from \"../style/inspect.ts\"\nimport type { LogState } from \"../widgets/log.ts\"\n\nimport { Node } from \"../core/node.ts\"\nimport { inspectFormat, isMarkdown } from \"../style/inspect.ts\"\nimport { log } from \"../widgets/log.ts\"\n\n/** Minimal stream surface the logger needs. Stream satisfies this. */\nexport interface LoggerStream {\n append: (node: () => Node) => unknown\n}\n\nexport type LogEntryFactory = (level: LogLevel, msg: unknown[]) => Node\n\nexport type LogStyleOverride = Omit<LogState, \"level\" | \"content\">\n\nexport interface TuiReporterOpts extends InspectOpts {\n /** Render string messages as markdown when they look like it.\n * Default: `true`. */\n markdown?: boolean\n /** Per-level overrides for the default `log()` widget style fields. */\n styles?: Partial<Record<LogLevel, LogStyleOverride>>\n /** Override the node produced per entry. Default uses `log()`. */\n factory?: LogEntryFactory\n wrap?: (node: Node) => Node\n /** Fallback writer for when no stream is attached. Defaults to\n * `process.stdout/stderr`. Injectable for tests. */\n write?: (text: string, kind: \"stdout\" | \"stderr\") => void\n}\n\nconst ERR_LEVELS = new Set<LogLevel>([\"error\", \"fatal\", \"warn\"])\n\nfunction defaultWrite(text: string, kind: \"stdout\" | \"stderr\"): void {\n if (typeof process === \"undefined\") return\n const stream = kind === \"stderr\" ? process.stderr : process.stdout\n stream.write(text)\n}\n\nexport class TuiReporter implements LogReporter {\n #stream?: LoggerStream\n #opts: TuiReporterOpts\n #factory: LogEntryFactory\n\n constructor(opts: TuiReporterOpts = {}) {\n this.#opts = opts\n this.#factory = opts.factory ?? ((level, msg) => this.#defaultFactory(level, msg))\n }\n\n attach(stream: LoggerStream): this {\n this.#stream = stream\n return this\n }\n\n detach(): this {\n this.#stream = undefined\n return this\n }\n\n $log({ level, msg }: LogEntry): void {\n if (this.#stream) {\n this.#stream.append(() => {\n const node = this.#factory(level, msg)\n return this.#opts.wrap?.(node) ?? node\n })\n return\n }\n this.#writeFallback(level, msg)\n }\n\n #defaultFactory(level: LogLevel, msg: unknown[]): Node {\n const nodes = msg.filter((m): m is Node => m instanceof Node)\n msg = msg.filter((m) => !(m instanceof Node))\n\n // Convert Error objects to their message unless stacktrace is requested.\n msg = this.#opts.stacktrace ? msg : msg.map((v) => (v instanceof Error ? v.message : v))\n\n // If all remaining messages are strings, join them into one string for the log content.\n if (msg.length && msg.every((m) => typeof m === \"string\")) msg = [msg.join(\" \")]\n\n // If there's exactly one string message, use it as the log content;\n // otherwise, leave it undefined to be formatted with `inspect()`.\n // Text allow markdown if the message looks like markdown and the option is enabled.\n let text = msg.length === 1 && typeof msg[0] === \"string\" ? msg[0] : undefined\n if (msg.length === 0) text = \"\"\n const markdown = (this.#opts.markdown ?? true) && text !== undefined && isMarkdown(text)\n const overrides = this.#opts.styles?.[level] ?? {}\n return log(\n {\n content: text ?? ((ctx) => inspectFormat(msg, { ...this.#opts, style: ctx.style })),\n level,\n markdown,\n ...overrides,\n },\n ...nodes\n )\n }\n\n /** String path for the no-stream fallback — builds a plain inspected\n * line (no prefix chrome) and writes it to stdout/stderr. Keeps the\n * fallback synchronous and ordered. */\n #writeFallback(level: LogLevel, msg: unknown[]): void {\n const str = inspectFormat(msg, this.#opts)\n const kind: \"stdout\" | \"stderr\" = ERR_LEVELS.has(level) ? \"stderr\" : \"stdout\"\n const write = this.#opts.write ?? defaultWrite\n write(`${str}\\n`, kind)\n }\n}\n"],"mappings":";;;;AA+BA,MAAM,6BAAa,IAAI,IAAc;CAAC;CAAS;CAAS;AAAM,CAAC;AAE/D,SAAS,aAAa,MAAc,MAAiC;CACnE,IAAI,OAAO,YAAY,aAAa;CAEpC,CADe,SAAS,WAAW,QAAQ,SAAS,QAAQ,OAAA,CACrD,MAAM,IAAI;AACnB;AAEA,IAAa,cAAb,MAAgD;CAC9C;CACA;CACA;CAEA,YAAY,OAAwB,CAAC,GAAG;EACtC,KAAK,QAAQ;EACb,KAAK,WAAW,KAAK,aAAa,OAAO,QAAQ,KAAK,gBAAgB,OAAO,GAAG;CAClF;CAEA,OAAO,QAA4B;EACjC,KAAK,UAAU;EACf,OAAO;CACT;CAEA,SAAe;EACb,KAAK,UAAU,KAAA;EACf,OAAO;CACT;CAEA,KAAK,EAAE,OAAO,OAAuB;EACnC,IAAI,KAAK,SAAS;GAChB,KAAK,QAAQ,aAAa;IACxB,MAAM,OAAO,KAAK,SAAS,OAAO,GAAG;IACrC,OAAO,KAAK,MAAM,OAAO,IAAI,KAAK;GACpC,CAAC;GACD;EACF;EACA,KAAK,eAAe,OAAO,GAAG;CAChC;CAEA,gBAAgB,OAAiB,KAAsB;EACrD,MAAM,QAAQ,IAAI,QAAQ,MAAiB,aAAa,IAAI;EAC5D,MAAM,IAAI,QAAQ,MAAM,EAAE,aAAa,KAAK;EAG5C,MAAM,KAAK,MAAM,aAAa,MAAM,IAAI,KAAK,MAAO,aAAa,QAAQ,EAAE,UAAU,CAAE;EAGvF,IAAI,IAAI,UAAU,IAAI,OAAO,MAAM,OAAO,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC;EAK/E,IAAI,OAAO,IAAI,WAAW,KAAK,OAAO,IAAI,OAAO,WAAW,IAAI,KAAK,KAAA;EACrE,IAAI,IAAI,WAAW,GAAG,OAAO;EAC7B,MAAM,YAAY,KAAK,MAAM,YAAY,SAAS,SAAS,KAAA,KAAa,WAAW,IAAI;EACvF,MAAM,YAAY,KAAK,MAAM,SAAS,UAAU,CAAC;EACjD,OAAO,IACL;GACE,SAAS,UAAU,QAAQ,cAAc,KAAK;IAAE,GAAG,KAAK;IAAO,OAAO,IAAI;GAAM,CAAC;GACjF;GACA;GACA,GAAG;EACL,GACA,GAAG,KACL;CACF;;;;CAKA,eAAe,OAAiB,KAAsB;EACpD,MAAM,MAAM,cAAc,KAAK,KAAK,KAAK;EACzC,MAAM,OAA4B,WAAW,IAAI,KAAK,IAAI,WAAW;EAErE,CADc,KAAK,MAAM,SAAS,aAAA,CAC5B,GAAG,IAAI,KAAK,IAAI;CACxB;AACF"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { S as unwrap, r as createAsync, w as useContext, y as signal } from "./reactive-
|
|
2
|
-
import { t as Node } from "./node-
|
|
3
|
-
import { i as expandTabs, o as formatText, t as calcLayout } from "./text-
|
|
4
|
-
import { r as textContent } from "./text-
|
|
5
|
-
import { t as RenderContext } from "./render-
|
|
6
|
-
import { n as shikiWorker } from "./client-
|
|
7
|
-
import { t as codeToAnsi } from "./shiki-
|
|
8
|
-
import { t as shikiTheme } from "./theme-
|
|
1
|
+
import { S as unwrap, r as createAsync, w as useContext, y as signal } from "./reactive-DkP75TPk.mjs";
|
|
2
|
+
import { t as Node } from "./node-CXNobGaP.mjs";
|
|
3
|
+
import { i as expandTabs, o as formatText, t as calcLayout } from "./text-4arC3odI.mjs";
|
|
4
|
+
import { r as textContent } from "./text-BArwVVkg.mjs";
|
|
5
|
+
import { t as RenderContext } from "./render-Bp2N2i6J.mjs";
|
|
6
|
+
import { n as shikiWorker } from "./client-BWm6dNZF.mjs";
|
|
7
|
+
import { t as codeToAnsi } from "./shiki-BAf9PdIc.mjs";
|
|
8
|
+
import { t as shikiTheme } from "./theme-B8hb1lPU.mjs";
|
|
9
9
|
import { hasColors } from "@zaly/shared/env";
|
|
10
|
-
|
|
10
|
+
// src/widgets/markdown.ts
|
|
11
11
|
var Markdown = class extends Node {
|
|
12
12
|
images = /* @__PURE__ */ new Map();
|
|
13
13
|
#renderer;
|
|
@@ -74,7 +74,7 @@ var Markdown = class extends Node {
|
|
|
74
74
|
}
|
|
75
75
|
async _render(ctx) {
|
|
76
76
|
if (!this.#renderer) {
|
|
77
|
-
const { MarkdownRenderer } = await import("./renderer-
|
|
77
|
+
const { MarkdownRenderer } = await import("./renderer-Ctz0hv5o.mjs");
|
|
78
78
|
this.#renderer = new MarkdownRenderer({
|
|
79
79
|
...this.state.options,
|
|
80
80
|
parent: this
|
|
@@ -119,7 +119,6 @@ function markdown(first, style) {
|
|
|
119
119
|
});
|
|
120
120
|
return new Markdown(first);
|
|
121
121
|
}
|
|
122
|
-
//#endregion
|
|
123
122
|
export { markdown as n, Markdown as t };
|
|
124
123
|
|
|
125
|
-
//# sourceMappingURL=markdown-
|
|
124
|
+
//# sourceMappingURL=markdown-CgRZBhIX.mjs.map
|