@zaly/tui 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +59 -0
  3. package/assets/schemas/theme.schema.json +899 -0
  4. package/assets/themes/LICENSE-tokyonight.txt +201 -0
  5. package/assets/themes/NOTICES.md +69 -0
  6. package/assets/themes/ayu-dark.json +119 -0
  7. package/assets/themes/catppuccin-frappe.json +124 -0
  8. package/assets/themes/catppuccin-latte.json +124 -0
  9. package/assets/themes/catppuccin-macchiato.json +124 -0
  10. package/assets/themes/catppuccin-mocha.json +124 -0
  11. package/assets/themes/dracula-soft.json +119 -0
  12. package/assets/themes/dracula.json +119 -0
  13. package/assets/themes/everforest-dark.json +118 -0
  14. package/assets/themes/everforest-light.json +118 -0
  15. package/assets/themes/github-dark.json +123 -0
  16. package/assets/themes/github-light.json +123 -0
  17. package/assets/themes/gruvbox-dark-medium.json +112 -0
  18. package/assets/themes/kanagawa-dragon.json +115 -0
  19. package/assets/themes/kanagawa-wave.json +115 -0
  20. package/assets/themes/material-theme-palenight.json +114 -0
  21. package/assets/themes/min-dark.json +55 -0
  22. package/assets/themes/min-light.json +59 -0
  23. package/assets/themes/monokai.json +116 -0
  24. package/assets/themes/night-owl.json +116 -0
  25. package/assets/themes/nord.json +101 -0
  26. package/assets/themes/one-dark-pro.json +110 -0
  27. package/assets/themes/one-light.json +108 -0
  28. package/assets/themes/poimandres.json +123 -0
  29. package/assets/themes/rose-pine.json +98 -0
  30. package/assets/themes/solarized-dark.json +116 -0
  31. package/assets/themes/solarized-light.json +116 -0
  32. package/assets/themes/synthwave-84.json +100 -0
  33. package/assets/themes/tokyonight-day.json +157 -0
  34. package/assets/themes/tokyonight-moon.json +157 -0
  35. package/assets/themes/tokyonight-night.json +157 -0
  36. package/assets/themes/tokyonight-storm.json +157 -0
  37. package/assets/themes/vesper.json +103 -0
  38. package/assets/themes/vitesse-dark.json +126 -0
  39. package/assets/themes/vitesse-light.json +126 -0
  40. package/dist/ansi-Clq0ozyA.mjs +206 -0
  41. package/dist/ansi-Clq0ozyA.mjs.map +1 -0
  42. package/dist/ansi.d.mts +48 -0
  43. package/dist/ansi.d.mts.map +1 -0
  44. package/dist/ansi.mjs +2 -0
  45. package/dist/autocomplete-Dfw-yQDa.d.mts +100 -0
  46. package/dist/autocomplete-Dfw-yQDa.d.mts.map +1 -0
  47. package/dist/box-DyaByEiG.mjs +386 -0
  48. package/dist/box-DyaByEiG.mjs.map +1 -0
  49. package/dist/builder-D49ECBEf.mjs +385 -0
  50. package/dist/builder-D49ECBEf.mjs.map +1 -0
  51. package/dist/callbacks-CNjGNxVw.mjs +279 -0
  52. package/dist/callbacks-CNjGNxVw.mjs.map +1 -0
  53. package/dist/client-D6C_uczF.mjs +142 -0
  54. package/dist/client-D6C_uczF.mjs.map +1 -0
  55. package/dist/clipboard.d.mts +104 -0
  56. package/dist/clipboard.d.mts.map +1 -0
  57. package/dist/clipboard.mjs +404 -0
  58. package/dist/clipboard.mjs.map +1 -0
  59. package/dist/flex-Bguo-fUe.mjs +202 -0
  60. package/dist/flex-Bguo-fUe.mjs.map +1 -0
  61. package/dist/image-Cm5T-uw-.mjs +108 -0
  62. package/dist/image-Cm5T-uw-.mjs.map +1 -0
  63. package/dist/image.d.mts +123 -0
  64. package/dist/image.d.mts.map +1 -0
  65. package/dist/image.mjs +2 -0
  66. package/dist/index.d.mts +64 -0
  67. package/dist/index.d.mts.map +1 -0
  68. package/dist/index.mjs +222 -0
  69. package/dist/index.mjs.map +1 -0
  70. package/dist/input-B5Vy-iaa.d.mts +141 -0
  71. package/dist/input-B5Vy-iaa.d.mts.map +1 -0
  72. package/dist/inspect-D1d9t-ni.mjs +101 -0
  73. package/dist/inspect-D1d9t-ni.mjs.map +1 -0
  74. package/dist/inspect-D6FW_QUo.d.mts +67 -0
  75. package/dist/inspect-D6FW_QUo.d.mts.map +1 -0
  76. package/dist/kitty-JbCJC0iQ.mjs +673 -0
  77. package/dist/kitty-JbCJC0iQ.mjs.map +1 -0
  78. package/dist/markdown.d.mts +24 -0
  79. package/dist/markdown.d.mts.map +1 -0
  80. package/dist/markdown.mjs +2 -0
  81. package/dist/md.bun.d.mts +14 -0
  82. package/dist/md.bun.d.mts.map +1 -0
  83. package/dist/md.bun.mjs +28 -0
  84. package/dist/md.bun.mjs.map +1 -0
  85. package/dist/md.node.d.mts +14 -0
  86. package/dist/md.node.d.mts.map +1 -0
  87. package/dist/md.node.mjs +126 -0
  88. package/dist/md.node.mjs.map +1 -0
  89. package/dist/node-BZ7f6HzU.mjs +316 -0
  90. package/dist/node-BZ7f6HzU.mjs.map +1 -0
  91. package/dist/picker-D8OLb6kZ.d.mts +36 -0
  92. package/dist/picker-D8OLb6kZ.d.mts.map +1 -0
  93. package/dist/picker-ndVVt6qF.mjs +621 -0
  94. package/dist/picker-ndVVt6qF.mjs.map +1 -0
  95. package/dist/queries-DH3bj74K.d.mts +1963 -0
  96. package/dist/queries-DH3bj74K.d.mts.map +1 -0
  97. package/dist/reactive-f7NpAi69.mjs +623 -0
  98. package/dist/reactive-f7NpAi69.mjs.map +1 -0
  99. package/dist/registry-U654j61Y.mjs +356 -0
  100. package/dist/registry-U654j61Y.mjs.map +1 -0
  101. package/dist/render-DxVLqqB9.mjs +74 -0
  102. package/dist/render-DxVLqqB9.mjs.map +1 -0
  103. package/dist/renderer-CdLCkJB-.mjs +42 -0
  104. package/dist/renderer-CdLCkJB-.mjs.map +1 -0
  105. package/dist/renderer-CxL4xbkl.mjs +2644 -0
  106. package/dist/renderer-CxL4xbkl.mjs.map +1 -0
  107. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  108. package/dist/search-FvGnswRl.d.mts +49 -0
  109. package/dist/search-FvGnswRl.d.mts.map +1 -0
  110. package/dist/select-CbmAZdpt.d.mts +116 -0
  111. package/dist/select-CbmAZdpt.d.mts.map +1 -0
  112. package/dist/services/logger.d.mts +2 -0
  113. package/dist/services/logger.mjs +71 -0
  114. package/dist/services/logger.mjs.map +1 -0
  115. package/dist/services/notifier.d.mts +17 -0
  116. package/dist/services/notifier.d.mts.map +1 -0
  117. package/dist/services/notifier.mjs +71 -0
  118. package/dist/services/notifier.mjs.map +1 -0
  119. package/dist/services/picker.d.mts +36 -0
  120. package/dist/services/picker.d.mts.map +1 -0
  121. package/dist/services/picker.mjs +137 -0
  122. package/dist/services/picker.mjs.map +1 -0
  123. package/dist/services/prompt.d.mts +30 -0
  124. package/dist/services/prompt.d.mts.map +1 -0
  125. package/dist/services/prompt.mjs +83 -0
  126. package/dist/services/prompt.mjs.map +1 -0
  127. package/dist/shiki-BrjVUkeh.mjs +423 -0
  128. package/dist/shiki-BrjVUkeh.mjs.map +1 -0
  129. package/dist/size-D8JogYLy.mjs +34 -0
  130. package/dist/size-D8JogYLy.mjs.map +1 -0
  131. package/dist/style.d.mts +10 -0
  132. package/dist/style.d.mts.map +1 -0
  133. package/dist/style.mjs +4 -0
  134. package/dist/text.d.mts +33 -0
  135. package/dist/text.d.mts.map +1 -0
  136. package/dist/text.mjs +111 -0
  137. package/dist/text.mjs.map +1 -0
  138. package/dist/theme.config-CU3B50HN.mjs +832 -0
  139. package/dist/theme.config-CU3B50HN.mjs.map +1 -0
  140. package/dist/themes.d.mts +113 -0
  141. package/dist/themes.d.mts.map +1 -0
  142. package/dist/themes.mjs +2 -0
  143. package/dist/tree-C28QOVIK.d.mts +23 -0
  144. package/dist/tree-C28QOVIK.d.mts.map +1 -0
  145. package/dist/types-B9Eh7k2v.d.mts +212 -0
  146. package/dist/types-B9Eh7k2v.d.mts.map +1 -0
  147. package/dist/types-D3jk1rtk.d.mts +140 -0
  148. package/dist/types-D3jk1rtk.d.mts.map +1 -0
  149. package/dist/utils-3M4D_AXZ.mjs +40 -0
  150. package/dist/utils-3M4D_AXZ.mjs.map +1 -0
  151. package/dist/widgets/autocomplete.d.mts +2 -0
  152. package/dist/widgets/autocomplete.mjs +165 -0
  153. package/dist/widgets/autocomplete.mjs.map +1 -0
  154. package/dist/widgets/box.d.mts +2 -0
  155. package/dist/widgets/box.mjs +2 -0
  156. package/dist/widgets/code.d.mts +48 -0
  157. package/dist/widgets/code.d.mts.map +1 -0
  158. package/dist/widgets/code.mjs +59 -0
  159. package/dist/widgets/code.mjs.map +1 -0
  160. package/dist/widgets/completions/actions.d.mts +41 -0
  161. package/dist/widgets/completions/actions.d.mts.map +1 -0
  162. package/dist/widgets/completions/actions.mjs +48 -0
  163. package/dist/widgets/completions/actions.mjs.map +1 -0
  164. package/dist/widgets/completions/files.d.mts +29 -0
  165. package/dist/widgets/completions/files.d.mts.map +1 -0
  166. package/dist/widgets/completions/files.mjs +42 -0
  167. package/dist/widgets/completions/files.mjs.map +1 -0
  168. package/dist/widgets/completions/github.d.mts +64 -0
  169. package/dist/widgets/completions/github.d.mts.map +1 -0
  170. package/dist/widgets/completions/github.mjs +137 -0
  171. package/dist/widgets/completions/github.mjs.map +1 -0
  172. package/dist/widgets/completions/index.d.mts +4 -0
  173. package/dist/widgets/completions/index.mjs +4 -0
  174. package/dist/widgets/diff.d.mts +57 -0
  175. package/dist/widgets/diff.d.mts.map +1 -0
  176. package/dist/widgets/diff.mjs +199 -0
  177. package/dist/widgets/diff.mjs.map +1 -0
  178. package/dist/widgets/divider.d.mts +11 -0
  179. package/dist/widgets/divider.d.mts.map +1 -0
  180. package/dist/widgets/divider.mjs +9 -0
  181. package/dist/widgets/divider.mjs.map +1 -0
  182. package/dist/widgets/image.d.mts +37 -0
  183. package/dist/widgets/image.d.mts.map +1 -0
  184. package/dist/widgets/image.mjs +77 -0
  185. package/dist/widgets/image.mjs.map +1 -0
  186. package/dist/widgets/input.d.mts +2 -0
  187. package/dist/widgets/input.mjs +497 -0
  188. package/dist/widgets/input.mjs.map +1 -0
  189. package/dist/widgets/log.d.mts +2 -0
  190. package/dist/widgets/log.mjs +130 -0
  191. package/dist/widgets/log.mjs.map +1 -0
  192. package/dist/widgets/markdown.d.mts +45 -0
  193. package/dist/widgets/markdown.d.mts.map +1 -0
  194. package/dist/widgets/markdown.mjs +124 -0
  195. package/dist/widgets/markdown.mjs.map +1 -0
  196. package/dist/widgets/overlay.d.mts +2 -0
  197. package/dist/widgets/overlay.mjs +18 -0
  198. package/dist/widgets/overlay.mjs.map +1 -0
  199. package/dist/widgets/picker.d.mts +2 -0
  200. package/dist/widgets/picker.mjs +2 -0
  201. package/dist/widgets/progress.d.mts +48 -0
  202. package/dist/widgets/progress.d.mts.map +1 -0
  203. package/dist/widgets/progress.mjs +48 -0
  204. package/dist/widgets/progress.mjs.map +1 -0
  205. package/dist/widgets/select.d.mts +2 -0
  206. package/dist/widgets/select.mjs +195 -0
  207. package/dist/widgets/select.mjs.map +1 -0
  208. package/dist/widgets/show.d.mts +55 -0
  209. package/dist/widgets/show.d.mts.map +1 -0
  210. package/dist/widgets/show.mjs +85 -0
  211. package/dist/widgets/show.mjs.map +1 -0
  212. package/dist/widgets/spinner.d.mts +65 -0
  213. package/dist/widgets/spinner.d.mts.map +1 -0
  214. package/dist/widgets/spinner.mjs +147 -0
  215. package/dist/widgets/spinner.mjs.map +1 -0
  216. package/dist/widgets/text.d.mts +2 -0
  217. package/dist/widgets/text.mjs +32 -0
  218. package/dist/widgets/text.mjs.map +1 -0
  219. package/dist/widgets/tree.d.mts +2 -0
  220. package/dist/widgets/tree.mjs +73 -0
  221. package/dist/widgets/tree.mjs.map +1 -0
  222. package/dist/widgets/widget.d.mts +49 -0
  223. package/dist/widgets/widget.d.mts.map +1 -0
  224. package/dist/widgets/widget.mjs +40 -0
  225. package/dist/widgets/widget.mjs.map +1 -0
  226. package/dist/worker-DjHuQSbY.mjs +27 -0
  227. package/dist/worker-DjHuQSbY.mjs.map +1 -0
  228. package/package.json +117 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kitty-JbCJC0iQ.mjs","names":["#support","#wrap"],"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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"}
@@ -0,0 +1,24 @@
1
+ import { P as RenderCtx, p as Node } from "./queries-DH3bj74K.mjs";
2
+ import { n as MdOptions, r as RenderMarkdown } from "./types-D3jk1rtk.mjs";
3
+ //#region src/markdown/renderer.d.ts
4
+ type MarkdownOptions = MdOptions & {
5
+ parent?: Node;
6
+ };
7
+ type MarkdownCtx = RenderCtx & {
8
+ images?: boolean;
9
+ highlight?: (code: string, lang?: string) => string;
10
+ };
11
+ declare class MarkdownRenderer {
12
+ #private;
13
+ constructor(opts?: MarkdownOptions);
14
+ render(source: string, ctx: MarkdownCtx): Promise<string>;
15
+ /** Mirror the source's trailing newlines: the renderer adds its own
16
+ /* padding after blocks (`\n\n` after paragraphs, etc.) which would
17
+ /* leave stray blank rows. Normalizing to what the caller typed keeps
18
+ /* single-line inputs compact and preserves explicit spacing when
19
+ /* they asked for it. */
20
+ normalizeEol(source: string, rendered: string): string;
21
+ }
22
+ //#endregion
23
+ export { MarkdownCtx, MarkdownOptions, MarkdownRenderer, type MdOptions, type RenderMarkdown };
24
+ //# sourceMappingURL=markdown.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.mts","names":[],"sources":["../src/markdown/renderer.ts"],"mappings":";;;KAKY,kBAAkB;EAC5B,SAAS;;KAGC,cAAc;EACxB;EACA,aAAa,cAAc;;cAGhB;;EAMX,YAAY,OAAM;EAKZ,OAAO,gBAAgB,KAAK,cAAc;;;;;;EAqChD,aAAa,gBAAgB"}
@@ -0,0 +1,2 @@
1
+ import { t as MarkdownRenderer } from "./renderer-CdLCkJB-.mjs";
2
+ export { MarkdownRenderer };
@@ -0,0 +1,14 @@
1
+ import { n as MdOptions, t as MdCallbacks } from "./types-D3jk1rtk.mjs";
2
+ //#region src/runtime/md.bun.d.ts
3
+ /**
4
+ * Bun wrapper for `renderMarkdown`. `Bun.markdown.render` truncates code
5
+ * fence info-strings at the first whitespace, so attrs like
6
+ * `title="foo.ts"` never make it through. We pre-encode the spaces as
7
+ * NUL sentinels and decode the full string back into `{ language, title }`
8
+ * inside the `code` callback. Node's marked-backed impl parses info-
9
+ * strings natively, so the equivalent dance lives only here.
10
+ */
11
+ declare function renderMarkdown(input: string, callbacks: MdCallbacks, opts?: MdOptions): string;
12
+ //#endregion
13
+ export { renderMarkdown };
14
+ //# sourceMappingURL=md.bun.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"md.bun.d.mts","names":[],"sources":["../src/runtime/md.bun.ts"],"mappings":";;;;;;;;;;iBAYgB,eAAe,eAAe,WAAW,aAAa,OAAO"}
@@ -0,0 +1,28 @@
1
+ import { n as parseCodeInfoString, t as encodeFenceInfoStrings } from "./utils-3M4D_AXZ.mjs";
2
+ //#region src/runtime/md.bun.ts
3
+ /**
4
+ * Bun wrapper for `renderMarkdown`. `Bun.markdown.render` truncates code
5
+ * fence info-strings at the first whitespace, so attrs like
6
+ * `title="foo.ts"` never make it through. We pre-encode the spaces as
7
+ * NUL sentinels and decode the full string back into `{ language, title }`
8
+ * inside the `code` callback. Node's marked-backed impl parses info-
9
+ * strings natively, so the equivalent dance lives only here.
10
+ */
11
+ function renderMarkdown(input, callbacks, opts) {
12
+ const encoded = encodeFenceInfoStrings(input);
13
+ const wrapped = callbacks.code === void 0 ? callbacks : {
14
+ ...callbacks,
15
+ code: (text, meta) => callbacks.code(text, decodeCodeMeta(meta))
16
+ };
17
+ return Bun.markdown.render(encoded, wrapped, opts);
18
+ }
19
+ function decodeCodeMeta(meta) {
20
+ if (meta === void 0) return void 0;
21
+ if (meta.title !== void 0) return meta;
22
+ if (meta.language === void 0) return meta;
23
+ return parseCodeInfoString(meta.language) ?? meta;
24
+ }
25
+ //#endregion
26
+ export { renderMarkdown };
27
+
28
+ //# sourceMappingURL=md.bun.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"md.bun.mjs","names":[],"sources":["../src/runtime/md.bun.ts"],"sourcesContent":["import type { MdCallbacks, MdCodeBlockMeta, MdOptions } from \"../markdown/types.ts\"\n\nimport { encodeFenceInfoStrings, parseCodeInfoString } from \"../markdown/utils.ts\"\n\n/**\n * Bun wrapper for `renderMarkdown`. `Bun.markdown.render` truncates code\n * fence info-strings at the first whitespace, so attrs like\n * `title=\"foo.ts\"` never make it through. We pre-encode the spaces as\n * NUL sentinels and decode the full string back into `{ language, title }`\n * inside the `code` callback. Node's marked-backed impl parses info-\n * strings natively, so the equivalent dance lives only here.\n */\nexport function renderMarkdown(input: string, callbacks: MdCallbacks, opts?: MdOptions): string {\n const encoded = encodeFenceInfoStrings(input)\n const wrapped: MdCallbacks =\n callbacks.code === undefined\n ? callbacks\n : {\n ...callbacks,\n code: (text, meta) => callbacks.code!(text, decodeCodeMeta(meta)),\n }\n return Bun.markdown.render(encoded, wrapped, opts)\n}\n\nfunction decodeCodeMeta(meta: MdCodeBlockMeta | undefined): MdCodeBlockMeta | undefined {\n if (meta === undefined) return undefined\n if (meta.title !== undefined) return meta\n if (meta.language === undefined) return meta\n return parseCodeInfoString(meta.language) ?? meta\n}\n"],"mappings":";;;;;;;;;;AAYA,SAAgB,eAAe,OAAe,WAAwB,MAA0B;CAC9F,MAAM,UAAU,uBAAuB,KAAK;CAC5C,MAAM,UACJ,UAAU,SAAS,KAAA,IACf,YACA;EACE,GAAG;EACH,OAAO,MAAM,SAAS,UAAU,KAAM,MAAM,eAAe,IAAI,CAAC;CAClE;CACN,OAAO,IAAI,SAAS,OAAO,SAAS,SAAS,IAAI;AACnD;AAEA,SAAS,eAAe,MAAgE;CACtF,IAAI,SAAS,KAAA,GAAW,OAAO,KAAA;CAC/B,IAAI,KAAK,UAAU,KAAA,GAAW,OAAO;CACrC,IAAI,KAAK,aAAa,KAAA,GAAW,OAAO;CACxC,OAAO,oBAAoB,KAAK,QAAQ,KAAK;AAC/C"}
@@ -0,0 +1,14 @@
1
+ import { n as MdOptions, t as MdCallbacks } from "./types-D3jk1rtk.mjs";
2
+ //#region src/markdown/marked.d.ts
3
+ /**
4
+ * Walk the markdown source with `marked`'s lexer and invoke the caller's
5
+ * callbacks for each block / inline element. Output shape matches
6
+ * `Bun.markdown.render()` — same callback names, same metadata, same
7
+ * "null/undefined omits, missing callback passes through" semantics.
8
+ *
9
+ * @internal
10
+ */
11
+ declare function renderMarkdown(input: string, callbacks: MdCallbacks, opts?: MdOptions): string;
12
+ //#endregion
13
+ export { renderMarkdown };
14
+ //# sourceMappingURL=md.node.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"md.node.d.mts","names":[],"sources":["../src/markdown/marked.ts"],"mappings":";;;;;;;;;;iBAuBgB,eAAe,eAAe,WAAW,aAAa,OAAO"}
@@ -0,0 +1,126 @@
1
+ import { n as parseCodeInfoString } from "./utils-3M4D_AXZ.mjs";
2
+ import { marked } from "marked";
3
+ //#region src/markdown/marked.ts
4
+ /**
5
+ * Walk the markdown source with `marked`'s lexer and invoke the caller's
6
+ * callbacks for each block / inline element. Output shape matches
7
+ * `Bun.markdown.render()` — same callback names, same metadata, same
8
+ * "null/undefined omits, missing callback passes through" semantics.
9
+ *
10
+ * @internal
11
+ */
12
+ function renderMarkdown(input, callbacks, opts) {
13
+ return renderTokens(marked.lexer(input, {
14
+ breaks: opts?.hardSoftBreaks ?? false,
15
+ gfm: true
16
+ }), callbacks, 0);
17
+ }
18
+ function renderTokens(tokens, cb, depth) {
19
+ let out = "";
20
+ for (const tok of tokens) out += renderToken(tok, cb, depth);
21
+ return out;
22
+ }
23
+ function renderToken(tok, cb, depth) {
24
+ switch (tok.type) {
25
+ case "heading": {
26
+ const t = tok;
27
+ return applyMeta(renderTokens(t.tokens, cb, depth), { level: t.depth }, cb.heading);
28
+ }
29
+ case "paragraph": return applyBlock(renderTokens(tok.tokens, cb, depth), cb.paragraph);
30
+ case "blockquote": return applyBlock(renderTokens(tok.tokens, cb, depth), cb.blockquote);
31
+ case "code": {
32
+ const t = tok;
33
+ const meta = parseCodeInfoString(t.lang);
34
+ if (cb.code === void 0) return t.text;
35
+ return cb.code(t.text, meta) ?? "";
36
+ }
37
+ case "list": {
38
+ const t = tok;
39
+ const ordered = t.ordered;
40
+ const start = ordered && t.start !== "" ? t.start : void 0;
41
+ const childDepth = depth + 1;
42
+ let items = "";
43
+ for (let i = 0; i < t.items.length; i++) {
44
+ const item = t.items[i];
45
+ const kids = renderTokens(item.tokens, cb, childDepth);
46
+ const meta = {
47
+ checked: item.task ? item.checked : void 0,
48
+ depth,
49
+ index: i,
50
+ ordered,
51
+ start
52
+ };
53
+ items += applyMeta(kids, meta, cb.listItem);
54
+ }
55
+ return applyMeta(items, {
56
+ depth,
57
+ ordered,
58
+ start
59
+ }, cb.list);
60
+ }
61
+ case "hr": return applyBlock("", cb.hr);
62
+ case "table": {
63
+ const t = tok;
64
+ const aligns = t.align;
65
+ const renderCell = (cell, col, fn) => {
66
+ const kids = renderTokens(cell.tokens, cb, depth);
67
+ const a = aligns[col];
68
+ const meta = a === null ? void 0 : { align: a };
69
+ if (fn === void 0) return kids;
70
+ return fn(kids, meta) ?? "";
71
+ };
72
+ return applyBlock(applyBlock(applyBlock(t.header.map((c, i) => renderCell(c, i, cb.th)).join(""), cb.tr), cb.thead) + applyBlock(t.rows.map((row) => applyBlock(row.map((c, i) => renderCell(c, i, cb.td)).join(""), cb.tr)).join(""), cb.tbody), cb.table);
73
+ }
74
+ case "html": return applyBlock(tok.text, cb.html);
75
+ case "space": return "";
76
+ case "strong": return applyBlock(renderTokens(tok.tokens, cb, depth), cb.strong);
77
+ case "em": return applyBlock(renderTokens(tok.tokens, cb, depth), cb.emphasis);
78
+ case "codespan": {
79
+ const t = tok;
80
+ if (cb.codespan === void 0) return t.text;
81
+ return cb.codespan(t.text) ?? "";
82
+ }
83
+ case "del": return applyBlock(renderTokens(tok.tokens, cb, depth), cb.strikethrough);
84
+ case "link": {
85
+ const t = tok;
86
+ return applyMeta(renderTokens(t.tokens, cb, depth), {
87
+ href: t.href,
88
+ title: t.title ?? void 0
89
+ }, cb.link);
90
+ }
91
+ case "image": {
92
+ const t = tok;
93
+ const meta = {
94
+ src: t.href,
95
+ title: t.title ?? void 0
96
+ };
97
+ if (cb.image === void 0) return t.text;
98
+ return cb.image(t.text, meta) ?? "";
99
+ }
100
+ case "br": return "\n";
101
+ case "checkbox": return "";
102
+ case "escape": return applyText(tok.text, cb);
103
+ case "text": {
104
+ const t = tok;
105
+ if (t.tokens) return renderTokens(t.tokens, cb, depth);
106
+ return applyText(t.text, cb);
107
+ }
108
+ default: return tok.text ?? tok.raw ?? "";
109
+ }
110
+ }
111
+ function applyBlock(children, fn) {
112
+ if (fn === void 0) return children;
113
+ return fn(children) ?? "";
114
+ }
115
+ function applyMeta(children, meta, fn) {
116
+ if (fn === void 0) return children;
117
+ return fn(children, meta) ?? "";
118
+ }
119
+ function applyText(text, cb) {
120
+ if (cb.text === void 0) return text;
121
+ return cb.text(text) ?? "";
122
+ }
123
+ //#endregion
124
+ export { renderMarkdown };
125
+
126
+ //# sourceMappingURL=md.node.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"md.node.mjs","names":["t"],"sources":["../src/markdown/marked.ts"],"sourcesContent":["import type { Token, Tokens } from \"marked\"\nimport type {\n CbNoMeta,\n MdCallbacks,\n MdCellMeta,\n MdImageMeta,\n MdListItemMeta,\n MdOptions,\n} from \"./types.ts\"\n\nimport { marked } from \"marked\"\nimport { parseCodeInfoString } from \"./utils.ts\"\n\n// ── Implementation (Node-side; Bun's runtime passes through to Bun.markdown) ──\n\n/**\n * Walk the markdown source with `marked`'s lexer and invoke the caller's\n * callbacks for each block / inline element. Output shape matches\n * `Bun.markdown.render()` — same callback names, same metadata, same\n * \"null/undefined omits, missing callback passes through\" semantics.\n *\n * @internal\n */\nexport function renderMarkdown(input: string, callbacks: MdCallbacks, opts?: MdOptions): string {\n const tokens = marked.lexer(input, {\n breaks: opts?.hardSoftBreaks ?? false,\n gfm: true,\n })\n return renderTokens(tokens, callbacks, 0)\n}\n\nfunction renderTokens(tokens: Token[], cb: MdCallbacks, depth: number): string {\n let out = \"\"\n for (const tok of tokens) out += renderToken(tok, cb, depth)\n return out\n}\n\nfunction renderToken(tok: Token, cb: MdCallbacks, depth: number): string {\n switch (tok.type) {\n case \"heading\": {\n const t = tok as Tokens.Heading\n const children = renderTokens(t.tokens, cb, depth)\n return applyMeta(children, { level: t.depth }, cb.heading)\n }\n case \"paragraph\": {\n const t = tok as Tokens.Paragraph\n const children = renderTokens(t.tokens, cb, depth)\n return applyBlock(children, cb.paragraph)\n }\n case \"blockquote\": {\n const t = tok as Tokens.Blockquote\n const children = renderTokens(t.tokens, cb, depth)\n return applyBlock(children, cb.blockquote)\n }\n case \"code\": {\n const t = tok as Tokens.Code\n const meta = parseCodeInfoString(t.lang)\n if (cb.code === undefined) return t.text\n return cb.code(t.text, meta) ?? \"\"\n }\n case \"list\": {\n const t = tok as Tokens.List\n const ordered = t.ordered\n const start = ordered && t.start !== \"\" ? t.start : undefined\n const childDepth = depth + 1\n let items = \"\"\n for (let i = 0; i < t.items.length; i++) {\n const item = t.items[i]\n const kids = renderTokens(item.tokens, cb, childDepth)\n const meta: MdListItemMeta = {\n checked: item.task ? item.checked : undefined,\n depth,\n index: i,\n ordered,\n start,\n }\n items += applyMeta(kids, meta, cb.listItem)\n }\n return applyMeta(items, { depth, ordered, start }, cb.list)\n }\n case \"hr\": {\n return applyBlock(\"\", cb.hr)\n }\n case \"table\": {\n const t = tok as Tokens.Table\n const aligns = t.align\n const renderCell = (\n cell: Tokens.TableCell,\n col: number,\n fn: MdCallbacks[\"th\"] | MdCallbacks[\"td\"]\n ): string => {\n const kids = renderTokens(cell.tokens, cb, depth)\n const a = aligns[col]\n const meta: MdCellMeta | undefined = a === null ? undefined : { align: a }\n if (fn === undefined) return kids\n return fn(kids, meta) ?? \"\"\n }\n const headerRow = t.header.map((c, i) => renderCell(c, i, cb.th)).join(\"\")\n const thead = applyBlock(applyBlock(headerRow, cb.tr), cb.thead)\n const bodyRows = t.rows\n .map((row) => applyBlock(row.map((c, i) => renderCell(c, i, cb.td)).join(\"\"), cb.tr))\n .join(\"\")\n const tbody = applyBlock(bodyRows, cb.tbody)\n return applyBlock(thead + tbody, cb.table)\n }\n case \"html\": {\n const t = tok as Tokens.HTML\n return applyBlock(t.text, cb.html)\n }\n case \"space\": {\n // marked emits these for inter-block whitespace; drop — block callbacks\n // add their own trailing separators.\n return \"\"\n }\n case \"strong\": {\n const t = tok as Tokens.Strong\n const children = renderTokens(t.tokens, cb, depth)\n return applyBlock(children, cb.strong)\n }\n case \"em\": {\n const t = tok as Tokens.Em\n const children = renderTokens(t.tokens, cb, depth)\n return applyBlock(children, cb.emphasis)\n }\n case \"codespan\": {\n const t = tok as Tokens.Codespan\n if (cb.codespan === undefined) return t.text\n return cb.codespan(t.text) ?? \"\"\n }\n case \"del\": {\n const t = tok as Tokens.Del\n const children = renderTokens(t.tokens, cb, depth)\n return applyBlock(children, cb.strikethrough)\n }\n case \"link\": {\n const t = tok as Tokens.Link\n const children = renderTokens(t.tokens, cb, depth)\n return applyMeta(children, { href: t.href, title: t.title ?? undefined }, cb.link)\n }\n case \"image\": {\n const t = tok as Tokens.Image\n const meta: MdImageMeta = { src: t.href, title: t.title ?? undefined }\n if (cb.image === undefined) return t.text\n return cb.image(t.text, meta) ?? \"\"\n }\n case \"br\": {\n return \"\\n\"\n }\n case \"checkbox\": {\n // marked emits this as a sibling of the task-item content. Drop —\n // the state is already carried on MdListItemMeta.checked.\n return \"\"\n }\n case \"escape\": {\n const t = tok as Tokens.Escape\n return applyText(t.text, cb)\n }\n case \"text\": {\n const t = tok as Tokens.Text\n // Block-level text wrappers carry inline tokens — recurse.\n if (t.tokens) return renderTokens(t.tokens, cb, depth)\n return applyText(t.text, cb)\n }\n default: {\n // Unknown / unsupported — pass through raw if available.\n const raw = (tok as { text?: string; raw?: string }).text\n return raw ?? (tok as { raw?: string }).raw ?? \"\"\n }\n }\n}\n\nfunction applyBlock(children: string, fn: CbNoMeta | undefined): string {\n if (fn === undefined) return children\n return fn(children) ?? \"\"\n}\n\nfunction applyMeta<M>(\n children: string,\n meta: M,\n fn: ((children: string, meta: M) => string | null | undefined) | undefined\n): string {\n if (fn === undefined) return children\n return fn(children, meta) ?? \"\"\n}\n\nfunction applyText(text: string, cb: MdCallbacks): string {\n if (cb.text === undefined) return text\n return cb.text(text) ?? \"\"\n}\n"],"mappings":"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"}
@@ -0,0 +1,316 @@
1
+ import { S as unwrap, T as withActiveNode, p as inRenderContextOf, u as createStore } from "./reactive-f7NpAi69.mjs";
2
+ import { Emitter } from "@zaly/shared";
3
+ //#region src/core/node.ts
4
+ /**
5
+ * Public Node handle. Calling `render(ctx)` returns the node's rows from the
6
+ * per-node cache, recomputing only if state read inside `_render` has changed
7
+ * since the last call.
8
+ *
9
+ * Concrete subclasses implement the protected `_render(ctx)` hook; the public
10
+ * `render` is the caching wrapper around it.
11
+ *
12
+ * State is a `createStore` proxy: reads inside `_render` track per-field;
13
+ * mutating a read field invalidates this node. Three write forms:
14
+ *
15
+ * - `n.state.field = value` (direct assignment)
16
+ * - `n.state.set({ field: value, ... })` (patch — partial merge)
17
+ * - `n.state.set(current => ({ ... }))` (updater — receives untracked current)
18
+ *
19
+ * Writes through nested objects/arrays (`n.state.padding[0] = 1`) do NOT —
20
+ * reassign the whole field instead.
21
+ */
22
+ var Node = class extends Emitter {
23
+ #cache;
24
+ #parent;
25
+ #rendering;
26
+ /** Bumped on every `invalidate()`. Captured at the start of a render
27
+ * and re-checked after `_render` resolves: if the count moved, an
28
+ * external mutation landed during the render and the rows we just
29
+ * produced reflect pre-mutation state. We skip writing the cache in
30
+ * that case so the surface's already-scheduled re-paint sees a
31
+ * cache miss and re-renders against the latest state. */
32
+ #invalidations = 0;
33
+ #children = [];
34
+ #state;
35
+ #ctx;
36
+ #id;
37
+ #actionTargets = /* @__PURE__ */ new Set();
38
+ #mountAc;
39
+ actions;
40
+ type;
41
+ constructor(state, ...children) {
42
+ super();
43
+ this.onEmitError = (err) => {
44
+ const logger = this.logger;
45
+ if (logger) logger.error(err);
46
+ else console.error("Uncaught node event error (node is unmounted, no ctx):", err);
47
+ };
48
+ this.#state = createStore(state);
49
+ children.forEach((c) => this.add(c));
50
+ }
51
+ withEvents() {
52
+ return this;
53
+ }
54
+ withActions(actions) {
55
+ this.actions = {
56
+ ...this.actions,
57
+ ...actions
58
+ };
59
+ return this;
60
+ }
61
+ action(id, opts) {
62
+ const entry = this.actions?.[id];
63
+ const fn = typeof entry === "function" ? entry : entry?.fn;
64
+ if (!fn) return false;
65
+ fn({
66
+ source: "programmatic",
67
+ target: this,
68
+ ...opts,
69
+ id,
70
+ node: this
71
+ });
72
+ return true;
73
+ }
74
+ get mountSignal() {
75
+ this.#mountAc ??= new AbortController();
76
+ return this.#mountAc.signal;
77
+ }
78
+ get state() {
79
+ return this.#state;
80
+ }
81
+ get children() {
82
+ return this.#children;
83
+ }
84
+ get logger() {
85
+ return this.#ctx?.logger.child({
86
+ id: this.#id,
87
+ name: "node",
88
+ node: this.type ?? "unknown"
89
+ });
90
+ }
91
+ try(fn) {
92
+ const logger = this.logger;
93
+ if (!logger) return fn();
94
+ return logger.try(fn);
95
+ }
96
+ get parent() {
97
+ return this.#parent;
98
+ }
99
+ /** Mount context when this node is attached to a surface — surface
100
+ * identifier plus scoped handles to router / overlay / tree lookups.
101
+ * `undefined` before mount and after unmount. Exposed so widget
102
+ * authors can reach renderer services without closing over a ref. */
103
+ get ctx() {
104
+ return this.#ctx;
105
+ }
106
+ get surface() {
107
+ return this.#ctx?.surface;
108
+ }
109
+ get mounted() {
110
+ return this.#ctx !== void 0;
111
+ }
112
+ id(value) {
113
+ if (value === void 0) return this.#id;
114
+ this.#id = value;
115
+ return this;
116
+ }
117
+ async getLayout(ctx) {
118
+ if (!this.layout) return;
119
+ return this.layout(ctx);
120
+ }
121
+ get layoutNodes() {
122
+ if (this.layoutChildren === void 0) return [this];
123
+ const ret = [];
124
+ for (const c of this.with(() => this.layoutChildren?.()) ?? []) ret.push(...c.layoutNodes);
125
+ return ret;
126
+ }
127
+ addActionTarget(node) {
128
+ this.#actionTargets.add(node);
129
+ return this;
130
+ }
131
+ removeActionTarget(node) {
132
+ this.#actionTargets.delete(node);
133
+ return this;
134
+ }
135
+ get actionTargets() {
136
+ return this.#actionTargets;
137
+ }
138
+ invalidate() {
139
+ this.#cache = void 0;
140
+ if (inRenderContextOf(this)) return this;
141
+ this.#invalidations++;
142
+ this.emit("invalidate");
143
+ this.parent?.invalidate();
144
+ return this;
145
+ }
146
+ with(fn) {
147
+ return withActiveNode(this, () => fn());
148
+ }
149
+ async render(ctx) {
150
+ this.#rendering ??= this.with(() => this.#render(ctx));
151
+ try {
152
+ return await this.#rendering;
153
+ } finally {
154
+ this.#rendering = void 0;
155
+ }
156
+ }
157
+ async #render(ctx) {
158
+ if (!(unwrap(this.state.visible) ?? true)) {
159
+ this.#cache = {
160
+ rows: [],
161
+ version: ctx.version,
162
+ width: ctx.width
163
+ };
164
+ return this.#cache.rows;
165
+ }
166
+ if (this.#cache?.version === ctx.version && this.#cache.width === ctx.width) return this.#cache.rows;
167
+ const stamp = this.#invalidations;
168
+ try {
169
+ const rows = await this._render(ctx);
170
+ if (this.#invalidations === stamp) this.#cache = {
171
+ rows,
172
+ version: ctx.version,
173
+ width: ctx.width
174
+ };
175
+ return rows;
176
+ } catch (error) {
177
+ this.logger?.error(error);
178
+ this.#cache = void 0;
179
+ return [ctx.style.error(`[Node render error: ${error instanceof Error ? error.message : String(error)}]`)];
180
+ }
181
+ }
182
+ add(child) {
183
+ this.splice(this.#children.length, 0, child);
184
+ return this;
185
+ }
186
+ remove(child) {
187
+ const i = this.#children.indexOf(child);
188
+ if (i === -1) return this;
189
+ this.splice(i, 1);
190
+ return this;
191
+ }
192
+ splice(start, deleteCount, ...items) {
193
+ const filtered = [];
194
+ for (const c of items) {
195
+ if (c === this) continue;
196
+ filtered.push(c);
197
+ }
198
+ let adjustedStart = Math.max(0, Math.min(start, this.#children.length));
199
+ for (const c of filtered) {
200
+ if (c.parent !== this) continue;
201
+ const i = this.#children.indexOf(c);
202
+ if (i === -1) continue;
203
+ this.#children.splice(i, 1);
204
+ if (i < adjustedStart) adjustedStart--;
205
+ }
206
+ const removed = this.#children.splice(adjustedStart, deleteCount, ...filtered);
207
+ for (const c of removed) {
208
+ this.emit("childremoved", { child: c });
209
+ if (c.mounted) c.unmount();
210
+ if (c.parent === this) c.#parent = void 0;
211
+ }
212
+ for (const c of filtered) {
213
+ if (c.parent && c.parent !== this) {
214
+ c.unmount();
215
+ c.parent.remove(c);
216
+ }
217
+ c.#parent = this;
218
+ this.emit("childadded", { child: c });
219
+ if (this.#ctx !== void 0) c.mount(this.#ctx);
220
+ }
221
+ this.invalidate();
222
+ return this;
223
+ }
224
+ clear() {
225
+ this.splice(0, this.#children.length);
226
+ return this;
227
+ }
228
+ mount(ctx) {
229
+ if (this.#ctx?.surface === ctx.surface) return this;
230
+ if (this.#ctx) throw new Error(`Node is already mounted on "${this.#ctx.surface}" (requested "${ctx.surface}"). Unmount first if you meant to move it.`);
231
+ withActiveNode(this, () => unwrap(this.state.visible));
232
+ this.#ctx = ctx;
233
+ this.#registerActionMeta(ctx);
234
+ this.emit("mount");
235
+ for (const c of this.#children) c.mount(ctx);
236
+ return this;
237
+ }
238
+ /** Contribute any `ActionInfo`-shaped entries in `this.actions` to
239
+ * the catalog. The instance `fn` stays on the node (dispatch finds
240
+ * it via the focus-chain walk); only metadata lands in the registry.
241
+ * Uses `extend: false` so defaults don't clobber user overrides
242
+ * that were registered before the widget mounted. */
243
+ #registerActionMeta(ctx) {
244
+ if (!this.actions) return;
245
+ const metas = {};
246
+ let any = false;
247
+ for (const [id, entry] of Object.entries(this.actions)) {
248
+ if (typeof entry === "function") continue;
249
+ const { fn: _fn, ...info } = entry;
250
+ metas[id] = info;
251
+ any = true;
252
+ }
253
+ if (any) ctx.actions.register(metas, { default: true });
254
+ }
255
+ unmount() {
256
+ if (!this.#ctx) return this;
257
+ this.#mountAc?.abort();
258
+ this.#mountAc = void 0;
259
+ for (const c of this.#children) c.unmount();
260
+ this.emit("unmount");
261
+ this.#ctx.input.blur(this);
262
+ this.#ctx = void 0;
263
+ return this;
264
+ }
265
+ /** Become the focused node. Routes through the MountCtx, which emits
266
+ * `blur` on the previous focus and `focus` on this node.
267
+ *
268
+ * When called before the node is mounted (the common case for
269
+ * `input({ focus: true }).on(...)` style setup), the focus is
270
+ * deferred until the next `mount` event. That keeps the API
271
+ * synchronous and side-effect-free at build time — callers don't
272
+ * have to think about ordering. */
273
+ focus() {
274
+ if (!this.#ctx) {
275
+ this.once("mount", () => this.focus());
276
+ return this;
277
+ }
278
+ this.#ctx.input.focus(this);
279
+ return this;
280
+ }
281
+ /** Release focus. No-op when not mounted. */
282
+ blur() {
283
+ this.#ctx?.input.blur(this);
284
+ return this;
285
+ }
286
+ get visible() {
287
+ return unwrap(this.state.visible) ?? true;
288
+ }
289
+ show() {
290
+ if (this.visible) return this;
291
+ this.state.visible = true;
292
+ this.emit("show");
293
+ return this;
294
+ }
295
+ hide() {
296
+ if (!this.visible) return this;
297
+ this.state.visible = false;
298
+ this.emit("hide");
299
+ return this;
300
+ }
301
+ toggle() {
302
+ this.state.visible = !this.visible;
303
+ return this;
304
+ }
305
+ ref(ref) {
306
+ if (ref) ref.value = this;
307
+ return this;
308
+ }
309
+ isVisible() {
310
+ return this.visible && (this.parent ? this.parent.isVisible() : true);
311
+ }
312
+ };
313
+ //#endregion
314
+ export { Node as t };
315
+
316
+ //# sourceMappingURL=node-BZ7f6HzU.mjs.map