@zaly/tui 0.0.4 → 0.0.5

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 (154) hide show
  1. package/dist/actions-CnVzKVID.d.mts +41 -0
  2. package/dist/actions-CnVzKVID.d.mts.map +1 -0
  3. package/dist/actions-DEIKF2ts.mjs +48 -0
  4. package/dist/actions-DEIKF2ts.mjs.map +1 -0
  5. package/dist/{box-DyaByEiG.mjs → box-DepqUtuo.mjs} +2 -2
  6. package/dist/{box-DyaByEiG.mjs.map → box-DepqUtuo.mjs.map} +1 -1
  7. package/dist/{builder-D49ECBEf.mjs → builder-T9oGIWFa.mjs} +2 -2
  8. package/dist/{builder-D49ECBEf.mjs.map → builder-T9oGIWFa.mjs.map} +1 -1
  9. package/dist/{callbacks-CNjGNxVw.mjs → callbacks-DcMBGQEO.mjs} +2 -2
  10. package/dist/{callbacks-CNjGNxVw.mjs.map → callbacks-DcMBGQEO.mjs.map} +1 -1
  11. package/dist/{client-D6C_uczF.mjs → client-BBdtbLp4.mjs} +5 -10
  12. package/dist/client-BBdtbLp4.mjs.map +1 -0
  13. package/dist/client-cIckDgAj.mjs +2 -0
  14. package/dist/clipboard-l_TWxxTf.mjs +404 -0
  15. package/dist/clipboard-l_TWxxTf.mjs.map +1 -0
  16. package/dist/clipboard.mjs +1 -403
  17. package/dist/ctx-Ctmvof1N.mjs +43 -0
  18. package/dist/ctx-Ctmvof1N.mjs.map +1 -0
  19. package/dist/ctx-DhJIKuOX.mjs +2 -0
  20. package/dist/divider-cclEAdPx.mjs +9 -0
  21. package/dist/divider-cclEAdPx.mjs.map +1 -0
  22. package/dist/files-Aw3iWpXD.d.mts +29 -0
  23. package/dist/files-Aw3iWpXD.d.mts.map +1 -0
  24. package/dist/files-BvThQpOf.mjs +42 -0
  25. package/dist/files-BvThQpOf.mjs.map +1 -0
  26. package/dist/github-Cy2hfWJ7.mjs +137 -0
  27. package/dist/github-Cy2hfWJ7.mjs.map +1 -0
  28. package/dist/github-DS00VoOj.d.mts +64 -0
  29. package/dist/github-DS00VoOj.d.mts.map +1 -0
  30. package/dist/image-BTxDPPiT.d.mts +37 -0
  31. package/dist/image-BTxDPPiT.d.mts.map +1 -0
  32. package/dist/index.mjs +6 -202
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/input-CRBuTrsL.mjs +497 -0
  35. package/dist/input-CRBuTrsL.mjs.map +1 -0
  36. package/dist/{inspect-D1d9t-ni.mjs → inspect-BaKG6cU_.mjs} +2 -2
  37. package/dist/{inspect-D1d9t-ni.mjs.map → inspect-BaKG6cU_.mjs.map} +1 -1
  38. package/dist/log-DYHEYX_z.mjs +130 -0
  39. package/dist/log-DYHEYX_z.mjs.map +1 -0
  40. package/dist/logger-Ch0LwSG_.mjs +71 -0
  41. package/dist/logger-Ch0LwSG_.mjs.map +1 -0
  42. package/dist/markdown-CYHHoYu0.mjs +124 -0
  43. package/dist/markdown-CYHHoYu0.mjs.map +1 -0
  44. package/dist/markdown.mjs +1 -1
  45. package/dist/overlay-9xNgsuuy.mjs +18 -0
  46. package/dist/overlay-9xNgsuuy.mjs.map +1 -0
  47. package/dist/{picker-ndVVt6qF.mjs → picker-cH-rc7-X.mjs} +5 -5
  48. package/dist/{picker-ndVVt6qF.mjs.map → picker-cH-rc7-X.mjs.map} +1 -1
  49. package/dist/queries-B_lOwEiE.mjs +200 -0
  50. package/dist/queries-B_lOwEiE.mjs.map +1 -0
  51. package/dist/{registry-U654j61Y.mjs → registry-CdeLjUo2.mjs} +2 -4
  52. package/dist/registry-CdeLjUo2.mjs.map +1 -0
  53. package/dist/render-CPUD4yaW.mjs +33 -0
  54. package/dist/render-CPUD4yaW.mjs.map +1 -0
  55. package/dist/{renderer-CxL4xbkl.mjs → renderer-DJ1pWXSL.mjs} +8 -7
  56. package/dist/{renderer-CxL4xbkl.mjs.map → renderer-DJ1pWXSL.mjs.map} +1 -1
  57. package/dist/renderer-Dgj_qEOA.mjs +2 -0
  58. package/dist/{renderer-CdLCkJB-.mjs → renderer-qSMVeNSV.mjs} +3 -5
  59. package/dist/{renderer-CdLCkJB-.mjs.map → renderer-qSMVeNSV.mjs.map} +1 -1
  60. package/dist/select-m7NE6Rwa.mjs +195 -0
  61. package/dist/select-m7NE6Rwa.mjs.map +1 -0
  62. package/dist/services/logger.mjs +1 -70
  63. package/dist/services/notifier.mjs +2 -2
  64. package/dist/services/picker.d.mts +1 -1
  65. package/dist/services/picker.mjs +6 -6
  66. package/dist/services/prompt.d.mts +1 -1
  67. package/dist/services/prompt.mjs +5 -5
  68. package/dist/shiki/server.d.mts +1 -0
  69. package/dist/shiki/server.mjs +129 -0
  70. package/dist/shiki/server.mjs.map +1 -0
  71. package/dist/{shiki-BrjVUkeh.mjs → shiki-B5NwIiot.mjs} +5 -10
  72. package/dist/shiki-B5NwIiot.mjs.map +1 -0
  73. package/dist/shiki-BK-v9CtF.mjs +12 -0
  74. package/dist/shiki-BK-v9CtF.mjs.map +1 -0
  75. package/dist/show-DR2x1YFc.mjs +85 -0
  76. package/dist/show-DR2x1YFc.mjs.map +1 -0
  77. package/dist/style.mjs +2 -2
  78. package/dist/text-9lwQeqYr.d.mts +33 -0
  79. package/dist/text-9lwQeqYr.d.mts.map +1 -0
  80. package/dist/text-DILrol9j.mjs +32 -0
  81. package/dist/text-DILrol9j.mjs.map +1 -0
  82. package/dist/text-q26V6_Sc.mjs +111 -0
  83. package/dist/text-q26V6_Sc.mjs.map +1 -0
  84. package/dist/text.d.mts +2 -33
  85. package/dist/text.mjs +1 -110
  86. package/dist/themes.mjs +1 -1
  87. package/dist/tree-Bo1afYhe.mjs +73 -0
  88. package/dist/tree-Bo1afYhe.mjs.map +1 -0
  89. package/dist/widget-BkMwhY2p.mjs +40 -0
  90. package/dist/widget-BkMwhY2p.mjs.map +1 -0
  91. package/dist/widget-M7jD8Rgg.d.mts +49 -0
  92. package/dist/widget-M7jD8Rgg.d.mts.map +1 -0
  93. package/dist/widgets/autocomplete.mjs +2 -2
  94. package/dist/widgets/box.mjs +1 -1
  95. package/dist/widgets/code.mjs +7 -7
  96. package/dist/widgets/completions/actions.d.mts +2 -41
  97. package/dist/widgets/completions/actions.mjs +1 -47
  98. package/dist/widgets/completions/files.d.mts +2 -29
  99. package/dist/widgets/completions/files.mjs +1 -41
  100. package/dist/widgets/completions/github.d.mts +2 -64
  101. package/dist/widgets/completions/github.mjs +1 -136
  102. package/dist/widgets/completions/index.d.mts +3 -3
  103. package/dist/widgets/completions/index.mjs +3 -3
  104. package/dist/widgets/diff.d.mts +1 -1
  105. package/dist/widgets/diff.mjs +3 -3
  106. package/dist/widgets/divider.mjs +1 -8
  107. package/dist/widgets/image.d.mts +2 -37
  108. package/dist/widgets/image.mjs +1 -1
  109. package/dist/widgets/input.mjs +1 -496
  110. package/dist/widgets/log.mjs +1 -129
  111. package/dist/widgets/markdown.d.mts +2 -2
  112. package/dist/widgets/markdown.mjs +1 -123
  113. package/dist/widgets/overlay.mjs +1 -17
  114. package/dist/widgets/picker.mjs +1 -1
  115. package/dist/widgets/select.mjs +1 -194
  116. package/dist/widgets/show.mjs +1 -84
  117. package/dist/widgets/text.mjs +1 -31
  118. package/dist/widgets/tree.mjs +1 -72
  119. package/dist/widgets/widget.d.mts +2 -49
  120. package/dist/widgets/widget.mjs +1 -39
  121. package/dist/worker-BvRm4OsW.mjs +2 -0
  122. package/dist/worker-T6SdPzUH.mjs +52 -0
  123. package/dist/worker-T6SdPzUH.mjs.map +1 -0
  124. package/package.json +5 -1
  125. package/dist/client-D6C_uczF.mjs.map +0 -1
  126. package/dist/clipboard.mjs.map +0 -1
  127. package/dist/registry-U654j61Y.mjs.map +0 -1
  128. package/dist/render-DxVLqqB9.mjs +0 -74
  129. package/dist/render-DxVLqqB9.mjs.map +0 -1
  130. package/dist/rolldown-runtime-D7D4PA-g.mjs +0 -13
  131. package/dist/services/logger.mjs.map +0 -1
  132. package/dist/shiki-BrjVUkeh.mjs.map +0 -1
  133. package/dist/text.d.mts.map +0 -1
  134. package/dist/text.mjs.map +0 -1
  135. package/dist/widgets/completions/actions.d.mts.map +0 -1
  136. package/dist/widgets/completions/actions.mjs.map +0 -1
  137. package/dist/widgets/completions/files.d.mts.map +0 -1
  138. package/dist/widgets/completions/files.mjs.map +0 -1
  139. package/dist/widgets/completions/github.d.mts.map +0 -1
  140. package/dist/widgets/completions/github.mjs.map +0 -1
  141. package/dist/widgets/divider.mjs.map +0 -1
  142. package/dist/widgets/image.d.mts.map +0 -1
  143. package/dist/widgets/input.mjs.map +0 -1
  144. package/dist/widgets/log.mjs.map +0 -1
  145. package/dist/widgets/markdown.mjs.map +0 -1
  146. package/dist/widgets/overlay.mjs.map +0 -1
  147. package/dist/widgets/select.mjs.map +0 -1
  148. package/dist/widgets/show.mjs.map +0 -1
  149. package/dist/widgets/text.mjs.map +0 -1
  150. package/dist/widgets/tree.mjs.map +0 -1
  151. package/dist/widgets/widget.d.mts.map +0 -1
  152. package/dist/widgets/widget.mjs.map +0 -1
  153. package/dist/worker-DjHuQSbY.mjs +0 -27
  154. package/dist/worker-DjHuQSbY.mjs.map +0 -1
@@ -1,404 +1,2 @@
1
- import { safeStat } from "@zaly/shared";
2
- import { isSSH } from "@zaly/shared/env";
3
- import { mkdtempSync, writeFileSync } from "node:fs";
4
- import { join } from "pathe";
5
- import { Spawn, spawnText, spawnWithInput, which } from "@zaly/shared/process";
6
- import { tmpdir } from "node:os";
7
- import { platform } from "node:process";
8
- //#region src/input/clipboard.ts
9
- let cached;
10
- let cacheResolved = false;
11
- /** Detect + cache the clipboard provider for this process. Returns
12
- * `undefined` when no provider is available. */
13
- function getClipboard() {
14
- if (cacheResolved) return cached;
15
- cached = detect();
16
- cacheResolved = true;
17
- return cached;
18
- }
19
- async function readClipboard(kind) {
20
- const p = getClipboard();
21
- if (!p) return void 0;
22
- try {
23
- return await p.read(kind);
24
- } catch {
25
- return;
26
- }
27
- }
28
- /** Reset the cached provider — mostly for tests that want to force a
29
- * re-probe. Also useful if the environment changes (e.g. Wayland
30
- * display started after process boot). */
31
- function resetClipboardCache() {
32
- cached = void 0;
33
- cacheResolved = false;
34
- }
35
- /**
36
- * Copy text to the system clipboard.
37
- *
38
- * Policy:
39
- * - **SSH session** → always OSC 52. Native tools on the remote box
40
- * would write to the remote clipboard, which isn't what the user
41
- * wants. OSC 52 routes through the local terminal.
42
- * - **Native tool available** → use it (fast, silent, no prompts).
43
- * - **Neither** → OSC 52 anyway, fire-and-forget.
44
- *
45
- * Resolves to `true` on best-effort delivery; `false` only when we had
46
- * nothing to try. OSC 52 writes are silent by design — the terminal
47
- * never confirms receipt — so `true` means "we emitted" not "the
48
- * user's clipboard definitely has it".
49
- */
50
- async function writeClipboardText(text) {
51
- if (isSSH) {
52
- writeOsc52(text);
53
- return true;
54
- }
55
- const p = getClipboard();
56
- if (p?.writeText) try {
57
- if (await p.writeText(text)) return true;
58
- } catch {}
59
- writeOsc52(text);
60
- return true;
61
- }
62
- /**
63
- * Namespace export for readable call sites:
64
- *
65
- * ```ts
66
- * import { clipboard } from "@zaly/tui"
67
- *
68
- * await clipboard.read()
69
- * await clipboard.read("text")
70
- * await clipboard.write("hello")
71
- * clipboard.reset()
72
- * ```
73
- */
74
- const clipboard = {
75
- read: readClipboard,
76
- reset: resetClipboardCache,
77
- write: writeClipboardText
78
- };
79
- /** Emit an OSC 52 clipboard write. Fire-and-forget; some terminals
80
- * ignore or prompt on this, and there's no response channel. */
81
- function writeOsc52(text) {
82
- const b64 = Buffer.from(text, "utf8").toString("base64");
83
- process.stdout.write(`\x1b]52;c;${b64}\x07`);
84
- }
85
- function detect() {
86
- if (platform === "darwin" && which("pbpaste")) return macos();
87
- if (process.env.WAYLAND_DISPLAY && which("wl-paste")) return wayland();
88
- if (process.env.DISPLAY) {
89
- if (which("xsel")) return xsel();
90
- if (which("xclip")) return xclip();
91
- }
92
- if (which("win32yank.exe")) return wsl();
93
- if (platform === "win32") return windows();
94
- }
95
- function macos() {
96
- return {
97
- id: "pbpaste",
98
- read: async (kind) => {
99
- if (kind === "image") return macosImage();
100
- if (kind === "files") return macosFiles();
101
- if (kind === "text") return macosText();
102
- const img = await macosImage();
103
- if (img) return img;
104
- const files = await macosFiles();
105
- if (files) return files;
106
- return macosText();
107
- },
108
- writeText: (text) => spawnWithInput("pbcopy", [], text)
109
- };
110
- }
111
- async function macosText() {
112
- const text = await spawnText("pbpaste", []);
113
- return text === void 0 ? void 0 : {
114
- kind: "text",
115
- text
116
- };
117
- }
118
- async function macosImage() {
119
- const out = await spawnText("osascript", ["-e", `
120
- try
121
- set png to (the clipboard as «class PNGf»)
122
- set b64 to do shell script "base64" with input (png as string)
123
- return b64
124
- on error
125
- return ""
126
- end try
127
- `]);
128
- if (!out) return void 0;
129
- return writeTempPng(Buffer.from(out.trim(), "base64"));
130
- }
131
- async function macosFiles() {
132
- const out = await spawnText("osascript", ["-e", `
133
- try
134
- set theClipboard to the clipboard as «class furl»
135
- return POSIX path of theClipboard
136
- on error
137
- try
138
- set theList to the clipboard as list
139
- set posix to ""
140
- repeat with item_ in theList
141
- try
142
- set posix to posix & (POSIX path of item_) & linefeed
143
- end try
144
- end repeat
145
- return posix
146
- on error
147
- return ""
148
- end try
149
- end try
150
- `]);
151
- if (!out) return void 0;
152
- const paths = out.split(/\r?\n/).map((s) => s.trim()).filter((s) => s !== "");
153
- return paths.length > 0 ? {
154
- kind: "files",
155
- paths
156
- } : void 0;
157
- }
158
- function wayland() {
159
- return {
160
- id: "wl-paste",
161
- read: async (kind) => {
162
- if (kind === "image") return waylandImage();
163
- if (kind === "files") return waylandFiles();
164
- if (kind === "text") return waylandText();
165
- const types = await spawnText("wl-paste", ["--list-types"]);
166
- if (!types) return void 0;
167
- if (/\bimage\/png\b/.test(types)) {
168
- const img = await waylandImage();
169
- if (img) return img;
170
- }
171
- if (/\btext\/uri-list\b/.test(types)) {
172
- const files = await waylandFiles();
173
- if (files) return files;
174
- }
175
- return waylandText();
176
- },
177
- writeText: (text) => spawnWithInput("wl-copy", ["--type", "text/plain"], text)
178
- };
179
- }
180
- async function waylandImage() {
181
- const r = await new Spawn("wl-paste", ["--type", "image/png"]).result;
182
- return r.code === 0 && r.stdout.length > 0 ? writeTempPng(r.stdout) : void 0;
183
- }
184
- async function waylandFiles() {
185
- const paths = parseUriList(await spawnText("wl-paste", ["--type", "text/uri-list"]));
186
- return paths.length > 0 ? {
187
- kind: "files",
188
- paths
189
- } : void 0;
190
- }
191
- async function waylandText() {
192
- const text = await spawnText("wl-paste", ["--no-newline"]);
193
- return text === void 0 ? void 0 : {
194
- kind: "text",
195
- text
196
- };
197
- }
198
- function xsel() {
199
- const xclipFallback = which("xclip");
200
- return {
201
- id: xclipFallback ? "xsel+xclip" : "xsel",
202
- read: async (kind) => {
203
- if (kind === "text") return xselText();
204
- if (xclipFallback) {
205
- if (kind === "image") return xclipImage();
206
- if (kind === "files") return xclipFiles();
207
- const rich = await xclipRead();
208
- if (rich && rich.kind !== "text") return rich;
209
- }
210
- return xselText();
211
- },
212
- writeText: (text) => spawnWithInput("xsel", [
213
- "--nodetach",
214
- "-i",
215
- "-b"
216
- ], text)
217
- };
218
- }
219
- function xclip() {
220
- return {
221
- id: "xclip",
222
- read: (kind) => {
223
- if (kind === "image") return xclipImage();
224
- if (kind === "files") return xclipFiles();
225
- if (kind === "text") return xclipText();
226
- return xclipRead();
227
- },
228
- writeText: (text) => spawnWithInput("xclip", [
229
- "-quiet",
230
- "-i",
231
- "-selection",
232
- "clipboard"
233
- ], text)
234
- };
235
- }
236
- async function xclipRead() {
237
- const targets = await spawnText("xclip", [
238
- "-selection",
239
- "clipboard",
240
- "-t",
241
- "TARGETS",
242
- "-o"
243
- ]);
244
- if (!targets) return void 0;
245
- if (/\bimage\/png\b/.test(targets)) {
246
- const img = await xclipImage();
247
- if (img) return img;
248
- }
249
- if (/\btext\/uri-list\b/.test(targets)) {
250
- const files = await xclipFiles();
251
- if (files) return files;
252
- }
253
- return xclipText();
254
- }
255
- async function xclipImage() {
256
- const r = await new Spawn("xclip", [
257
- "-selection",
258
- "clipboard",
259
- "-t",
260
- "image/png",
261
- "-o"
262
- ]).result;
263
- return r.code === 0 && r.stdout.length > 0 ? writeTempPng(r.stdout) : void 0;
264
- }
265
- async function xclipFiles() {
266
- const paths = parseUriList(await spawnText("xclip", [
267
- "-selection",
268
- "clipboard",
269
- "-t",
270
- "text/uri-list",
271
- "-o"
272
- ]));
273
- return paths.length > 0 ? {
274
- kind: "files",
275
- paths
276
- } : void 0;
277
- }
278
- async function xclipText() {
279
- const text = await spawnText("xclip", [
280
- "-o",
281
- "-selection",
282
- "clipboard"
283
- ]);
284
- return text === void 0 ? void 0 : {
285
- kind: "text",
286
- text
287
- };
288
- }
289
- async function xselText() {
290
- const text = await spawnText("xsel", ["-o", "-b"]);
291
- return text === void 0 ? void 0 : {
292
- kind: "text",
293
- text
294
- };
295
- }
296
- function wsl() {
297
- return {
298
- id: "win32yank",
299
- read: async (kind) => {
300
- if (kind === "image" || kind === "files") return void 0;
301
- const text = await spawnText("win32yank.exe", ["-o", "--lf"]);
302
- return text === void 0 ? void 0 : {
303
- kind: "text",
304
- text
305
- };
306
- },
307
- writeText: (text) => spawnWithInput("win32yank.exe", ["-i", "--crlf"], text)
308
- };
309
- }
310
- function windows() {
311
- return {
312
- id: "powershell",
313
- read: async (kind) => {
314
- if (kind === "image") return windowsImage();
315
- if (kind === "files") return windowsFiles();
316
- if (kind === "text") return windowsText();
317
- const img = await windowsImage();
318
- if (img) return img;
319
- const files = await windowsFiles();
320
- if (files) return files;
321
- return windowsText();
322
- },
323
- writeText: (text) => spawnWithInput("clip", [], text)
324
- };
325
- }
326
- async function windowsText() {
327
- const text = await spawnText("powershell", [
328
- "-NoProfile",
329
- "-NoLogo",
330
- "-Command",
331
- "Get-Clipboard"
332
- ]);
333
- return text === void 0 ? void 0 : {
334
- kind: "text",
335
- text
336
- };
337
- }
338
- async function windowsImage() {
339
- const tmp = writeTempPath("zaly-clip-", ".png");
340
- await spawnText("powershell", [
341
- "-NoProfile",
342
- "-NoLogo",
343
- "-Command",
344
- [
345
- "Add-Type -AssemblyName System.Windows.Forms",
346
- "$img = [System.Windows.Forms.Clipboard]::GetImage()",
347
- `if ($img) { $img.Save('${tmp.replace(/\\/g, String.raw`\\`)}') }`
348
- ].join("; ")
349
- ]);
350
- if ((safeStat(tmp)?.size ?? 0) > 0) return {
351
- kind: "image",
352
- path: tmp,
353
- type: "image/png"
354
- };
355
- }
356
- async function windowsFiles() {
357
- const out = await spawnText("powershell", [
358
- "-NoProfile",
359
- "-NoLogo",
360
- "-Command",
361
- "Get-Clipboard -Format FileDropList | ForEach-Object { $_.FullName }"
362
- ]);
363
- if (!out) return void 0;
364
- const paths = out.split(/\r?\n/).map((s) => s.trim()).filter((s) => s !== "");
365
- return paths.length > 0 ? {
366
- kind: "files",
367
- paths
368
- } : void 0;
369
- }
370
- function writeTempPng(bytes) {
371
- const path = writeTempPath("zaly-clip-", ".png");
372
- writeFileSync(path, bytes);
373
- return {
374
- kind: "image",
375
- path,
376
- type: "image/png"
377
- };
378
- }
379
- /** Parse a `text/uri-list` blob (RFC 2483): `file://…\r\n` lines, skip
380
- * blanks and comment lines (`#…`), decode percent-encoding. Returns
381
- * absolute filesystem paths. Non-`file://` URIs are dropped — we
382
- * can't hand a remote URL off as an attachment path. */
383
- function parseUriList(raw) {
384
- if (!raw) return [];
385
- const out = [];
386
- for (const line of raw.split(/\r?\n/)) {
387
- const s = line.trim();
388
- if (s === "" || s.startsWith("#")) continue;
389
- if (!s.startsWith("file://")) continue;
390
- try {
391
- let path = decodeURIComponent(s.slice(7));
392
- if (/^\/[A-Za-z]:\//.test(path)) path = path.slice(1);
393
- out.push(path);
394
- } catch {}
395
- }
396
- return out;
397
- }
398
- function writeTempPath(prefix, ext) {
399
- return join(mkdtempSync(join(tmpdir(), prefix)), `clip${ext}`);
400
- }
401
- //#endregion
1
+ import { t as clipboard } from "./clipboard-l_TWxxTf.mjs";
402
2
  export { clipboard };
403
-
404
- //# sourceMappingURL=clipboard.mjs.map
@@ -0,0 +1,43 @@
1
+ import { t as defaultTheme } from "./registry-CdeLjUo2.mjs";
2
+ import { t as styleBuilder } from "./builder-T9oGIWFa.mjs";
3
+ //#region src/core/ctx.ts
4
+ /**
5
+ * Current terminal width in cells. Returns `undefined` when stdout isn't a
6
+ * TTY (piped output, tests, non-Node/Bun runtimes) — callers should fall
7
+ * back to a sensible default when this is `undefined`.
8
+ *
9
+ * @internal
10
+ */
11
+ function termWidth() {
12
+ if (typeof process === "undefined") return void 0;
13
+ const cols = process.stdout.columns;
14
+ return typeof cols === "number" && cols > 0 ? cols : void 0;
15
+ }
16
+ /**
17
+ * Build a fresh `RenderCtx` from a resolved theme + width. Binds a `style`
18
+ * builder to the theme so components can use `ctx.style.primary(...)`
19
+ * without constructing their own.
20
+ *
21
+ * Width is clamped to the terminal's current column count (falling back to
22
+ * 80 when stdout isn't a TTY). No width passed → terminal width is used
23
+ * directly; an explicit `width` wider than the terminal is capped so
24
+ * components never produce rows that wrap the display. Narrower explicit
25
+ * widths (e.g. for fixed-layout tests) pass through unchanged.
26
+ *
27
+ * Dynamic theme loading (from a string name) lives in `themes/loadTheme`
28
+ * — resolve the name first, then pass the `Theme` object here.
29
+ */
30
+ function createCtx(opts = {}) {
31
+ const tw = termWidth() ?? 80;
32
+ return {
33
+ style: opts.style ?? styleBuilder(opts.theme ?? defaultTheme),
34
+ transmit: (data) => process.stdout.write(data),
35
+ version: opts.version ?? 0,
36
+ width: Math.min(opts.width ?? tw, tw),
37
+ ...opts
38
+ };
39
+ }
40
+ //#endregion
41
+ export { createCtx as t };
42
+
43
+ //# sourceMappingURL=ctx-Ctmvof1N.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ctx-Ctmvof1N.mjs","names":[],"sources":["../src/core/ctx.ts"],"sourcesContent":["import type { Emitter } from \"@zaly/shared\"\nimport type { Logger } from \"@zaly/shared/logger\"\nimport type { Actions } from \"../input/actions.ts\"\nimport type { TerminalQueries } from \"../input/queries.ts\"\nimport type { InputRouterEvents } from \"../input/router.ts\"\nimport type { SurfaceType } from \"../renderer/renderer.ts\"\nimport type { StyleBuilder } from \"../style/builder.ts\"\nimport type { Theme } from \"../themes/types.ts\"\nimport type { Overlay } from \"../widgets/overlay.ts\"\nimport type { Node } from \"./node.ts\"\n\nimport { styleBuilder } from \"../style/builder.ts\"\nimport { defaultTheme } from \"../themes/registry.ts\"\n\n/**\n * Passed to every `render(ctx)` call. Width flows in; height emerges from\n * the returned row count. Theme is ambient — children share the parent's.\n *\n * `style` is a theme-bound chainable builder made available to components so\n * they can produce inline-styled strings without re-binding the theme.\n *\n * `version` is a monotonic cache-key bumped by the `Renderer` whenever any\n * identity-relevant ctx field changes (resize, theme swap). Node caches\n * compare this integer — no hashing, no string keys.\n */\nexport interface RenderCtx {\n width: number\n style: StyleBuilder\n version: number\n /** Queue a side-channel ANSI payload (e.g. KGP image transmit) for\n * the renderer to flush before the next paint. Use this to keep\n * side-effecting bytes out of cached row strings — what `_render`\n * returns should be safe to reuse across paints, and transmit\n * bytes shouldn't be. */\n readonly transmit: (seq: string) => void\n}\n\n/**\n * Context handed to a node when it mounts onto a surface. Gives widget\n * authors a scoped handle to the services they legitimately need —\n * focus, overlays, tree lookups, out-of-band repaints — without\n * exposing the full Renderer.\n *\n * MountCtx is *per-lifetime*: set once when `mount()` is called and\n * cleared on `unmount()`. Distinct from `RenderCtx` (per-tick, carries\n * width/theme/version). If a node moves between surfaces, it receives\n * a fresh MountCtx via the subsequent `mount()` call.\n */\nexport interface MountCtx {\n /** Which surface owns this subtree. */\n readonly surface: SurfaceType\n\n /** Overlay capabilities — open/close an Overlay node from inside a\n * widget (e.g. a confirm dialog, autocomplete popover, tooltip). */\n readonly overlay: {\n readonly add: (o: () => Overlay) => void\n readonly remove: (o: Overlay) => void\n }\n\n /** Input capabilities — a narrow slice of the router. We deliberately\n * don't expose the full `InputRouter`: `setKeymap` / `dispatch` are\n * app-level concerns. Widgets legitimately need to install direct\n * global key bindings (autocomplete) and move focus. */\n readonly input: {\n readonly terminalFocus: boolean\n readonly events: Emitter<InputRouterEvents>\n readonly bind: Actions[\"bind\"]\n /** Move focus to `node`. Mirrors `router.focus(node)`. */\n readonly focus: (node: Node) => void\n /** Clear focus. */\n readonly blur: (node: Node) => void\n readonly queries: TerminalQueries\n }\n\n /** Action registry — widgets and plugins can `register` catalog\n * entries (with desc + default keys + optional `fn`) and `dispatch`\n * actions by id. The Router feeds key-triggered dispatches through\n * here; programmatic callers do the same. */\n readonly actions: Actions\n\n /** Look up a node anywhere in the tree by its `id`. First match\n * wins; `undefined` when nothing matches. Same semantics as\n * `Renderer.getNode`. */\n readonly getNode: (id: string) => Node | undefined\n /** Find every node matching a predicate. Strings match `node.type`;\n * pass a function for richer predicates. Same semantics as\n * `Renderer.findNode`. */\n readonly findNode: (match: string | ((n: Node) => boolean)) => Node[]\n\n logger: Logger\n}\n\n/**\n * Current terminal width in cells. Returns `undefined` when stdout isn't a\n * TTY (piped output, tests, non-Node/Bun runtimes) — callers should fall\n * back to a sensible default when this is `undefined`.\n *\n * @internal\n */\nfunction termWidth(): number | undefined {\n if (typeof process === \"undefined\") return undefined\n const cols = process.stdout.columns\n return typeof cols === \"number\" && cols > 0 ? cols : undefined\n}\n\n/**\n * Build a fresh `RenderCtx` from a resolved theme + width. Binds a `style`\n * builder to the theme so components can use `ctx.style.primary(...)`\n * without constructing their own.\n *\n * Width is clamped to the terminal's current column count (falling back to\n * 80 when stdout isn't a TTY). No width passed → terminal width is used\n * directly; an explicit `width` wider than the terminal is capped so\n * components never produce rows that wrap the display. Narrower explicit\n * widths (e.g. for fixed-layout tests) pass through unchanged.\n *\n * Dynamic theme loading (from a string name) lives in `themes/loadTheme`\n * — resolve the name first, then pass the `Theme` object here.\n */\nexport function createCtx(opts: Partial<RenderCtx> & { theme?: Theme } = {}): RenderCtx {\n const tw = termWidth() ?? 80\n return {\n style: opts.style ?? styleBuilder(opts.theme ?? defaultTheme),\n transmit: (data) => process.stdout.write(data),\n version: opts.version ?? 0,\n width: Math.min(opts.width ?? tw, tw),\n ...opts,\n }\n}\n"],"mappings":";;;;;;;;;;AAmGA,SAAS,YAAgC;CACvC,IAAI,OAAO,YAAY,aAAa,OAAO,KAAA;CAC3C,MAAM,OAAO,QAAQ,OAAO;CAC5B,OAAO,OAAO,SAAS,YAAY,OAAO,IAAI,OAAO,KAAA;AACvD;;;;;;;;;;;;;;;AAgBA,SAAgB,UAAU,OAA+C,CAAC,GAAc;CACtF,MAAM,KAAK,UAAU,KAAK;CAC1B,OAAO;EACL,OAAO,KAAK,SAAS,aAAa,KAAK,SAAS,YAAY;EAC5D,WAAW,SAAS,QAAQ,OAAO,MAAM,IAAI;EAC7C,SAAS,KAAK,WAAW;EACzB,OAAO,KAAK,IAAI,KAAK,SAAS,IAAI,EAAE;EACpC,GAAG;CACL;AACF"}
@@ -0,0 +1,2 @@
1
+ import { t as createCtx } from "./ctx-Ctmvof1N.mjs";
2
+ export { createCtx };
@@ -0,0 +1,9 @@
1
+ import { n as text } from "./text-DILrol9j.mjs";
2
+ //#region src/widgets/divider.ts
3
+ function divider(state = { style: "divider" }) {
4
+ return text((ctx) => (state.char ?? "─").repeat(state.length ?? ctx.width), state);
5
+ }
6
+ //#endregion
7
+ export { divider as t };
8
+
9
+ //# sourceMappingURL=divider-cclEAdPx.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"divider-cclEAdPx.mjs","names":[],"sources":["../src/widgets/divider.ts"],"sourcesContent":["import type { Style } from \"../style/types.ts\"\nimport type { Text } from \"./text.ts\"\n\nimport { text } from \"./text.ts\"\n\nexport type DividerState = Style & {\n char?: string\n length?: number\n}\n\nexport function divider(state: DividerState = { style: \"divider\" }): Text {\n return text((ctx) => (state.char ?? \"─\").repeat(state.length ?? ctx.width), state)\n}\n"],"mappings":";;AAUA,SAAgB,QAAQ,QAAsB,EAAE,OAAO,UAAU,GAAS;CACxE,OAAO,MAAM,SAAS,MAAM,QAAQ,IAAA,CAAK,OAAO,MAAM,UAAU,IAAI,KAAK,GAAG,KAAK;AACnF"}
@@ -0,0 +1,29 @@
1
+ import { n as PickerItem } from "./picker-D8OLb6kZ.mjs";
2
+ import { o as CompletionSource } from "./autocomplete-Dfw-yQDa.mjs";
3
+ import { FindOptions } from "@zaly/shared/find";
4
+ //#region src/widgets/completions/files.d.ts
5
+ interface FilesSourceOptions extends FindOptions {
6
+ /** Base directory relative queries resolve against. Default:
7
+ * `process.cwd()`. */
8
+ cwd?: string;
9
+ /** Trigger regex. Default: `/(?<=^|\s)@/` — `@` preceded by start-of-
10
+ * string or whitespace. Lookbehind keeps `match.start` on the `@`
11
+ * itself so the leading space isn't eaten on insertion. */
12
+ trigger?: RegExp;
13
+ /** Prefix prepended to accepted values so the trigger character stays
14
+ * in the input after a pick (letting users keep typing to drill into
15
+ * subdirectories). Default: `"@"` — matches the default trigger.
16
+ * When customizing `trigger`, set this to the character your trigger
17
+ * represents. */
18
+ prefix?: string;
19
+ refreshInterval?: number;
20
+ }
21
+ type File = PickerItem & {
22
+ file: string;
23
+ };
24
+ /** Completion source for files. Uses `@zaly/shared/find` under the hood, so
25
+ * supports all the same options and respects .gitignore by default. */
26
+ declare function filesSource(opts?: FilesSourceOptions): CompletionSource<File>;
27
+ //#endregion
28
+ export { filesSource as n, FilesSourceOptions as t };
29
+ //# sourceMappingURL=files-Aw3iWpXD.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files-Aw3iWpXD.d.mts","names":[],"sources":["../src/widgets/completions/files.ts"],"mappings":";;;;UAQiB,2BAA2B;;;EAG1C;;;;EAIA,UAAU;;;;;;EAMV;EACA;;KAGG,OAAO;EAAe;;;;iBAIX,YAAY,OAAM,qBAA0B,iBAAiB"}
@@ -0,0 +1,42 @@
1
+ import { a as createIterable, y as signal } from "./reactive-f7NpAi69.mjs";
2
+ import { normPath } from "@zaly/shared";
3
+ //#region src/widgets/completions/files.ts
4
+ /** Completion source for files. Uses `@zaly/shared/find` under the hood, so
5
+ * supports all the same options and respects .gitignore by default. */
6
+ function filesSource(opts = {}) {
7
+ const cwd = normPath(opts.cwd);
8
+ const trigger = opts.trigger ?? /(?<=^|\s)@/;
9
+ const prefix = opts.prefix ?? "@";
10
+ let results;
11
+ const [gen, setGen] = signal(0);
12
+ let lastRefresh = 0;
13
+ return {
14
+ accept: (item) => {
15
+ const v = item.file;
16
+ return `${prefix}${v}${v.endsWith("/") ? "" : " "}`;
17
+ },
18
+ get complete() {
19
+ const now = performance.now();
20
+ if (!results?.loading() && now - lastRefresh > (opts.refreshInterval ?? 1e4)) {
21
+ setGen((g) => g + 1);
22
+ lastRefresh = now;
23
+ }
24
+ return results ??= createIterable(async function* iterFiles() {
25
+ gen();
26
+ const { find } = await import("@zaly/shared/find");
27
+ for await (const f of find({
28
+ ...opts,
29
+ cwd
30
+ })) yield (Array.isArray(f) ? f : [f]).map((file) => ({
31
+ file,
32
+ text: file
33
+ }));
34
+ });
35
+ },
36
+ triggers: [trigger]
37
+ };
38
+ }
39
+ //#endregion
40
+ export { filesSource as t };
41
+
42
+ //# sourceMappingURL=files-BvThQpOf.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files-BvThQpOf.mjs","names":[],"sources":["../src/widgets/completions/files.ts"],"sourcesContent":["import type { FindOptions } from \"@zaly/shared/find\"\nimport type { Progressive } from \"../../core/reactive.ts\"\nimport type { CompletionSource } from \"../autocomplete.ts\"\nimport type { PickerItem } from \"../picker.ts\"\n\nimport { normPath } from \"@zaly/shared\"\nimport { createIterable, signal } from \"../../core/reactive.ts\"\n\nexport interface FilesSourceOptions extends FindOptions {\n /** Base directory relative queries resolve against. Default:\n * `process.cwd()`. */\n cwd?: string\n /** Trigger regex. Default: `/(?<=^|\\s)@/` — `@` preceded by start-of-\n * string or whitespace. Lookbehind keeps `match.start` on the `@`\n * itself so the leading space isn't eaten on insertion. */\n trigger?: RegExp\n /** Prefix prepended to accepted values so the trigger character stays\n * in the input after a pick (letting users keep typing to drill into\n * subdirectories). Default: `\"@\"` — matches the default trigger.\n * When customizing `trigger`, set this to the character your trigger\n * represents. */\n prefix?: string\n refreshInterval?: number\n}\n\ntype File = PickerItem & { file: string }\n\n/** Completion source for files. Uses `@zaly/shared/find` under the hood, so\n * supports all the same options and respects .gitignore by default. */\nexport function filesSource(opts: FilesSourceOptions = {}): CompletionSource<File> {\n const cwd = normPath(opts.cwd)\n const trigger = opts.trigger ?? /(?<=^|\\s)@/\n const prefix = opts.prefix ?? \"@\"\n let results: Progressive<readonly File[]> | undefined\n const [gen, setGen] = signal(0)\n let lastRefresh = 0\n return {\n accept: (item) => {\n // Dirs keep the popup open (trigger still matches, user can\n // drill in). Files close it — a trailing space makes `#detect`\n // see whitespace in the query and bail.\n const v = item.file\n return `${prefix}${v}${v.endsWith(\"/\") ? \"\" : \" \"}`\n },\n get complete() {\n const now = performance.now()\n if (!results?.loading() && now - lastRefresh > (opts.refreshInterval ?? 10_000)) {\n setGen((g) => g + 1) // Refresh results\n lastRefresh = now\n }\n return (results ??= createIterable<File>(async function* iterFiles() {\n gen() // Re-run when `gen` changes\n const { find } = await import(\"@zaly/shared/find\")\n for await (const f of find({ ...opts, cwd })) {\n const ff = Array.isArray(f) ? f : [f]\n yield ff.map((file) => ({ file, text: file }))\n }\n }))\n },\n triggers: [trigger],\n }\n}\n"],"mappings":";;;;;AA6BA,SAAgB,YAAY,OAA2B,CAAC,GAA2B;CACjF,MAAM,MAAM,SAAS,KAAK,GAAG;CAC7B,MAAM,UAAU,KAAK,WAAW;CAChC,MAAM,SAAS,KAAK,UAAU;CAC9B,IAAI;CACJ,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC;CAC9B,IAAI,cAAc;CAClB,OAAO;EACL,SAAS,SAAS;GAIhB,MAAM,IAAI,KAAK;GACf,OAAO,GAAG,SAAS,IAAI,EAAE,SAAS,GAAG,IAAI,KAAK;EAChD;EACA,IAAI,WAAW;GACb,MAAM,MAAM,YAAY,IAAI;GAC5B,IAAI,CAAC,SAAS,QAAQ,KAAK,MAAM,eAAe,KAAK,mBAAmB,MAAS;IAC/E,QAAQ,MAAM,IAAI,CAAC;IACnB,cAAc;GAChB;GACA,OAAQ,YAAY,eAAqB,gBAAgB,YAAY;IACnE,IAAI;IACJ,MAAM,EAAE,SAAS,MAAM,OAAO;IAC9B,WAAW,MAAM,KAAK,KAAK;KAAE,GAAG;KAAM;IAAI,CAAC,GAEzC,OADW,MAAM,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAC,EAAA,CAC3B,KAAK,UAAU;KAAE;KAAM,MAAM;IAAK,EAAE;GAEjD,CAAC;EACH;EACA,UAAU,CAAC,OAAO;CACpB;AACF"}