@vincemakes/kiso-tui 0.15.8 → 0.15.9
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/compositor.js +47 -17
- package/dist/editor.d.ts +4 -0
- package/dist/editor.js +36 -6
- package/package.json +2 -2
package/dist/compositor.js
CHANGED
|
@@ -867,7 +867,7 @@ export class Body {
|
|
|
867
867
|
if (process.stdout.isTTY !== true || palette().bold === "" || rows < 4)
|
|
868
868
|
return;
|
|
869
869
|
this.#docked = true;
|
|
870
|
-
this.#
|
|
870
|
+
this.#guardOutput();
|
|
871
871
|
this.#attachResize();
|
|
872
872
|
this.#fullRedraw = true;
|
|
873
873
|
this.#dirty = true;
|
|
@@ -936,26 +936,56 @@ export class Body {
|
|
|
936
936
|
* change, and the cursor parks on the wrong row. Three PTY gates
|
|
937
937
|
* caught it.
|
|
938
938
|
*
|
|
939
|
-
*
|
|
940
|
-
*
|
|
941
|
-
*
|
|
942
|
-
*
|
|
939
|
+
* REL-0152-D17: BOTH descriptors, and the second one is the one that
|
|
940
|
+
* mattered. The first version of this guard wrapped stdout alone,
|
|
941
|
+
* while kiso's degradation notices go to stderr through
|
|
942
|
+
* `console.error` — and several of them BEGIN with `[` and contain
|
|
943
|
+
* `]`:
|
|
944
|
+
*
|
|
945
|
+
* [extensions] … [project .kiso] …
|
|
946
|
+
* [KISO_FAUX_SCRIPT] … [run failed] …
|
|
947
|
+
*
|
|
948
|
+
* Those land on the tty wherever the cursor is, and a renderer that
|
|
949
|
+
* does not know they were printed skips exactly the rows that would
|
|
950
|
+
* repair them. The residue survives on the rows whose desired content
|
|
951
|
+
* NEVER changes — the composer box's own edges — which is a stray `[`
|
|
952
|
+
* at the left and `]` at the right for the rest of the session,
|
|
953
|
+
* clearing only on a resize and returning on the next launch.
|
|
954
|
+
*
|
|
955
|
+
* The reasoning that missed it was mine, and it is worth keeping: the
|
|
956
|
+
* renderer emits no OSC and no bare `]`, so a `]` on screen CANNOT
|
|
957
|
+
* have come from its stream. I had that fact and concluded "therefore
|
|
958
|
+
* the terminal invents it" when the only sound conclusion is
|
|
959
|
+
* "therefore something else wrote it".
|
|
960
|
+
*
|
|
961
|
+
* The fix is not a list of writers to remember, and not silencing the
|
|
962
|
+
* loggers. A compositor cannot hold a belief about a terminal it does
|
|
963
|
+
* not own: any write it did not make forgets the screen, whichever
|
|
964
|
+
* descriptor carried it. New callers cannot get it wrong because they
|
|
965
|
+
* are not asked to get it right.
|
|
943
966
|
*/
|
|
944
|
-
#
|
|
967
|
+
#guardOutput() {
|
|
945
968
|
if (this.#unguard !== null || this.#opts.write !== undefined)
|
|
946
969
|
return;
|
|
947
|
-
const
|
|
948
|
-
const
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
970
|
+
const restores = [];
|
|
971
|
+
for (const stream of [process.stdout, process.stderr]) {
|
|
972
|
+
const real = stream.write.bind(stream);
|
|
973
|
+
const patched = ((chunk, ...rest) => {
|
|
974
|
+
if (!this.#inFrame)
|
|
975
|
+
this.#screen = [];
|
|
976
|
+
return real(chunk, ...rest);
|
|
977
|
+
});
|
|
978
|
+
stream.write = patched;
|
|
979
|
+
restores.push(() => {
|
|
980
|
+
// only restore what we installed — another wrapper may have
|
|
981
|
+
// been layered on top since (the byte trace does exactly that)
|
|
982
|
+
if (stream.write === patched)
|
|
983
|
+
stream.write = real;
|
|
984
|
+
});
|
|
985
|
+
}
|
|
954
986
|
this.#unguard = () => {
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
if (process.stdout.write === patched)
|
|
958
|
-
process.stdout.write = real;
|
|
987
|
+
for (const r of restores)
|
|
988
|
+
r();
|
|
959
989
|
this.#unguard = null;
|
|
960
990
|
};
|
|
961
991
|
}
|
package/dist/editor.d.ts
CHANGED
|
@@ -72,6 +72,10 @@ export declare class Editor {
|
|
|
72
72
|
* human asks for them — ctrl+V, or an empty paste. The CLI owns the
|
|
73
73
|
* platform, the editor owns the moment. */
|
|
74
74
|
onClipboardPaste(cb: () => string | null): void;
|
|
75
|
+
/** REL-0152-D16: the files this line's `[Image #N]` capsules stand
|
|
76
|
+
* for, by their number. The CLI resolves them when it builds the
|
|
77
|
+
* turn; a capsule the human deleted is simply never looked up. */
|
|
78
|
+
attachments(): Map<number, string>;
|
|
75
79
|
onRedirect(cb: (line: string) => void): void;
|
|
76
80
|
/** W22: bind the pending-turn queue — the CLI's live slots. The ↑
|
|
77
81
|
* pop walks them (each pop leaves the queue, cancelling the turn);
|
package/dist/editor.js
CHANGED
|
@@ -131,6 +131,24 @@ export class Editor {
|
|
|
131
131
|
* every entry is text they chose to paste and may still submit.
|
|
132
132
|
*/
|
|
133
133
|
#pastes = new Map();
|
|
134
|
+
/**
|
|
135
|
+
* REL-0152-D16 — which file each `[Image #N]` capsule stands for.
|
|
136
|
+
*
|
|
137
|
+
* D15 made ctrl+V fetch the clipboard and it worked; then it inserted
|
|
138
|
+
* the PATH, the path began with `/`, and the composer handed it to
|
|
139
|
+
* the slash-command dispatcher. A feature that reaches the last step
|
|
140
|
+
* and gives the result to the wrong parser has not shipped.
|
|
141
|
+
*
|
|
142
|
+
* So the buffer carries a token and this carries the file. The token
|
|
143
|
+
* is what the LINE is — the dispatcher sees `[Image #1]`, which is
|
|
144
|
+
* not a command and never could be — and the CLI reads this map when
|
|
145
|
+
* it builds the turn. Unlike the text capsule, the image is NOT
|
|
146
|
+
* expanded into the line on the way out: a path is not something the
|
|
147
|
+
* model should be sent, and a transcript full of temp-file names is
|
|
148
|
+
* not something the human should have to read.
|
|
149
|
+
*/
|
|
150
|
+
#attachments = new Map();
|
|
151
|
+
#attachSeq = 0;
|
|
134
152
|
#pasteSeq = 0;
|
|
135
153
|
/** The buffer index where the in-flight paste began; null outside one. */
|
|
136
154
|
#pasteAt = null;
|
|
@@ -311,6 +329,12 @@ export class Editor {
|
|
|
311
329
|
onClipboardPaste(cb) {
|
|
312
330
|
this.#onClipboardPaste = cb;
|
|
313
331
|
}
|
|
332
|
+
/** REL-0152-D16: the files this line's `[Image #N]` capsules stand
|
|
333
|
+
* for, by their number. The CLI resolves them when it builds the
|
|
334
|
+
* turn; a capsule the human deleted is simply never looked up. */
|
|
335
|
+
attachments() {
|
|
336
|
+
return new Map(this.#attachments);
|
|
337
|
+
}
|
|
314
338
|
onRedirect(cb) {
|
|
315
339
|
this.#redirectCbs.push(cb);
|
|
316
340
|
}
|
|
@@ -1205,9 +1229,13 @@ export class Editor {
|
|
|
1205
1229
|
// REL-0152-D15: ctrl+V asks for the clipboard. Inert with no
|
|
1206
1230
|
// hook wired, and 0x16 must NEVER reach the buffer — an
|
|
1207
1231
|
// unhandled control byte in a prompt is a corrupt prompt.
|
|
1208
|
-
const
|
|
1209
|
-
if (
|
|
1210
|
-
|
|
1232
|
+
const file = this.#onClipboardPaste?.() ?? null;
|
|
1233
|
+
if (file !== null && file !== "") {
|
|
1234
|
+
// REL-0152-D16: the capsule goes in the buffer, the file
|
|
1235
|
+
// goes beside it. See #attachments.
|
|
1236
|
+
this.#attachSeq += 1;
|
|
1237
|
+
this.#attachments.set(this.#attachSeq, file);
|
|
1238
|
+
for (const ch of `[Image #${this.#attachSeq}]`)
|
|
1211
1239
|
this.#insert(ch.codePointAt(0));
|
|
1212
1240
|
this.#onRender();
|
|
1213
1241
|
}
|
|
@@ -1951,10 +1979,12 @@ export class Editor {
|
|
|
1951
1979
|
// REL-0152-D11: an empty paste is the image case — see
|
|
1952
1980
|
// #onEmptyPaste. Anything it returns is ordinary text from here
|
|
1953
1981
|
// on and takes the same route as if it had been typed.
|
|
1954
|
-
const
|
|
1955
|
-
if (
|
|
1982
|
+
const file = this.#onClipboardPaste?.() ?? null;
|
|
1983
|
+
if (file === null || file === "")
|
|
1956
1984
|
return;
|
|
1957
|
-
|
|
1985
|
+
this.#attachSeq += 1;
|
|
1986
|
+
this.#attachments.set(this.#attachSeq, file);
|
|
1987
|
+
run = [...`[Image #${this.#attachSeq}]`].map((ch) => ch.codePointAt(0));
|
|
1958
1988
|
}
|
|
1959
1989
|
if (this.#historyIdx !== null)
|
|
1960
1990
|
this.#historyIdx = null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-tui",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.9",
|
|
4
4
|
"description": "kiso tui \u2014 the pure terminal layer (cell renderer, dock, raw editor, diff, palette). Zero runtime dependencies: input is data, output is bytes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,6 +35,6 @@
|
|
|
35
35
|
},
|
|
36
36
|
"homepage": "https://github.com/vincemakes/kiso/tree/main/packages/tui#readme",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@vincemakes/kiso-tui-cells": "0.15.
|
|
38
|
+
"@vincemakes/kiso-tui-cells": "0.15.9"
|
|
39
39
|
}
|
|
40
40
|
}
|