@vincemakes/kiso-tui 0.25.0 → 0.26.1
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/ask-panel.js +1 -1
- package/dist/at-picker.js +1 -1
- package/dist/components.d.ts +1 -1
- package/dist/components.js +1 -1
- package/dist/compositor.d.ts +22 -42
- package/dist/compositor.js +265 -924
- package/dist/context-ledger.js +1 -1
- package/dist/editor.d.ts +6 -7
- package/dist/editor.js +376 -786
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{render.js → lines.js} +3 -3
- package/dist/panel-input.d.ts +105 -0
- package/dist/panel-input.js +468 -0
- package/dist/pick-input.d.ts +34 -0
- package/dist/pick-input.js +100 -0
- package/dist/session-picker.js +1 -1
- package/dist/status.js +1 -1
- package/dist/transcript.js +4 -27
- package/package.json +2 -2
- /package/dist/{render.d.ts → lines.d.ts} +0 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SESSION PICKER's input controller — S5 (finding C10). TUI2-R2 ②:
|
|
3
|
+
* the band's third occupant. Its filter is the @ picker's rank aimed at
|
|
4
|
+
* the session id; this controller owns the keys, the compositor draws
|
|
5
|
+
* the rows.
|
|
6
|
+
*
|
|
7
|
+
* The picker is MODAL in a way the @ picker is not: it opens before a
|
|
8
|
+
* session exists, owns the whole composer (the buffer IS the filter
|
|
9
|
+
* query, derived on every read rather than stored, so every buffer op —
|
|
10
|
+
* backspace, the kills, paste — filters correctly with no handler of
|
|
11
|
+
* its own), and the only ways out are a pick and an esc. That is why
|
|
12
|
+
* the commit callback lives here rather than on the line channel: the
|
|
13
|
+
* caller is waiting for an id, not for a turn.
|
|
14
|
+
*
|
|
15
|
+
* DECLARED MOVE (S5, 2026-09-06): `beginPick`, `#pickView`, `pickState`,
|
|
16
|
+
* `#pickUp`, `#pickRows`, `#pickClose`, `#pickAccept` and the ↑↓ branch
|
|
17
|
+
* stood in editor.ts; the bodies are the same, the buffer access goes
|
|
18
|
+
* through the host.
|
|
19
|
+
*/
|
|
20
|
+
import { AT_VISIBLE } from "./at-picker.js";
|
|
21
|
+
import { sessionFilter } from "./session-picker.js";
|
|
22
|
+
export class PickInput {
|
|
23
|
+
host;
|
|
24
|
+
#cards = null;
|
|
25
|
+
#commit = null;
|
|
26
|
+
#sel = 0;
|
|
27
|
+
constructor(host) {
|
|
28
|
+
this.host = host;
|
|
29
|
+
}
|
|
30
|
+
up() {
|
|
31
|
+
return this.#cards !== null;
|
|
32
|
+
}
|
|
33
|
+
/** Open the picker on a bound card source. The composer is cleared
|
|
34
|
+
* (the buffer becomes the filter query) and `onPick` receives the
|
|
35
|
+
* chosen id — or null when the human leaves without picking, which
|
|
36
|
+
* is a first-class outcome and not an error. */
|
|
37
|
+
begin(cards, onPick) {
|
|
38
|
+
this.#cards = cards;
|
|
39
|
+
this.#commit = onPick;
|
|
40
|
+
this.#sel = 0;
|
|
41
|
+
this.host.syncMouse();
|
|
42
|
+
this.host.clear();
|
|
43
|
+
this.host.reflow();
|
|
44
|
+
this.host.render();
|
|
45
|
+
}
|
|
46
|
+
/** The picker's state, derived: the full card list (the id column
|
|
47
|
+
* measures over ALL of them, so the columns never jump), the
|
|
48
|
+
* filtered matches, and the selection CLAMPED at read time — the
|
|
49
|
+
* same correction discipline the @ picker uses, for the same
|
|
50
|
+
* reason: narrowing can only ever shrink the list. */
|
|
51
|
+
state() {
|
|
52
|
+
if (this.#cards === null)
|
|
53
|
+
return null;
|
|
54
|
+
const cards = this.#cards();
|
|
55
|
+
const matches = sessionFilter(cards, this.host.line());
|
|
56
|
+
return { cards, matches, selected: Math.max(0, Math.min(this.#sel, matches.length - 1)) };
|
|
57
|
+
}
|
|
58
|
+
/** The band's height estimate: the header + the windowed rows (or
|
|
59
|
+
* the one "no match" row) + the counter. */
|
|
60
|
+
rows() {
|
|
61
|
+
const view = this.state();
|
|
62
|
+
return view === null ? 0 : Math.min(Math.max(view.matches.length, 1), AT_VISIBLE) + 2;
|
|
63
|
+
}
|
|
64
|
+
/** ↑↓: the selection walks the matches and stops at both ends. True
|
|
65
|
+
* when the picker owned the key (the caller renders). */
|
|
66
|
+
arrow(dir) {
|
|
67
|
+
const view = this.state();
|
|
68
|
+
if (view === null)
|
|
69
|
+
return false;
|
|
70
|
+
this.#sel = dir === "up" ? Math.max(0, view.selected - 1) : Math.min(Math.max(0, view.matches.length - 1), view.selected + 1);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
/** Close and hand the verdict back. The callback fires AFTER the
|
|
74
|
+
* state is cleared, so a caller that re-enters (a second picker, a
|
|
75
|
+
* session that starts) never sees the closing picker's rows. */
|
|
76
|
+
close(id) {
|
|
77
|
+
const cb = this.#commit;
|
|
78
|
+
this.#cards = null;
|
|
79
|
+
this.#commit = null;
|
|
80
|
+
this.#sel = 0;
|
|
81
|
+
this.host.syncMouse();
|
|
82
|
+
this.host.clear();
|
|
83
|
+
this.host.reflow();
|
|
84
|
+
cb?.(id);
|
|
85
|
+
this.host.render();
|
|
86
|
+
}
|
|
87
|
+
/** Enter takes the SELECTED session. An empty match set takes
|
|
88
|
+
* nothing and leaves the picker up: a picker that invented a pick
|
|
89
|
+
* when the query matched nothing would resume the wrong session,
|
|
90
|
+
* which is the one failure this surface must never have. */
|
|
91
|
+
accept() {
|
|
92
|
+
const view = this.state();
|
|
93
|
+
if (view === null)
|
|
94
|
+
return;
|
|
95
|
+
const card = view.matches[view.selected];
|
|
96
|
+
if (card === undefined)
|
|
97
|
+
return;
|
|
98
|
+
this.close(card.id);
|
|
99
|
+
}
|
|
100
|
+
}
|
package/dist/session-picker.js
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* state — which is what lets the picker band and the `kiso sessions`
|
|
24
24
|
* listing render from ONE definition instead of two that drift.
|
|
25
25
|
*/
|
|
26
|
-
import { escapeTerminal, palette } from "./
|
|
26
|
+
import { escapeTerminal, palette } from "./lines.js";
|
|
27
27
|
import { selectionBar, visibleWidth, widthCut } from "./components.js";
|
|
28
28
|
import { atEmbed, bandHeader, longestRun, AT_VISIBLE, atWindow } from "./at-picker.js";
|
|
29
29
|
/** The glyph per state — one cell each, so the badge column never
|
package/dist/status.js
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* deliberate exception: the running row's interrupt hint, which KC2 §2
|
|
22
22
|
* widens to name the new gesture.
|
|
23
23
|
*/
|
|
24
|
-
import { kUnit } from "./
|
|
24
|
+
import { kUnit } from "./lines.js";
|
|
25
25
|
import { TWINKLE } from "@vincemakes/kiso-tui-cells/render";
|
|
26
26
|
/**
|
|
27
27
|
* R3 (design §5.2) — the working glyph family is the TWINKLE, and the
|
package/dist/transcript.js
CHANGED
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
* so a viewer that expanded a committed cell in place would corrupt the
|
|
34
34
|
* window arithmetic for the rest of the session.
|
|
35
35
|
*/
|
|
36
|
-
import { palette } from "./
|
|
37
|
-
import { visibleWidth } from "./components.js";
|
|
36
|
+
import { palette } from "./lines.js";
|
|
37
|
+
import { cutLine, visibleWidth } from "./components.js";
|
|
38
38
|
/** The gutter every viewer row carries: the cursor mark and its space. */
|
|
39
39
|
export const VIEWER_GUTTER = 3;
|
|
40
40
|
export function viewerInit(entries) {
|
|
@@ -135,7 +135,7 @@ export function viewerRows(entries, state, W, rows) {
|
|
|
135
135
|
const mark = line.head ? (open ? "▾" : onCursor ? "▸" : " ") : "│";
|
|
136
136
|
const gutter = onCursor ? `${p.bold}${mark}${p.reset} ` : `${p.dim}${mark}${p.reset} `;
|
|
137
137
|
const row = ` ${gutter}${line.text}`;
|
|
138
|
-
out.push(open ? shade(row, W) :
|
|
138
|
+
out.push(open ? shade(row, W) : cutLine(row, W));
|
|
139
139
|
}
|
|
140
140
|
return out;
|
|
141
141
|
}
|
|
@@ -152,34 +152,11 @@ export function viewerRows(entries, state, W, rows) {
|
|
|
152
152
|
*/
|
|
153
153
|
function shade(row, W) {
|
|
154
154
|
const p = palette();
|
|
155
|
-
const body =
|
|
155
|
+
const body = cutLine(row, W);
|
|
156
156
|
if (p.wash === "")
|
|
157
157
|
return body;
|
|
158
158
|
return `${p.wash}${body}${" ".repeat(Math.max(0, W - visibleWidth(body)))}${p.washEnd}`;
|
|
159
159
|
}
|
|
160
|
-
/** The last resort — the row is cut at W rather than overflowing it. */
|
|
161
|
-
function cut(row, W) {
|
|
162
|
-
if (visibleWidth(row) <= W)
|
|
163
|
-
return row;
|
|
164
|
-
let out = "";
|
|
165
|
-
let n = 0;
|
|
166
|
-
for (let i = 0; i < row.length;) {
|
|
167
|
-
if (row[i] === "\x1b") {
|
|
168
|
-
const j = row.indexOf("m", i);
|
|
169
|
-
if (j < 0)
|
|
170
|
-
break;
|
|
171
|
-
out += row.slice(i, j + 1);
|
|
172
|
-
i = j + 1;
|
|
173
|
-
continue;
|
|
174
|
-
}
|
|
175
|
-
if (n >= W - 1)
|
|
176
|
-
break;
|
|
177
|
-
out += row[i];
|
|
178
|
-
n += 1;
|
|
179
|
-
i += 1;
|
|
180
|
-
}
|
|
181
|
-
return `${out}…${palette().reset}`;
|
|
182
|
-
}
|
|
183
160
|
/** The viewer's affordance row — what the keys do, where they are
|
|
184
161
|
* useful (the PICKER_HINT convention). */
|
|
185
162
|
export function viewerHint(state, entries) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-tui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.1",
|
|
4
4
|
"description": "kiso tui — 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.
|
|
38
|
+
"@vincemakes/kiso-tui-cells": "0.26.1"
|
|
39
39
|
}
|
|
40
40
|
}
|
|
File without changes
|