@zaly/tui 0.0.4 → 0.0.6
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-CnVzKVID.d.mts +41 -0
- package/dist/actions-CnVzKVID.d.mts.map +1 -0
- package/dist/actions-DEIKF2ts.mjs +48 -0
- package/dist/actions-DEIKF2ts.mjs.map +1 -0
- package/dist/{box-DyaByEiG.mjs → box-DepqUtuo.mjs} +2 -2
- package/dist/{box-DyaByEiG.mjs.map → box-DepqUtuo.mjs.map} +1 -1
- package/dist/{builder-D49ECBEf.mjs → builder-DTz5mppV.mjs} +2 -2
- package/dist/{builder-D49ECBEf.mjs.map → builder-DTz5mppV.mjs.map} +1 -1
- package/dist/{callbacks-CNjGNxVw.mjs → callbacks-DcMBGQEO.mjs} +2 -2
- package/dist/{callbacks-CNjGNxVw.mjs.map → callbacks-DcMBGQEO.mjs.map} +1 -1
- package/dist/{client-D6C_uczF.mjs → client-BBdtbLp4.mjs} +5 -10
- package/dist/client-BBdtbLp4.mjs.map +1 -0
- package/dist/client-cIckDgAj.mjs +2 -0
- package/dist/clipboard-l_TWxxTf.mjs +404 -0
- package/dist/clipboard-l_TWxxTf.mjs.map +1 -0
- package/dist/clipboard.mjs +1 -403
- package/dist/ctx-Bt4VlRPg.mjs +2 -0
- package/dist/ctx-DjJ1zSbs.mjs +43 -0
- package/dist/ctx-DjJ1zSbs.mjs.map +1 -0
- package/dist/divider-cclEAdPx.mjs +9 -0
- package/dist/divider-cclEAdPx.mjs.map +1 -0
- package/dist/files-Aw3iWpXD.d.mts +29 -0
- package/dist/files-Aw3iWpXD.d.mts.map +1 -0
- package/dist/files-BvThQpOf.mjs +42 -0
- package/dist/files-BvThQpOf.mjs.map +1 -0
- package/dist/github-Cy2hfWJ7.mjs +137 -0
- package/dist/github-Cy2hfWJ7.mjs.map +1 -0
- package/dist/github-DS00VoOj.d.mts +64 -0
- package/dist/github-DS00VoOj.d.mts.map +1 -0
- package/dist/image-BTxDPPiT.d.mts +37 -0
- package/dist/image-BTxDPPiT.d.mts.map +1 -0
- package/dist/index.mjs +6 -202
- package/dist/index.mjs.map +1 -1
- package/dist/input-CRBuTrsL.mjs +497 -0
- package/dist/input-CRBuTrsL.mjs.map +1 -0
- package/dist/{inspect-D1d9t-ni.mjs → inspect-DE5goDzB.mjs} +2 -2
- package/dist/{inspect-D1d9t-ni.mjs.map → inspect-DE5goDzB.mjs.map} +1 -1
- package/dist/log-Djvrxqk0.mjs +130 -0
- package/dist/log-Djvrxqk0.mjs.map +1 -0
- package/dist/logger-DDrt03So.mjs +71 -0
- package/dist/logger-DDrt03So.mjs.map +1 -0
- package/dist/markdown-CTlPe5ks.mjs +124 -0
- package/dist/markdown-CTlPe5ks.mjs.map +1 -0
- package/dist/markdown.mjs +1 -1
- package/dist/overlay-9xNgsuuy.mjs +18 -0
- package/dist/overlay-9xNgsuuy.mjs.map +1 -0
- package/dist/{picker-ndVVt6qF.mjs → picker-cH-rc7-X.mjs} +5 -5
- package/dist/{picker-ndVVt6qF.mjs.map → picker-cH-rc7-X.mjs.map} +1 -1
- package/dist/queries-B_lOwEiE.mjs +200 -0
- package/dist/queries-B_lOwEiE.mjs.map +1 -0
- package/dist/{registry-U654j61Y.mjs → registry-w_w7gZr_.mjs} +3 -5
- package/dist/registry-w_w7gZr_.mjs.map +1 -0
- package/dist/render-F8pVXN7h.mjs +33 -0
- package/dist/render-F8pVXN7h.mjs.map +1 -0
- package/dist/renderer-Dgj_qEOA.mjs +2 -0
- package/dist/{renderer-CdLCkJB-.mjs → renderer-qSMVeNSV.mjs} +3 -5
- package/dist/{renderer-CdLCkJB-.mjs.map → renderer-qSMVeNSV.mjs.map} +1 -1
- package/dist/{renderer-CxL4xbkl.mjs → renderer-uMeDzF9B.mjs} +8 -7
- package/dist/{renderer-CxL4xbkl.mjs.map → renderer-uMeDzF9B.mjs.map} +1 -1
- package/dist/select-m7NE6Rwa.mjs +195 -0
- package/dist/select-m7NE6Rwa.mjs.map +1 -0
- package/dist/services/logger.mjs +1 -70
- package/dist/services/notifier.mjs +2 -2
- package/dist/services/picker.d.mts +1 -1
- package/dist/services/picker.mjs +6 -6
- package/dist/services/prompt.d.mts +1 -1
- package/dist/services/prompt.mjs +5 -5
- package/dist/shiki/server.d.mts +1 -0
- package/dist/shiki/server.mjs +129 -0
- package/dist/shiki/server.mjs.map +1 -0
- package/dist/{shiki-BrjVUkeh.mjs → shiki-B5NwIiot.mjs} +5 -10
- package/dist/shiki-B5NwIiot.mjs.map +1 -0
- package/dist/shiki-BK-v9CtF.mjs +12 -0
- package/dist/shiki-BK-v9CtF.mjs.map +1 -0
- package/dist/show-DR2x1YFc.mjs +85 -0
- package/dist/show-DR2x1YFc.mjs.map +1 -0
- package/dist/style.mjs +2 -2
- package/dist/text-9lwQeqYr.d.mts +33 -0
- package/dist/text-9lwQeqYr.d.mts.map +1 -0
- package/dist/text-DILrol9j.mjs +32 -0
- package/dist/text-DILrol9j.mjs.map +1 -0
- package/dist/text-q26V6_Sc.mjs +111 -0
- package/dist/text-q26V6_Sc.mjs.map +1 -0
- package/dist/text.d.mts +2 -33
- package/dist/text.mjs +1 -110
- package/dist/{theme.config-CU3B50HN.mjs → theme.config-BptYUq4K.mjs} +4 -4
- package/dist/{theme.config-CU3B50HN.mjs.map → theme.config-BptYUq4K.mjs.map} +1 -1
- package/dist/themes.mjs +1 -1
- package/dist/tree-Bo1afYhe.mjs +73 -0
- package/dist/tree-Bo1afYhe.mjs.map +1 -0
- package/dist/widget-BkMwhY2p.mjs +40 -0
- package/dist/widget-BkMwhY2p.mjs.map +1 -0
- package/dist/widget-M7jD8Rgg.d.mts +49 -0
- package/dist/widget-M7jD8Rgg.d.mts.map +1 -0
- package/dist/widgets/autocomplete.mjs +2 -2
- package/dist/widgets/box.mjs +1 -1
- package/dist/widgets/code.mjs +7 -7
- package/dist/widgets/completions/actions.d.mts +2 -41
- package/dist/widgets/completions/actions.mjs +1 -47
- package/dist/widgets/completions/files.d.mts +2 -29
- package/dist/widgets/completions/files.mjs +1 -41
- package/dist/widgets/completions/github.d.mts +2 -64
- package/dist/widgets/completions/github.mjs +1 -136
- package/dist/widgets/completions/index.d.mts +3 -3
- package/dist/widgets/completions/index.mjs +3 -3
- package/dist/widgets/diff.d.mts +1 -1
- package/dist/widgets/diff.mjs +3 -3
- package/dist/widgets/divider.mjs +1 -8
- package/dist/widgets/image.d.mts +2 -37
- package/dist/widgets/image.mjs +1 -1
- package/dist/widgets/input.mjs +1 -496
- package/dist/widgets/log.mjs +1 -129
- package/dist/widgets/markdown.d.mts +2 -2
- package/dist/widgets/markdown.mjs +1 -123
- package/dist/widgets/overlay.mjs +1 -17
- package/dist/widgets/picker.mjs +1 -1
- package/dist/widgets/select.mjs +1 -194
- package/dist/widgets/show.mjs +1 -84
- package/dist/widgets/text.mjs +1 -31
- package/dist/widgets/tree.mjs +1 -72
- package/dist/widgets/widget.d.mts +2 -49
- package/dist/widgets/widget.mjs +1 -39
- package/dist/worker-BvRm4OsW.mjs +2 -0
- package/dist/worker-T6SdPzUH.mjs +52 -0
- package/dist/worker-T6SdPzUH.mjs.map +1 -0
- package/package.json +7 -3
- package/dist/client-D6C_uczF.mjs.map +0 -1
- package/dist/clipboard.mjs.map +0 -1
- package/dist/registry-U654j61Y.mjs.map +0 -1
- package/dist/render-DxVLqqB9.mjs +0 -74
- package/dist/render-DxVLqqB9.mjs.map +0 -1
- package/dist/rolldown-runtime-D7D4PA-g.mjs +0 -13
- package/dist/services/logger.mjs.map +0 -1
- package/dist/shiki-BrjVUkeh.mjs.map +0 -1
- package/dist/text.d.mts.map +0 -1
- package/dist/text.mjs.map +0 -1
- package/dist/widgets/completions/actions.d.mts.map +0 -1
- package/dist/widgets/completions/actions.mjs.map +0 -1
- package/dist/widgets/completions/files.d.mts.map +0 -1
- package/dist/widgets/completions/files.mjs.map +0 -1
- package/dist/widgets/completions/github.d.mts.map +0 -1
- package/dist/widgets/completions/github.mjs.map +0 -1
- package/dist/widgets/divider.mjs.map +0 -1
- package/dist/widgets/image.d.mts.map +0 -1
- package/dist/widgets/input.mjs.map +0 -1
- package/dist/widgets/log.mjs.map +0 -1
- package/dist/widgets/markdown.mjs.map +0 -1
- package/dist/widgets/overlay.mjs.map +0 -1
- package/dist/widgets/select.mjs.map +0 -1
- package/dist/widgets/show.mjs.map +0 -1
- package/dist/widgets/text.mjs.map +0 -1
- package/dist/widgets/tree.mjs.map +0 -1
- package/dist/widgets/widget.d.mts.map +0 -1
- package/dist/widgets/widget.mjs.map +0 -1
- package/dist/worker-DjHuQSbY.mjs +0 -27
- package/dist/worker-DjHuQSbY.mjs.map +0 -1
package/dist/widgets/input.mjs
CHANGED
|
@@ -1,497 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as Node } from "../node-BZ7f6HzU.mjs";
|
|
3
|
-
import { formatText } from "../text.mjs";
|
|
4
|
-
import { clipboard } from "../clipboard.mjs";
|
|
5
|
-
import { hash, isPromiseLike } from "@zaly/shared";
|
|
6
|
-
import { sliceAnsi, splitAnsi, stringWidth } from "@zaly/shared/ansi";
|
|
7
|
-
import { basename } from "pathe";
|
|
8
|
-
import { fileDetect } from "@zaly/shared/detect";
|
|
9
|
-
//#region src/widgets/input.ts
|
|
10
|
-
const PASTE_MAX_LINES = 5;
|
|
11
|
-
const PASTE_MAX_CHARS = 1e3;
|
|
12
|
-
/**
|
|
13
|
-
* Multi-line text input with auto-grow.
|
|
14
|
-
*
|
|
15
|
-
* Editing commands (`cursorLeft`, `deleteWordBack`, `submit`, …) live on
|
|
16
|
-
* `this.actions` as zero-arg methods. The input router maps keymap
|
|
17
|
-
* bindings like `"input.cursorLeft"` onto those methods — users bind
|
|
18
|
-
* different keys by configuring the keymap, not by patching the class.
|
|
19
|
-
* The methods are also callable directly (`input.actions.submit()`),
|
|
20
|
-
* which is handy in tests or for higher-level macros.
|
|
21
|
-
*
|
|
22
|
-
* What this class *still* handles via its `key` event listener:
|
|
23
|
-
* - **Printable character insertion.** An unbound keystroke whose
|
|
24
|
-
* `text` is set and has no ctrl/alt/meta modifier becomes a literal
|
|
25
|
-
* insert at the cursor. There's no action for every printable char
|
|
26
|
-
* in the keymap; the raw-key fallback handles them.
|
|
27
|
-
* - **Paste events.** Whole payload inserted at cursor; always.
|
|
28
|
-
*
|
|
29
|
-
* Everything else (navigation, editing, submit/newline) goes through
|
|
30
|
-
* the router → actions pipeline. Unbound non-printable keys fall back
|
|
31
|
-
* to `emit("key", …)` and bubble to the parent chain.
|
|
32
|
-
*
|
|
33
|
-
* Rendering word-wraps each logical line to `ctx.width`, so long
|
|
34
|
-
* messages naturally grow vertically. The UI surface resizes its
|
|
35
|
-
* reserved footer when the Input's row count changes, so the stream
|
|
36
|
-
* above shifts accordingly.
|
|
37
|
-
*/
|
|
38
|
-
var Input = class Input extends Node {
|
|
39
|
-
/** Class-level scope tag used by the input router to bind keymaps. */
|
|
40
|
-
static type = "input";
|
|
41
|
-
type = Input.type;
|
|
42
|
-
#focused = false;
|
|
43
|
-
#history = [];
|
|
44
|
-
#historyDraft = "";
|
|
45
|
-
#historyIndex;
|
|
46
|
-
#preferredCol;
|
|
47
|
-
#staged = [];
|
|
48
|
-
#formatCache = /* @__PURE__ */ new Map();
|
|
49
|
-
#formatGen = 0;
|
|
50
|
-
/**
|
|
51
|
-
* Editing actions. Parameterless — they close over `this` — so both
|
|
52
|
-
* the router (via keymap dispatch) and application code can invoke
|
|
53
|
-
* them. Add to the keymap in `src/input/actions.ts` to give them
|
|
54
|
-
* default key bindings.
|
|
55
|
-
*/
|
|
56
|
-
actions = {
|
|
57
|
-
"input.cursorDown": () => {
|
|
58
|
-
const v = this.state.value ?? "";
|
|
59
|
-
const { col, line } = posToLineCol(v, this.#cursor());
|
|
60
|
-
if (line >= countLines(v) - 1) {
|
|
61
|
-
this.#historyNext();
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
this.#preferredCol ??= col;
|
|
65
|
-
this.state.cursor = lineColToPos(v, line + 1, this.#preferredCol);
|
|
66
|
-
},
|
|
67
|
-
"input.cursorLeft": () => {
|
|
68
|
-
const c = this.#cursor();
|
|
69
|
-
this.#preferredCol = void 0;
|
|
70
|
-
this.state.cursor = c > 0 ? c - 1 : c;
|
|
71
|
-
},
|
|
72
|
-
"input.cursorLineEnd": () => {
|
|
73
|
-
const v = this.state.value ?? "";
|
|
74
|
-
this.#preferredCol = void 0;
|
|
75
|
-
this.state.cursor = lineEndPos(v, this.#cursor());
|
|
76
|
-
},
|
|
77
|
-
"input.cursorLineStart": () => {
|
|
78
|
-
const v = this.state.value ?? "";
|
|
79
|
-
const { line } = posToLineCol(v, this.#cursor());
|
|
80
|
-
this.#preferredCol = void 0;
|
|
81
|
-
this.state.cursor = lineColToPos(v, line, 0);
|
|
82
|
-
},
|
|
83
|
-
"input.cursorRight": () => {
|
|
84
|
-
const v = this.state.value ?? "";
|
|
85
|
-
const c = this.#cursor();
|
|
86
|
-
this.#preferredCol = void 0;
|
|
87
|
-
this.state.cursor = c < v.length ? c + 1 : c;
|
|
88
|
-
},
|
|
89
|
-
"input.cursorUp": () => {
|
|
90
|
-
const v = this.state.value ?? "";
|
|
91
|
-
const { col, line } = posToLineCol(v, this.#cursor());
|
|
92
|
-
if (line === 0) {
|
|
93
|
-
this.#historyPrev();
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
this.#preferredCol ??= col;
|
|
97
|
-
this.state.cursor = lineColToPos(v, line - 1, this.#preferredCol);
|
|
98
|
-
},
|
|
99
|
-
"input.deleteCharBack": () => {
|
|
100
|
-
const v = this.state.value ?? "";
|
|
101
|
-
const c = this.#cursor();
|
|
102
|
-
this.#preferredCol = void 0;
|
|
103
|
-
if (c === 0) return;
|
|
104
|
-
this.#historyEdit();
|
|
105
|
-
const marker = this.#markerRange(c, "back");
|
|
106
|
-
if (marker) return this.#deleteRange(marker.start, marker.end);
|
|
107
|
-
this.state.set({
|
|
108
|
-
cursor: c - 1,
|
|
109
|
-
value: v.slice(0, c - 1) + v.slice(c)
|
|
110
|
-
});
|
|
111
|
-
},
|
|
112
|
-
"input.deleteCharForward": () => {
|
|
113
|
-
const v = this.state.value ?? "";
|
|
114
|
-
const c = this.#cursor();
|
|
115
|
-
this.#preferredCol = void 0;
|
|
116
|
-
if (c >= v.length) return;
|
|
117
|
-
this.#historyEdit();
|
|
118
|
-
const marker = this.#markerRange(c, "forward");
|
|
119
|
-
if (marker) return this.#deleteRange(marker.start, marker.end);
|
|
120
|
-
this.state.value = v.slice(0, c) + v.slice(c + 1);
|
|
121
|
-
},
|
|
122
|
-
"input.deleteWordBack": () => {
|
|
123
|
-
const v = this.state.value ?? "";
|
|
124
|
-
const c = this.#cursor();
|
|
125
|
-
this.#preferredCol = void 0;
|
|
126
|
-
let i = c;
|
|
127
|
-
while (i > 0 && isWhitespace(v[i - 1])) i--;
|
|
128
|
-
while (i > 0 && !isWhitespace(v[i - 1])) i--;
|
|
129
|
-
if (i === c) return;
|
|
130
|
-
this.#historyEdit();
|
|
131
|
-
this.state.set({
|
|
132
|
-
cursor: i,
|
|
133
|
-
value: v.slice(0, i) + v.slice(c)
|
|
134
|
-
});
|
|
135
|
-
},
|
|
136
|
-
"input.insertNewline": () => {
|
|
137
|
-
const v = this.state.value ?? "";
|
|
138
|
-
const c = this.#cursor();
|
|
139
|
-
this.#preferredCol = void 0;
|
|
140
|
-
let lineStart = c;
|
|
141
|
-
while (lineStart > 0 && v[lineStart - 1] !== "\n") lineStart--;
|
|
142
|
-
let indent = "";
|
|
143
|
-
for (let i = lineStart; i < c; i++) {
|
|
144
|
-
const ch = v[i];
|
|
145
|
-
if (ch === " " || ch === " ") indent += ch;
|
|
146
|
-
else break;
|
|
147
|
-
}
|
|
148
|
-
const insert = `\n${indent}`;
|
|
149
|
-
this.#historyEdit();
|
|
150
|
-
this.state.set({
|
|
151
|
-
cursor: c + insert.length,
|
|
152
|
-
value: v.slice(0, c) + insert + v.slice(c)
|
|
153
|
-
});
|
|
154
|
-
},
|
|
155
|
-
"input.insertTab": () => {
|
|
156
|
-
const v = this.state.value ?? "";
|
|
157
|
-
const c = this.#cursor();
|
|
158
|
-
this.#preferredCol = void 0;
|
|
159
|
-
const tab = " ";
|
|
160
|
-
this.#historyEdit();
|
|
161
|
-
this.state.set({
|
|
162
|
-
cursor: c + 2,
|
|
163
|
-
value: v.slice(0, c) + tab + v.slice(c)
|
|
164
|
-
});
|
|
165
|
-
},
|
|
166
|
-
"input.paste": () => {
|
|
167
|
-
(async () => {
|
|
168
|
-
const content = await clipboard.read();
|
|
169
|
-
if (!content) return;
|
|
170
|
-
if (content.kind === "text") {
|
|
171
|
-
this.emit("paste", { paste: {
|
|
172
|
-
stop: () => void 0,
|
|
173
|
-
stopped: false,
|
|
174
|
-
text: content.text
|
|
175
|
-
} });
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
const paths = content.kind === "image" ? [content.path] : content.paths;
|
|
179
|
-
const files = await Promise.all(paths.map((path) => fileDetect({ path })));
|
|
180
|
-
for (let i = 0; i < paths.length; i++) {
|
|
181
|
-
const path = paths[i];
|
|
182
|
-
const file = files[i];
|
|
183
|
-
if (!file) continue;
|
|
184
|
-
this.attach({
|
|
185
|
-
...file,
|
|
186
|
-
path
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
})();
|
|
190
|
-
},
|
|
191
|
-
"input.submit": () => {
|
|
192
|
-
const value = this.state.value ?? "";
|
|
193
|
-
if (this.state.validate?.(value) === false) return;
|
|
194
|
-
const ret = this.consume();
|
|
195
|
-
this.#historyAdd(ret.value);
|
|
196
|
-
this.emit("submit", ret);
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
constructor(initial = {}) {
|
|
200
|
-
const value = initial.value ?? "";
|
|
201
|
-
super({
|
|
202
|
-
cursor: value.length,
|
|
203
|
-
value,
|
|
204
|
-
...initial
|
|
205
|
-
});
|
|
206
|
-
this.#history = [...initial.history ?? []];
|
|
207
|
-
this.on("key", ({ key }) => {
|
|
208
|
-
this.#handleKey(key);
|
|
209
|
-
});
|
|
210
|
-
this.on("paste", ({ paste }) => {
|
|
211
|
-
this.paste(paste.text);
|
|
212
|
-
paste.stop();
|
|
213
|
-
});
|
|
214
|
-
this.on("focus", () => {
|
|
215
|
-
this.#focused = true;
|
|
216
|
-
this.invalidate();
|
|
217
|
-
});
|
|
218
|
-
this.on("blur", () => {
|
|
219
|
-
this.#focused = false;
|
|
220
|
-
this.invalidate();
|
|
221
|
-
});
|
|
222
|
-
this.on("mount", () => {
|
|
223
|
-
this.ctx?.input.events.on("terminal-focus", () => this.invalidate(), { signal: this.mountSignal });
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
get history() {
|
|
227
|
-
return this.#history;
|
|
228
|
-
}
|
|
229
|
-
set history(v) {
|
|
230
|
-
this.#history = [...v];
|
|
231
|
-
this.#historyIndex = void 0;
|
|
232
|
-
}
|
|
233
|
-
attach(att) {
|
|
234
|
-
if (att.type !== "paste" && this.state.canAttach?.(att) === false) return this.insert(att.path);
|
|
235
|
-
const id = this.#staged.length + 1;
|
|
236
|
-
let prefix = att.type[0].toUpperCase() + att.type.slice(1);
|
|
237
|
-
let suffix = "";
|
|
238
|
-
if (att.type === "paste") {
|
|
239
|
-
prefix = "Pasted text";
|
|
240
|
-
suffix = ` +${countLines(att.text)} lines`;
|
|
241
|
-
} else if (!["image", "pdf"].includes(att.type)) suffix = ` ${basename(att.path)}`;
|
|
242
|
-
const marker = `[${prefix} #${id}${suffix}]`;
|
|
243
|
-
this.#staged.push({
|
|
244
|
-
...att,
|
|
245
|
-
id,
|
|
246
|
-
marker
|
|
247
|
-
});
|
|
248
|
-
this.insert(marker);
|
|
249
|
-
if (att.type !== "paste") this.emit("attach", { attachment: att });
|
|
250
|
-
}
|
|
251
|
-
paste(text) {
|
|
252
|
-
if (countLines(text) > (this.state.pasteMaxLines ?? PASTE_MAX_LINES) || stringWidth(text) > (this.state.pasteMaxChars ?? PASTE_MAX_CHARS)) return this.attach({
|
|
253
|
-
text,
|
|
254
|
-
type: "paste"
|
|
255
|
-
});
|
|
256
|
-
this.insert(text);
|
|
257
|
-
}
|
|
258
|
-
insert(text) {
|
|
259
|
-
const v = this.state.value ?? "";
|
|
260
|
-
const c = this.#cursor();
|
|
261
|
-
this.#historyEdit();
|
|
262
|
-
this.#preferredCol = void 0;
|
|
263
|
-
this.state.set({
|
|
264
|
-
cursor: c + text.length,
|
|
265
|
-
value: v.slice(0, c) + text + v.slice(c)
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
replace(text) {
|
|
269
|
-
this.state.value = "";
|
|
270
|
-
this.insert(text);
|
|
271
|
-
}
|
|
272
|
-
/** Consume the input's current value and attachments.
|
|
273
|
-
* Pastes are replaced inline with their text; file/image
|
|
274
|
-
* attachments are returned in the `attachments` array and removed from the value. */
|
|
275
|
-
consume() {
|
|
276
|
-
let value = this.state.value ?? "";
|
|
277
|
-
const atts = [];
|
|
278
|
-
for (const att of this.#staged) {
|
|
279
|
-
if (!value.includes(att.marker)) continue;
|
|
280
|
-
if (att.type === "paste") value = value.replace(att.marker, att.text);
|
|
281
|
-
else atts.push(att);
|
|
282
|
-
}
|
|
283
|
-
this.#staged = [];
|
|
284
|
-
this.#preferredCol = void 0;
|
|
285
|
-
this.state.set({
|
|
286
|
-
cursor: 0,
|
|
287
|
-
value: ""
|
|
288
|
-
});
|
|
289
|
-
return {
|
|
290
|
-
attachments: atts,
|
|
291
|
-
value
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
#cursor() {
|
|
295
|
-
const v = this.state.value ?? "";
|
|
296
|
-
return Math.max(0, Math.min(v.length, this.state.cursor ?? 0));
|
|
297
|
-
}
|
|
298
|
-
#deleteRange(start, end) {
|
|
299
|
-
const v = this.state.value ?? "";
|
|
300
|
-
this.#historyEdit();
|
|
301
|
-
this.#preferredCol = void 0;
|
|
302
|
-
this.state.set({
|
|
303
|
-
cursor: start,
|
|
304
|
-
value: v.slice(0, start) + v.slice(end)
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
historyAdd(value) {
|
|
308
|
-
this.#historyAdd(value);
|
|
309
|
-
}
|
|
310
|
-
#historyAdd(value) {
|
|
311
|
-
if (value.trim() === "") return;
|
|
312
|
-
if (this.#history.at(-1) !== value) {
|
|
313
|
-
this.#history.push(value);
|
|
314
|
-
this.emit("history", {
|
|
315
|
-
added: value,
|
|
316
|
-
history: [...this.#history]
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
this.#historyDraft = "";
|
|
320
|
-
this.#historyIndex = void 0;
|
|
321
|
-
}
|
|
322
|
-
#historyEdit() {
|
|
323
|
-
this.#historyDraft = "";
|
|
324
|
-
this.#historyIndex = void 0;
|
|
325
|
-
}
|
|
326
|
-
#historyNext() {
|
|
327
|
-
if (this.#historyIndex === void 0) return;
|
|
328
|
-
const next = this.#historyIndex + 1;
|
|
329
|
-
if (next >= this.#history.length) {
|
|
330
|
-
this.#historySet(this.#historyDraft);
|
|
331
|
-
this.#historyDraft = "";
|
|
332
|
-
this.#historyIndex = void 0;
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
335
|
-
this.#historyIndex = next;
|
|
336
|
-
this.#historySet(this.#history[next]);
|
|
337
|
-
}
|
|
338
|
-
#historyPrev() {
|
|
339
|
-
if (this.#history.length === 0) return;
|
|
340
|
-
if (this.#historyIndex === void 0) {
|
|
341
|
-
this.#historyDraft = this.state.value ?? "";
|
|
342
|
-
this.#historyIndex = this.#history.length - 1;
|
|
343
|
-
} else if (this.#historyIndex > 0) this.#historyIndex--;
|
|
344
|
-
this.#historySet(this.#history[this.#historyIndex]);
|
|
345
|
-
}
|
|
346
|
-
#historySet(value) {
|
|
347
|
-
this.#preferredCol = void 0;
|
|
348
|
-
this.state.set({
|
|
349
|
-
cursor: value.length,
|
|
350
|
-
value
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
#markerRange(pos, dir) {
|
|
354
|
-
const value = this.state.value ?? "";
|
|
355
|
-
for (const att of this.#staged) {
|
|
356
|
-
const start = value.indexOf(att.marker);
|
|
357
|
-
if (start === -1) continue;
|
|
358
|
-
const end = start + att.marker.length;
|
|
359
|
-
if (dir === "back" && pos > start && pos <= end) return {
|
|
360
|
-
end,
|
|
361
|
-
start
|
|
362
|
-
};
|
|
363
|
-
if (dir === "forward" && pos >= start && pos < end) return {
|
|
364
|
-
end,
|
|
365
|
-
start
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
#handleKey(ev) {
|
|
370
|
-
if (ev.text === void 0 || ev.ctrl || ev.alt || ev.meta) return;
|
|
371
|
-
this.insert(ev.text);
|
|
372
|
-
ev.stop();
|
|
373
|
-
}
|
|
374
|
-
#format(value, ctx) {
|
|
375
|
-
const format = this.state.format;
|
|
376
|
-
if (!format) return value;
|
|
377
|
-
if (ctx.version !== this.#formatCache.version) {
|
|
378
|
-
this.#formatCache.clear();
|
|
379
|
-
this.#formatCache.version = ctx.version;
|
|
380
|
-
}
|
|
381
|
-
const key = hash(value);
|
|
382
|
-
const cached = this.#formatCache.get(key);
|
|
383
|
-
if (cached?.result !== void 0) return cached.result;
|
|
384
|
-
const streaming = this.#streamingFormat(value);
|
|
385
|
-
if (cached?.promise) return streaming ?? value;
|
|
386
|
-
const ret = format(value, { style: ctx.style });
|
|
387
|
-
if (!isPromiseLike(ret)) return ret;
|
|
388
|
-
const gen = ++this.#formatGen;
|
|
389
|
-
const entry = { input: value };
|
|
390
|
-
entry.promise = ret.then((result) => {
|
|
391
|
-
if (this.#formatCache.get(key) !== entry) return;
|
|
392
|
-
entry.result = result;
|
|
393
|
-
entry.promise = void 0;
|
|
394
|
-
if (this.#formatGen === gen && result !== value) untrack(() => this.invalidate());
|
|
395
|
-
}, () => {
|
|
396
|
-
if (this.#formatCache.get(key) === entry) this.#formatCache.delete(key);
|
|
397
|
-
});
|
|
398
|
-
this.#formatCache.set(key, entry);
|
|
399
|
-
while (this.#formatCache.size > 100) this.#formatCache.delete(this.#formatCache.keys().next().value);
|
|
400
|
-
return streaming ?? value;
|
|
401
|
-
}
|
|
402
|
-
/** Reuse a highlighted prefix while async formatting catches up. */
|
|
403
|
-
#streamingFormat(value) {
|
|
404
|
-
let ret;
|
|
405
|
-
for (const [key, cached] of this.#formatCache) {
|
|
406
|
-
if (cached.result === void 0) continue;
|
|
407
|
-
if (value.startsWith(cached.input) && cached.input.length > (ret?.[1].input.length ?? 0)) ret = [key, cached];
|
|
408
|
-
}
|
|
409
|
-
if (ret === void 0) return;
|
|
410
|
-
this.#formatCache.delete(ret[0]);
|
|
411
|
-
this.#formatCache.set(ret[0], ret[1]);
|
|
412
|
-
return ret[1].result + value.slice(ret[1].input.length);
|
|
413
|
-
}
|
|
414
|
-
async _render(ctx) {
|
|
415
|
-
const value = this.state.value ?? "";
|
|
416
|
-
const placeholder = this.state.placeholder ?? "";
|
|
417
|
-
const cursor = this.#cursor();
|
|
418
|
-
const focused = this.#focused;
|
|
419
|
-
let content;
|
|
420
|
-
if (value === "") {
|
|
421
|
-
const ph = unwrap(placeholder);
|
|
422
|
-
content = ph ? ` ${ctx.style.quiet(ph)}` : "";
|
|
423
|
-
} else {
|
|
424
|
-
content = value;
|
|
425
|
-
for (const att of this.#staged) {
|
|
426
|
-
if (!content.includes(att.marker)) continue;
|
|
427
|
-
content = content.replace(att.marker, ctx.style.accent(att.marker));
|
|
428
|
-
}
|
|
429
|
-
content = this.#format(content, ctx);
|
|
430
|
-
}
|
|
431
|
-
if (focused && this.ctx?.input.terminalFocus) {
|
|
432
|
-
const { col, line } = posToLineCol(value, cursor);
|
|
433
|
-
const lines = splitAnsi(content);
|
|
434
|
-
const target = Math.max(0, Math.min(line, lines.length - 1));
|
|
435
|
-
const row = lines[target] ?? "";
|
|
436
|
-
const head = sliceAnsi(row, 0, col);
|
|
437
|
-
const at = sliceAnsi(row, col, col + 1) || " ";
|
|
438
|
-
const tail = sliceAnsi(row, col + 1);
|
|
439
|
-
lines[target] = head + ctx.style.inverse(at) + tail;
|
|
440
|
-
content = lines.join("\n");
|
|
441
|
-
}
|
|
442
|
-
return formatText(content, {
|
|
443
|
-
style: ctx.style.add(this.state),
|
|
444
|
-
width: ctx.width,
|
|
445
|
-
wrap: "word"
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
};
|
|
449
|
-
/**
|
|
450
|
-
* Factory for `Input`. All fields optional; default is an empty,
|
|
451
|
-
* focusable input that fills `ctx.width` and has no placeholder.
|
|
452
|
-
*
|
|
453
|
-
* ```ts
|
|
454
|
-
* input({ placeholder: "type a message…" })
|
|
455
|
-
* const i = input({ value: "draft" })
|
|
456
|
-
* i.on("submit", (text) => console.log("user typed", text))
|
|
457
|
-
* ```
|
|
458
|
-
*/
|
|
459
|
-
function input(state = {}) {
|
|
460
|
-
return new Input(state);
|
|
461
|
-
}
|
|
462
|
-
function isWhitespace(ch) {
|
|
463
|
-
return ch !== void 0 && (ch === " " || ch === " " || ch === "\n");
|
|
464
|
-
}
|
|
465
|
-
function posToLineCol(value, cursor) {
|
|
466
|
-
let line = 0;
|
|
467
|
-
let col = 0;
|
|
468
|
-
for (let i = 0; i < cursor; i++) if (value[i] === "\n") {
|
|
469
|
-
line++;
|
|
470
|
-
col = 0;
|
|
471
|
-
} else col++;
|
|
472
|
-
return {
|
|
473
|
-
col,
|
|
474
|
-
line
|
|
475
|
-
};
|
|
476
|
-
}
|
|
477
|
-
function lineColToPos(value, line, col) {
|
|
478
|
-
const lines = value.split("\n");
|
|
479
|
-
const clampLine = Math.max(0, Math.min(line, lines.length - 1));
|
|
480
|
-
let abs = 0;
|
|
481
|
-
for (let i = 0; i < clampLine; i++) abs += lines[i].length + 1;
|
|
482
|
-
return abs + Math.min(col, lines[clampLine].length);
|
|
483
|
-
}
|
|
484
|
-
function lineEndPos(value, cursor) {
|
|
485
|
-
let i = cursor;
|
|
486
|
-
while (i < value.length && value[i] !== "\n") i++;
|
|
487
|
-
return i;
|
|
488
|
-
}
|
|
489
|
-
function countLines(value) {
|
|
490
|
-
let n = 1;
|
|
491
|
-
for (const ch of value) if (ch === "\n") n++;
|
|
492
|
-
return n;
|
|
493
|
-
}
|
|
494
|
-
//#endregion
|
|
1
|
+
import { n as input, t as Input } from "../input-CRBuTrsL.mjs";
|
|
495
2
|
export { Input, input };
|
|
496
|
-
|
|
497
|
-
//# sourceMappingURL=input.mjs.map
|
package/dist/widgets/log.mjs
CHANGED
|
@@ -1,130 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { text } from "./text.mjs";
|
|
3
|
-
import { markdown } from "./markdown.mjs";
|
|
4
|
-
import { widget } from "./widget.mjs";
|
|
5
|
-
import { stringWidth } from "@zaly/shared/ansi";
|
|
6
|
-
import { hasColors } from "@zaly/shared/env";
|
|
7
|
-
//#region src/widgets/log.ts
|
|
8
|
-
/** Per-level default prefix style + icon + color. Matches rekal's
|
|
9
|
-
* `defaultStyles` table, adapted to zaly's theme slots. */
|
|
10
|
-
const defaultLogStyles = {
|
|
11
|
-
cancel: {
|
|
12
|
-
color: "warn",
|
|
13
|
-
icon: "✖ ",
|
|
14
|
-
style: "icon"
|
|
15
|
-
},
|
|
16
|
-
debug: {
|
|
17
|
-
color: "info",
|
|
18
|
-
icon: "⚙ ",
|
|
19
|
-
style: "prompt"
|
|
20
|
-
},
|
|
21
|
-
error: {
|
|
22
|
-
color: "error",
|
|
23
|
-
icon: "✖ ",
|
|
24
|
-
style: "badge",
|
|
25
|
-
textColor: "error"
|
|
26
|
-
},
|
|
27
|
-
fatal: {
|
|
28
|
-
color: "error",
|
|
29
|
-
icon: "☢ ",
|
|
30
|
-
style: "badge"
|
|
31
|
-
},
|
|
32
|
-
info: {
|
|
33
|
-
color: "info",
|
|
34
|
-
icon: "ℹ ",
|
|
35
|
-
style: "icon"
|
|
36
|
-
},
|
|
37
|
-
log: {
|
|
38
|
-
color: "muted",
|
|
39
|
-
icon: "●",
|
|
40
|
-
style: "icon"
|
|
41
|
-
},
|
|
42
|
-
success: {
|
|
43
|
-
color: "success",
|
|
44
|
-
icon: "✔ ",
|
|
45
|
-
style: "icon"
|
|
46
|
-
},
|
|
47
|
-
trace: {
|
|
48
|
-
color: "muted",
|
|
49
|
-
icon: "⠿",
|
|
50
|
-
style: "icon",
|
|
51
|
-
textColor: "muted"
|
|
52
|
-
},
|
|
53
|
-
warn: {
|
|
54
|
-
color: "warn",
|
|
55
|
-
icon: "⚠",
|
|
56
|
-
style: "badge",
|
|
57
|
-
textColor: "warn"
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
const noColorStyles = {
|
|
61
|
-
badge: "title",
|
|
62
|
-
icon: "text",
|
|
63
|
-
notif: "text",
|
|
64
|
-
prompt: "text",
|
|
65
|
-
text: "text",
|
|
66
|
-
title: "text"
|
|
67
|
-
};
|
|
68
|
-
function renderPrefix(s, ctx) {
|
|
69
|
-
const style = ctx.style;
|
|
70
|
-
const base = defaultLogStyles[s.level];
|
|
71
|
-
let ls = s.style ?? base.style;
|
|
72
|
-
if (!hasColors) ls = noColorStyles[ls];
|
|
73
|
-
let icon = s.icon ?? base.icon ?? "";
|
|
74
|
-
icon = icon === "" ? "" : `${icon}${" ".repeat(2 - stringWidth(icon))}`;
|
|
75
|
-
const color = s.color ?? base.color ?? "inherit";
|
|
76
|
-
let styledPrefix = "";
|
|
77
|
-
if (ls === "badge") styledPrefix = style.bg(color).fg("black").bold(` ${s.level} `);
|
|
78
|
-
else if (ls === "icon") styledPrefix = style.fg(color)(icon);
|
|
79
|
-
else if (ls === "prompt") styledPrefix = style.fg(color).bold(`${icon} ${s.level}`);
|
|
80
|
-
else if (ls === "title") styledPrefix = style.fg(color).bold(`${s.level}:`);
|
|
81
|
-
else if (ls === "notif") styledPrefix = style.fg(color).bold(`${icon} ${s.title ?? s.level}`);
|
|
82
|
-
if (s.prefix) styledPrefix = s.prefix + styledPrefix;
|
|
83
|
-
if (s.title && ls !== "notif") styledPrefix += style.bold(` ${s.title}`);
|
|
84
|
-
return styledPrefix;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* A single log entry — level-styled prefix (icon / badge / prompt / title /
|
|
88
|
-
* plain text) followed by the body content. The body can be any Node, so
|
|
89
|
-
* callers can stack markdown, code, images, etc. inside a log line.
|
|
90
|
-
*
|
|
91
|
-
* ```ts
|
|
92
|
-
* log({ level: "info", content: "hello" })
|
|
93
|
-
* log({ level: "error", content: markdown("**boom**") })
|
|
94
|
-
* ```
|
|
95
|
-
*/
|
|
96
|
-
const log = widget((state, ...children) => {
|
|
97
|
-
const base = defaultLogStyles[state.level];
|
|
98
|
-
const color = state.color ?? base.color ?? "inherit";
|
|
99
|
-
const s = state;
|
|
100
|
-
const textColor = state.textColor ?? (s.style === "notif" ? "inherit" : base.textColor);
|
|
101
|
-
const style = {
|
|
102
|
-
style: textColor ? { fg: textColor } : void 0,
|
|
103
|
-
width: "fill"
|
|
104
|
-
};
|
|
105
|
-
if (state.content !== "") children = [state.markdown ?? true ? markdown(state.content, style) : text(state.content, style), ...children];
|
|
106
|
-
return box({
|
|
107
|
-
...s.style === "notif" ? {
|
|
108
|
-
border: "single",
|
|
109
|
-
borderStyle: { fg: color },
|
|
110
|
-
borderTitle: (ctx) => renderPrefix(state, ctx),
|
|
111
|
-
borderTitleAlign: "center",
|
|
112
|
-
padding: [0, 1],
|
|
113
|
-
width: "fill"
|
|
114
|
-
} : void 0,
|
|
115
|
-
flexDirection: "row",
|
|
116
|
-
gap: 1,
|
|
117
|
-
visible: state.visible
|
|
118
|
-
}, s.style === "notif" ? void 0 : text((ctx) => renderPrefix(state, ctx), {
|
|
119
|
-
flexShrink: 0,
|
|
120
|
-
wrap: "none"
|
|
121
|
-
}), box({
|
|
122
|
-
flexDirection: "column",
|
|
123
|
-
flexGrow: 1,
|
|
124
|
-
gap: 1
|
|
125
|
-
}, ...children));
|
|
126
|
-
});
|
|
127
|
-
//#endregion
|
|
1
|
+
import { t as log } from "../log-Djvrxqk0.mjs";
|
|
128
2
|
export { log };
|
|
129
|
-
|
|
130
|
-
//# sourceMappingURL=log.mjs.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { J as Layout, P as RenderCtx, U as TextContent, X as State, p as Node } from "../queries-DH3bj74K.mjs";
|
|
2
2
|
import { o as AnyStyle } from "../types-B9Eh7k2v.mjs";
|
|
3
|
-
import { WrapMode } from "../text.mjs";
|
|
3
|
+
import { t as WrapMode } from "../text-9lwQeqYr.mjs";
|
|
4
4
|
import { n as MdOptions } from "../types-D3jk1rtk.mjs";
|
|
5
|
-
import { Image } from "
|
|
5
|
+
import { t as Image } from "../image-BTxDPPiT.mjs";
|
|
6
6
|
//#region src/widgets/markdown.d.ts
|
|
7
7
|
interface MarkdownState {
|
|
8
8
|
/** Markdown source. Accepts a plain string or a reactive accessor —
|