@vincemakes/kiso-tui 0.15.5 → 0.15.7
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 +38 -1
- package/dist/editor.d.ts +4 -0
- package/dist/editor.js +33 -3
- package/package.json +2 -2
package/dist/compositor.js
CHANGED
|
@@ -803,8 +803,14 @@ export class Body {
|
|
|
803
803
|
// "[?1000l[?1006l" into piped stdout and four gates caught it
|
|
804
804
|
// (compact-cli, tui-modes, tui-v7-planmode, tui2-r2-resume-picker):
|
|
805
805
|
// the invariant is about terminals, and a pipe is not one.
|
|
806
|
+
// REL-0152-D14: autowrap goes back on with the mouse, and for the
|
|
807
|
+
// same reason — the terminal outlives kiso, and a mode kiso turned
|
|
808
|
+
// off inside a frame must never be what the shell inherits. The
|
|
809
|
+
// frame restores it itself; this is the second belt, on the same
|
|
810
|
+
// TTY gate, because a half-torn-down compositor is exactly where a
|
|
811
|
+
// mode leak survives.
|
|
806
812
|
if (process.stdout.isTTY === true)
|
|
807
|
-
this.#write(MOUSE_OFF);
|
|
813
|
+
this.#write(`${MOUSE_OFF}\x1b[?7h`);
|
|
808
814
|
if (!this.#docked) {
|
|
809
815
|
// TUI2-R2pre ③: an un-docked compositor can still hold a listener
|
|
810
816
|
// (it was superseded, or enter() ran and the dock was torn down by
|
|
@@ -1180,6 +1186,36 @@ export class Body {
|
|
|
1180
1186
|
panelSpan === null ? null : { top: liveTop + panelSpan.offset, count: panelSpan.count, first: panelSpan.first };
|
|
1181
1187
|
// 5. the frame bytes.
|
|
1182
1188
|
const out = [];
|
|
1189
|
+
// REL-0152-D14 — AUTOWRAP OFF for the frame's duration.
|
|
1190
|
+
//
|
|
1191
|
+
// Found in the owner's own capture: 97 of the rows kiso emitted at
|
|
1192
|
+
// 80 columns are EXACTLY 80 cells wide — the box top, the box
|
|
1193
|
+
// bottom, the composer row, every gap row the chrome pads out. A
|
|
1194
|
+
// character printed into the last column does not move the cursor
|
|
1195
|
+
// past it; it sets the terminal's PENDING WRAP flag, and the next
|
|
1196
|
+
// printed character goes to column 1 of the following row. What
|
|
1197
|
+
// terminals do with that flag when a cursor MOVE arrives instead
|
|
1198
|
+
// of a character is not agreed on — some clear it, some keep it —
|
|
1199
|
+
// and this frame then makes 65 relative cursor-ups through exactly
|
|
1200
|
+
// that state.
|
|
1201
|
+
//
|
|
1202
|
+
// So the frame's layout depended on a behaviour terminals disagree
|
|
1203
|
+
// about, on every frame, at every width where a row happens to
|
|
1204
|
+
// fill the screen. That is enough to explain a layout that is
|
|
1205
|
+
// correct on one terminal and damaged on another, and damaged only
|
|
1206
|
+
// while frames are being painted.
|
|
1207
|
+
//
|
|
1208
|
+
// With autowrap off, a character in the last column simply stays
|
|
1209
|
+
// there: no pending flag, no disagreement, and relative moves mean
|
|
1210
|
+
// what they say. kiso can never lose content to it either, because
|
|
1211
|
+
// #checked already refuses to emit a row wider than the screen —
|
|
1212
|
+
// the invariant that makes turning wrapping off safe was in place
|
|
1213
|
+
// long before this.
|
|
1214
|
+
//
|
|
1215
|
+
// Restored at the end of every frame: prose written OUTSIDE a
|
|
1216
|
+
// frame (bodyLog, an error) is ordinary output and must still
|
|
1217
|
+
// wrap, and the shell inherits the terminal when kiso exits.
|
|
1218
|
+
out.push("\x1b[?7l");
|
|
1183
1219
|
out.push(this.#conservative ? "\x1b[?25l" : "\x1b[?2026h"); // D1: sync ON, or cursor-hide where 2026 is dead bytes
|
|
1184
1220
|
// A8: the bottom-anchored window (the model's last H rows) shifts
|
|
1185
1221
|
// DOWN when the live region SHRINKS — the done-fold, the fold-hold
|
|
@@ -1202,6 +1238,7 @@ export class Body {
|
|
|
1202
1238
|
this.#drawSteady(out, W, H, liveTop, liveLines, queueRows, menuRows, editor);
|
|
1203
1239
|
}
|
|
1204
1240
|
out.push(this.#conservative ? "\x1b[?25h" : "\x1b[?2026l");
|
|
1241
|
+
out.push("\x1b[?7h"); // REL-0152-D14: autowrap back on for everything outside the frame
|
|
1205
1242
|
this.#write(out.join(""));
|
|
1206
1243
|
this.#lastLiveTop = liveTop;
|
|
1207
1244
|
this.#lastLiveRows = liveRowsTotal;
|
package/dist/editor.d.ts
CHANGED
|
@@ -68,6 +68,10 @@ export declare class Editor {
|
|
|
68
68
|
* over while the run is told to stop. Mirrors onEscape (a list, so
|
|
69
69
|
* listeners can coexist); the line arrives already gone from the
|
|
70
70
|
* composer, exactly as a submit's does. */
|
|
71
|
+
/** REL-0152-D11: what to do when a paste arrives empty. See
|
|
72
|
+
* #onEmptyPaste — the CLI owns the platform, the editor owns the
|
|
73
|
+
* moment. */
|
|
74
|
+
onEmptyPaste(cb: () => string | null): void;
|
|
71
75
|
onRedirect(cb: (line: string) => void): void;
|
|
72
76
|
/** W22: bind the pending-turn queue — the CLI's live slots. The ↑
|
|
73
77
|
* pop walks them (each pop leaves the queue, cancelling the turn);
|
package/dist/editor.js
CHANGED
|
@@ -153,6 +153,23 @@ export class Editor {
|
|
|
153
153
|
* reads, and this is a field, not a local.
|
|
154
154
|
*/
|
|
155
155
|
#pasteRun = null;
|
|
156
|
+
/**
|
|
157
|
+
* REL-0152-D11 — what an EMPTY paste means.
|
|
158
|
+
*
|
|
159
|
+
* Pasting an image sends nothing: a terminal has no way to put binary
|
|
160
|
+
* into a byte stream, so the bracketed paste arrives with no content.
|
|
161
|
+
* That emptiness is the signal — the user pressed paste and the
|
|
162
|
+
* terminal had nothing to hand over — and whatever they meant has to
|
|
163
|
+
* be fetched from the clipboard instead.
|
|
164
|
+
*
|
|
165
|
+
* The editor does not know what a clipboard is and must not: this
|
|
166
|
+
* package renders and reads keys, and reaching into the operating
|
|
167
|
+
* system from it would put a platform dependency under every gate in
|
|
168
|
+
* the suite. The CLI supplies the hook; the editor supplies the
|
|
169
|
+
* moment. It returns the text to insert (a path, for the CLI's
|
|
170
|
+
* attachment scan to pick up) or null when there was nothing.
|
|
171
|
+
*/
|
|
172
|
+
#onEmptyPaste = null;
|
|
156
173
|
/** TUI2-R3v2 ①: one-shot — a panel that just closed swallows the
|
|
157
174
|
* habitual trailing enter rather than submitting the restored draft. */
|
|
158
175
|
#swallowEnter = false;
|
|
@@ -282,6 +299,12 @@ export class Editor {
|
|
|
282
299
|
* over while the run is told to stop. Mirrors onEscape (a list, so
|
|
283
300
|
* listeners can coexist); the line arrives already gone from the
|
|
284
301
|
* composer, exactly as a submit's does. */
|
|
302
|
+
/** REL-0152-D11: what to do when a paste arrives empty. See
|
|
303
|
+
* #onEmptyPaste — the CLI owns the platform, the editor owns the
|
|
304
|
+
* moment. */
|
|
305
|
+
onEmptyPaste(cb) {
|
|
306
|
+
this.#onEmptyPaste = cb;
|
|
307
|
+
}
|
|
285
308
|
onRedirect(cb) {
|
|
286
309
|
this.#redirectCbs.push(cb);
|
|
287
310
|
}
|
|
@@ -1902,12 +1925,19 @@ export class Editor {
|
|
|
1902
1925
|
* operation in this file works on it without knowing it exists.
|
|
1903
1926
|
*/
|
|
1904
1927
|
#commitPaste() {
|
|
1905
|
-
|
|
1928
|
+
let run = this.#pasteRun ?? [];
|
|
1906
1929
|
const start = this.#pasteAt ?? this.#cursor;
|
|
1907
1930
|
this.#pasteRun = null;
|
|
1908
1931
|
this.#pasteAt = null;
|
|
1909
|
-
if (run.length === 0)
|
|
1910
|
-
|
|
1932
|
+
if (run.length === 0) {
|
|
1933
|
+
// REL-0152-D11: an empty paste is the image case — see
|
|
1934
|
+
// #onEmptyPaste. Anything it returns is ordinary text from here
|
|
1935
|
+
// on and takes the same route as if it had been typed.
|
|
1936
|
+
const substitute = this.#onEmptyPaste?.() ?? null;
|
|
1937
|
+
if (substitute === null || substitute === "")
|
|
1938
|
+
return;
|
|
1939
|
+
run = [...substitute].map((ch) => ch.codePointAt(0));
|
|
1940
|
+
}
|
|
1911
1941
|
if (this.#historyIdx !== null)
|
|
1912
1942
|
this.#historyIdx = null;
|
|
1913
1943
|
this.#queuePopMode = false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-tui",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.7",
|
|
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.7"
|
|
39
39
|
}
|
|
40
40
|
}
|