@chengchenccc/tui 0.2.0-rc.2 → 0.2.0-rc.4
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/components/ansi-console.d.ts.map +1 -1
- package/dist/components/ansi-console.js +5 -1
- package/dist/components/loader.d.ts +9 -9
- package/dist/components/loader.d.ts.map +1 -1
- package/dist/components/loader.js +10 -9
- package/dist/components/output-block.d.ts.map +1 -1
- package/dist/components/output-block.js +10 -6
- package/dist/components/output-block.test.d.ts +2 -0
- package/dist/components/output-block.test.d.ts.map +1 -0
- package/dist/components/output-block.test.js +32 -0
- package/dist/components/statusline.d.ts.map +1 -1
- package/dist/components/statusline.js +3 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/loader-sweep.test.js +2 -2
- package/dist/mermaid.d.ts.map +1 -1
- package/dist/mermaid.js +13 -1
- package/dist/stdin-buffer.d.ts +3 -0
- package/dist/stdin-buffer.d.ts.map +1 -1
- package/dist/stdin-buffer.js +13 -3
- package/dist/stdin-buffer.test.js +15 -0
- package/dist/terminal.d.ts +2 -0
- package/dist/terminal.d.ts.map +1 -1
- package/dist/terminal.js +16 -1
- package/dist/theme.d.ts +46 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +52 -0
- package/dist/tui-scrollback.test.js +92 -0
- package/dist/tui.d.ts +3 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +47 -4
- package/package.json +1 -1
- package/dist/mouse.d.ts +0 -40
- package/dist/mouse.d.ts.map +0 -1
- package/dist/mouse.js +0 -39
- package/dist/mouse.test.d.ts +0 -2
- package/dist/mouse.test.d.ts.map +0 -1
- package/dist/mouse.test.js +0 -36
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ansi-console.d.ts","sourceRoot":"","sources":["../../src/components/ansi-console.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"ansi-console.d.ts","sourceRoot":"","sources":["../../src/components/ansi-console.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAS3C;;;;;;;;;;sCAUsC;AACtC,qBAAa,WAAY,YAAW,SAAS;IAQzC,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAVlC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAqC;IACxD,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,WAAW,CAAM;gBAGvB,OAAO,EAAE,MAAM,EACE,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAC/B,SAAS,EAAE,MAAM,IAAI,EACrB,eAAe,GAAE,MAAM,IAAe;IAUzD,iEAAiE;IACjE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMzB;0EACsE;IACtE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAc/B,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAU/B,UAAU,IAAI,IAAI;CAInB"}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import xterm from "@xterm/headless";
|
|
2
|
+
import { sliceByColumn } from "../utils.js";
|
|
2
3
|
import { lineToAnsi } from "../virtual-terminal.js";
|
|
4
|
+
/** sliceByColumn's strict flag: hard-cut at the column boundary rather
|
|
5
|
+
* than leave a wide char straddling it. */
|
|
6
|
+
const TRUNCATE_STRICT = true;
|
|
3
7
|
const XtermTerminal = xterm.Terminal;
|
|
4
8
|
/** Live ANSI console pane backed by a headless xterm VT.
|
|
5
9
|
*
|
|
@@ -57,7 +61,7 @@ export class AnsiConsole {
|
|
|
57
61
|
this.cachedWidth = width;
|
|
58
62
|
this.dirty = false;
|
|
59
63
|
}
|
|
60
|
-
return this.cached.map((line) => line
|
|
64
|
+
return this.cached.map((line) => sliceByColumn(line, 0, width, TRUNCATE_STRICT));
|
|
61
65
|
}
|
|
62
66
|
handleInput(data) {
|
|
63
67
|
// A lone Esc terminates the console (pi semantics); escape sequences
|
|
@@ -9,17 +9,17 @@ export interface LoaderIndicatorOptions {
|
|
|
9
9
|
/**
|
|
10
10
|
* Loader component that updates with an optional spinning animation.
|
|
11
11
|
*/
|
|
12
|
-
/** The one light-sweep palette
|
|
13
|
-
* consumer's shimmer (oma's chrome rows,
|
|
14
|
-
* "working" animations cannot drift
|
|
15
|
-
*
|
|
12
|
+
/** The one light-sweep palette, fed from the theme (sweepLow/Mid/High). The
|
|
13
|
+
* loader's message band and every consumer's shimmer (oma's chrome rows,
|
|
14
|
+
* tool bodies) read from here, so the "working" animations cannot drift
|
|
15
|
+
* into different colors: band and spinner read as one animation. */
|
|
16
16
|
export declare const SHIMMER_TIER_OPEN: {
|
|
17
17
|
/** Base tier: dim, the resting color of an unsettled line. */
|
|
18
|
-
readonly low:
|
|
19
|
-
/** Mid band: the spinner's own
|
|
20
|
-
readonly mid:
|
|
21
|
-
/** Crest: bold
|
|
22
|
-
readonly high:
|
|
18
|
+
readonly low: string;
|
|
19
|
+
/** Mid band: the spinner's own accent. */
|
|
20
|
+
readonly mid: string;
|
|
21
|
+
/** Crest: bold accent. */
|
|
22
|
+
readonly high: `\u001B[1m${string}`;
|
|
23
23
|
};
|
|
24
24
|
export type ShimmerTier = keyof typeof SHIMMER_TIER_OPEN;
|
|
25
25
|
export declare class Loader extends Text {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/components/loader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/components/loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,WAAW,sBAAsB;IACrC,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAKD;;GAEG;AACH;;;qEAGqE;AACrE,eAAO,MAAM,iBAAiB;IAC5B,8DAA8D;;IAE9D,0CAA0C;;IAE1C,0BAA0B;;CAElB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,iBAAiB,CAAC;AAEzD,qBAAa,MAAO,SAAQ,IAAI;IAC9B,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,YAAY,CAAK;IACzB;;mEAE+D;IAC/D,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,uBAAuB,CAAS;IACxC,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,OAAO,CAAwB;gBAGrC,EAAE,EAAE,GAAG,EACP,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EACvC,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EACvC,OAAO,GAAE,MAAqB,EAC9B,SAAS,CAAC,EAAE,sBAAsB;IAU3B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAOxC,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,IAAI;IAOZ,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAMjC,YAAY,CAAC,SAAS,CAAC,EAAE,sBAAsB,GAAG,IAAI;IAYtD,OAAO,CAAC,gBAAgB;IAYxB;;;qDAGiD;IACjD,OAAO,CAAC,cAAc;IAuBtB,OAAO,CAAC,aAAa;CAStB"}
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
+
import { tuiTheme } from "../theme.js";
|
|
1
2
|
import { Text } from "./text.js";
|
|
2
3
|
const DEFAULT_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
3
4
|
const DEFAULT_INTERVAL_MS = 80;
|
|
4
5
|
/**
|
|
5
6
|
* Loader component that updates with an optional spinning animation.
|
|
6
7
|
*/
|
|
7
|
-
/** The one light-sweep palette
|
|
8
|
-
* consumer's shimmer (oma's chrome rows,
|
|
9
|
-
* "working" animations cannot drift
|
|
10
|
-
*
|
|
8
|
+
/** The one light-sweep palette, fed from the theme (sweepLow/Mid/High). The
|
|
9
|
+
* loader's message band and every consumer's shimmer (oma's chrome rows,
|
|
10
|
+
* tool bodies) read from here, so the "working" animations cannot drift
|
|
11
|
+
* into different colors: band and spinner read as one animation. */
|
|
11
12
|
export const SHIMMER_TIER_OPEN = {
|
|
12
13
|
/** Base tier: dim, the resting color of an unsettled line. */
|
|
13
|
-
low:
|
|
14
|
-
/** Mid band: the spinner's own
|
|
15
|
-
mid:
|
|
16
|
-
/** Crest: bold
|
|
17
|
-
high:
|
|
14
|
+
low: tuiTheme.dim,
|
|
15
|
+
/** Mid band: the spinner's own accent. */
|
|
16
|
+
mid: tuiTheme.accent,
|
|
17
|
+
/** Crest: bold accent. */
|
|
18
|
+
high: `\u001b[1m${tuiTheme.accent}`,
|
|
18
19
|
};
|
|
19
20
|
export class Loader extends Text {
|
|
20
21
|
frames = [...DEFAULT_FRAMES];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output-block.d.ts","sourceRoot":"","sources":["../../src/components/output-block.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"output-block.d.ts","sourceRoot":"","sources":["../../src/components/output-block.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAEvF,MAAM,WAAW,kBAAkB;IACjC,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+CAA+C;IAC/C,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,gBAAgB,CAAC;IACxB,QAAQ,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAkBD,yEAAyE;AACzE,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,EACb,kBAAkB,CAAC,EAAE,MAAM,EAC3B,mBAAmB,CAAC,EAAE,MAAM,GAC3B,MAAM,CAIR;AAwCD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,EAAE,CA+CvE;AAED;;;;;;;GAOG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,WAAW,CAAgC;IAEnD,MAAM,CAAC,OAAO,EAAE,kBAAkB,GAAG,SAAS,MAAM,EAAE;IAStD,UAAU,IAAI,IAAI;IAKlB,OAAO,CAAC,QAAQ;CAmBjB"}
|
|
@@ -5,14 +5,18 @@
|
|
|
5
5
|
* rich result blocks. It replaces the ad-hoc Card + Text children hacks that
|
|
6
6
|
* made each tool renderer re-implement its own border/background rules.
|
|
7
7
|
*/
|
|
8
|
+
import { tuiTheme } from "../theme.js";
|
|
8
9
|
import { applyBackgroundToLine, visibleWidth, wrapTextWithAnsi } from "../utils.js";
|
|
9
|
-
/**
|
|
10
|
+
/** Border color per state — the SAME verdict tokens the header icon/title
|
|
11
|
+
* use (running gold, error crimson, success jade), so the frame echoes the
|
|
12
|
+
* verdict instead of a second, off-palette color system. Routed through
|
|
13
|
+
* tuiTheme like every other SGR decision in the TUI. */
|
|
10
14
|
const STATE_BORDER = {
|
|
11
|
-
pending:
|
|
12
|
-
running:
|
|
13
|
-
success:
|
|
14
|
-
error:
|
|
15
|
-
warning:
|
|
15
|
+
pending: tuiTheme.info,
|
|
16
|
+
running: tuiTheme.warning,
|
|
17
|
+
success: tuiTheme.success,
|
|
18
|
+
error: tuiTheme.error,
|
|
19
|
+
warning: tuiTheme.warning,
|
|
16
20
|
};
|
|
17
21
|
function normalizePadding(value) {
|
|
18
22
|
return value === undefined ? 1 : Math.max(0, Math.trunc(value));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output-block.test.d.ts","sourceRoot":"","sources":["../../src/components/output-block.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { tuiTheme } from "../theme.js";
|
|
3
|
+
import { renderOutputBlock } from "./output-block.js";
|
|
4
|
+
/** The border is the state's verdict channel: it must carry the SAME theme
|
|
5
|
+
* token the header icon/title use (running gold, error crimson, success
|
|
6
|
+
* jade), so the frame color answers "live / failed / done" at a glance —
|
|
7
|
+
* and a future theme swap recolors borders with everything else. */
|
|
8
|
+
describe("output block state border", () => {
|
|
9
|
+
const top = (state) => renderOutputBlock({ state, sections: [], width: 12 })[0] ?? "";
|
|
10
|
+
test("border color mirrors the verdict token per state", () => {
|
|
11
|
+
expect(top("running")).toContain(tuiTheme.warning);
|
|
12
|
+
expect(top("error")).toContain(tuiTheme.error);
|
|
13
|
+
expect(top("success")).toContain(tuiTheme.success);
|
|
14
|
+
expect(top("pending")).toContain(tuiTheme.info);
|
|
15
|
+
expect(top("warning")).toContain(tuiTheme.warning);
|
|
16
|
+
});
|
|
17
|
+
/** The mapping this file replaced had running=blue and error=teal-blue —
|
|
18
|
+
* visually the same border for opposite verdicts, which is why the border
|
|
19
|
+
* carried no status signal at all. */
|
|
20
|
+
test("running and error borders are distinguishable", () => {
|
|
21
|
+
expect(top("running")).not.toBe(top("error"));
|
|
22
|
+
});
|
|
23
|
+
test("an explicit borderColor override still wins over the state default", () => {
|
|
24
|
+
const lines = renderOutputBlock({
|
|
25
|
+
state: "running",
|
|
26
|
+
borderColor: tuiTheme.dim,
|
|
27
|
+
sections: [],
|
|
28
|
+
width: 12,
|
|
29
|
+
});
|
|
30
|
+
expect(lines[0]).toContain(tuiTheme.dim);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statusline.d.ts","sourceRoot":"","sources":["../../src/components/statusline.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"statusline.d.ts","sourceRoot":"","sources":["../../src/components/statusline.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0DAA0D;IAC1D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gEAAgE;IAChE,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;uEACuE;AACvE,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,aAAa,EAAE,GAAG,MAAM,CAatE;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,MAAM,CAaT"}
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Minimal omp-style status bar renderer (powerline chip + semantic colors).
|
|
3
|
-
* Pure ANSI functions, no component state. Keeping this in packages/tui lets
|
|
4
|
-
* both the bottom status line and (optionally) the header reuse it.
|
|
5
|
-
*/
|
|
1
|
+
import { tuiTheme } from "../theme.js";
|
|
6
2
|
/** One powerline chip: ◀bg label bg▶ using the same color for arrows/fill,
|
|
7
3
|
* but white bold text inside so the label is readable on the tint. */
|
|
8
4
|
export function chip(text, bgAnsi) {
|
|
@@ -17,7 +13,7 @@ export function renderStatusBar(segs) {
|
|
|
17
13
|
if (!s.text)
|
|
18
14
|
continue;
|
|
19
15
|
if (i > 0)
|
|
20
|
-
out.push(
|
|
16
|
+
out.push(`${tuiTheme.dim} ┆ \x1b[0m`);
|
|
21
17
|
if (s.chip && s.bg) {
|
|
22
18
|
out.push(chip(s.text, s.bg));
|
|
23
19
|
}
|
|
@@ -39,7 +35,7 @@ export function renderToolHeader(opts) {
|
|
|
39
35
|
if (meta.length > 0)
|
|
40
36
|
parts.push(meta.join(" · "));
|
|
41
37
|
if (parts.length > 0) {
|
|
42
|
-
const dim = opts.dimColor ??
|
|
38
|
+
const dim = opts.dimColor ?? tuiTheme.dim;
|
|
43
39
|
return `${title} ${dim}${parts.join(" · ")}\u001b[0m`;
|
|
44
40
|
}
|
|
45
41
|
return title;
|
package/dist/index.d.ts
CHANGED
|
@@ -15,12 +15,12 @@ export { TruncatedText } from "./components/truncated-text.ts";
|
|
|
15
15
|
export type { EditorComponent } from "./editor-component.ts";
|
|
16
16
|
export { getKeybindings, type Keybinding, type KeybindingConflict, type KeybindingDefinition, type KeybindingDefinitions, type Keybindings, type KeybindingsConfig, KeybindingsManager, setKeybindings, TUI_KEYBINDINGS, } from "./keybindings.ts";
|
|
17
17
|
export { decodeKittyPrintable, isKeyRelease, isKeyRepeat, isKittyProtocolActive, Key, type KeyEventType, type KeyId, matchesKey, parseKey, setKittyProtocolActive, } from "./keys.ts";
|
|
18
|
-
export { parseSgrMouse, routeSgrMouseInput, type SgrMouseEvent, type SgrMouseHandler, } from "./mouse.ts";
|
|
19
18
|
export { StdinBuffer, type StdinBufferEventMap, type StdinBufferOptions, } from "./stdin-buffer.ts";
|
|
20
19
|
export { KITTY_KEYBOARD_SET_FLAGS, ProcessTerminal, type Terminal, } from "./terminal.ts";
|
|
21
20
|
export { parseOsc11BackgroundColor, parseTerminalColorSchemeReport, type RgbColor, type TerminalColorScheme, } from "./terminal-colors.ts";
|
|
22
21
|
export { deleteKittyImage, getCapabilities, isImageLine, setCellDimensions, } from "./terminal-image.ts";
|
|
23
22
|
export { setTextSizingEnabled, textSizingEnabled, textSizingSupported, } from "./text-sizing.ts";
|
|
23
|
+
export { obsidianDarkTheme, type TuiTheme, tuiTheme } from "./theme.ts";
|
|
24
24
|
export { type Component, Container, CURSOR_MARKER, type Focusable, type FramePlan, getNativeScrollbackLiveRegionStart, getRenderStablePrefixRows, type HistoryBatch, isFocusable, type NativeScrollbackCommittedRows, type NativeScrollbackLiveRegion, type NativeScrollbackReplay, type OverlayAnchor, type OverlayHandle, type OverlayMargin, type OverlayOptions, type OverlayUnfocusOptions, prepareNativeScrollbackReplay, type RenderStablePrefix, type SizeValue, setNativeScrollbackCommittedRows, type TerminalFrameProvider, TUI, type ViewportTailProvider, } from "./tui.ts";
|
|
25
25
|
export { applyBackgroundToLine, sliceByColumn, truncateToWidth, visibleWidth, wrapTextWithAnsi, } from "./utils.ts";
|
|
26
26
|
export { VirtualTerminal } from "./virtual-terminal.ts";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,4BAA4B,EAC5B,KAAK,YAAY,GAClB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EACL,MAAM,EACN,KAAK,aAAa,EAClB,KAAK,WAAW,GACjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EACL,MAAM,EACN,KAAK,sBAAsB,EAC3B,iBAAiB,EACjB,KAAK,WAAW,GACjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,gBAAgB,EACrB,QAAQ,EACR,KAAK,eAAe,EACpB,KAAK,aAAa,GACnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,KAAK,UAAU,EACf,UAAU,EACV,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,gCAAgC,GACtC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EACL,IAAI,EACJ,eAAe,EACf,gBAAgB,EAChB,KAAK,aAAa,GACnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAE/D,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,EACL,cAAc,EACd,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,kBAAkB,EAClB,cAAc,EACd,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,oBAAoB,EACpB,YAAY,EACZ,WAAW,EACX,qBAAqB,EACrB,GAAG,EACH,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,UAAU,EACV,QAAQ,EACR,sBAAsB,GACvB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -21,8 +21,6 @@ export { TruncatedText } from "./components/truncated-text.js";
|
|
|
21
21
|
export { getKeybindings, KeybindingsManager, setKeybindings, TUI_KEYBINDINGS, } from "./keybindings.js";
|
|
22
22
|
// Keyboard input handling
|
|
23
23
|
export { decodeKittyPrintable, isKeyRelease, isKeyRepeat, isKittyProtocolActive, Key, matchesKey, parseKey, setKittyProtocolActive, } from "./keys.js";
|
|
24
|
-
// SGR mouse reports (wheel scroll routing)
|
|
25
|
-
export { parseSgrMouse, routeSgrMouseInput, } from "./mouse.js";
|
|
26
24
|
// Input buffering for batch splitting
|
|
27
25
|
export { StdinBuffer, } from "./stdin-buffer.js";
|
|
28
26
|
// Terminal interface and implementations
|
|
@@ -32,6 +30,8 @@ export { parseOsc11BackgroundColor, parseTerminalColorSchemeReport, } from "./te
|
|
|
32
30
|
// Terminal image helpers (used internally by tui.ts)
|
|
33
31
|
export { deleteKittyImage, getCapabilities, isImageLine, setCellDimensions, } from "./terminal-image.js";
|
|
34
32
|
export { setTextSizingEnabled, textSizingEnabled, textSizingSupported, } from "./text-sizing.js";
|
|
33
|
+
// Theme tokens (default: omp obsidian dark)
|
|
34
|
+
export { obsidianDarkTheme, tuiTheme } from "./theme.js";
|
|
35
35
|
export { Container, CURSOR_MARKER, getNativeScrollbackLiveRegionStart, getRenderStablePrefixRows, isFocusable, prepareNativeScrollbackReplay, setNativeScrollbackCommittedRows, TUI, } from "./tui.js";
|
|
36
36
|
// Utilities
|
|
37
37
|
export { applyBackgroundToLine, sliceByColumn, truncateToWidth, visibleWidth, wrapTextWithAnsi, } from "./utils.js";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { describe, expect, test, vi } from "bun:test";
|
|
2
|
-
import { Loader } from "./components/loader.js";
|
|
2
|
+
import { Loader, SHIMMER_TIER_OPEN } from "./components/loader.js";
|
|
3
3
|
const ESC = String.fromCharCode(27);
|
|
4
4
|
/** Cell index of the bright (bold) sweep tier on the rendered line, or -1. */
|
|
5
5
|
function bandCell(line) {
|
|
6
|
-
return visibleIndex(line,
|
|
6
|
+
return visibleIndex(line, SHIMMER_TIER_OPEN.high);
|
|
7
7
|
}
|
|
8
8
|
/** The message row: Loader.render pads with a blank row above and below. */
|
|
9
9
|
function messageRow(loader) {
|
package/dist/mermaid.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mermaid.d.ts","sourceRoot":"","sources":["../src/mermaid.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,KAAK,kBAAkB,EAAsB,MAAM,iCAAiC,CAAC;AAE9F,YAAY,EAAE,kBAAkB,IAAI,yBAAyB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"mermaid.d.ts","sourceRoot":"","sources":["../src/mermaid.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,KAAK,kBAAkB,EAAsB,MAAM,iCAAiC,CAAC;AAE9F,YAAY,EAAE,kBAAkB,IAAI,yBAAyB,EAAE,CAAC;AA0ChE,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,kBAAkB,GAC3B,MAAM,GAAG,IAAI,CAMf;AAED,MAAM,WAAW,qBAAsB,SAAQ,kBAAkB;IAC/D,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,qBAAqB,GAC9B,MAAM,GAAG,IAAI,CA4Bf;AAED,uDAAuD;AACvD,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
|
package/dist/mermaid.js
CHANGED
|
@@ -7,7 +7,13 @@
|
|
|
7
7
|
* forced direction when the base layout overflows the requested maxWidth.
|
|
8
8
|
*/
|
|
9
9
|
import { renderMermaidASCII } from "./vendor/mermaid-ascii/index.js";
|
|
10
|
-
/** Memoized renders (and failures), keyed on source + options + direction.
|
|
10
|
+
/** Memoized renders (and failures), keyed on source + options + direction.
|
|
11
|
+
* Bounded: an assistant can emit unbounded distinct diagrams across a
|
|
12
|
+
* long session, and the cache holds rendered ASCII (plus failed renders)
|
|
13
|
+
* by strong reference — without a cap it grows until process exit.
|
|
14
|
+
* Insertion order gives a cheap FIFO eviction; re-hits do not reorder
|
|
15
|
+
* (ponytail: a true LRU matters only if diagrams repeat non-uniformly). */
|
|
16
|
+
const CACHE_CAP = 64;
|
|
11
17
|
const cache = new Map();
|
|
12
18
|
/** Widest rendered row in display columns (Bun wcwidth-style). */
|
|
13
19
|
function asciiDisplayWidth(ascii) {
|
|
@@ -27,6 +33,12 @@ function renderVariant(source, baseOptions, baseKey, direction) {
|
|
|
27
33
|
const options = direction ? { ...baseOptions, direction } : baseOptions;
|
|
28
34
|
const ascii = renderMermaidAsciiSafe(source, options);
|
|
29
35
|
cache.set(key, ascii);
|
|
36
|
+
while (cache.size > CACHE_CAP) {
|
|
37
|
+
const oldest = cache.keys().next().value;
|
|
38
|
+
if (oldest === undefined)
|
|
39
|
+
break;
|
|
40
|
+
cache.delete(oldest);
|
|
41
|
+
}
|
|
30
42
|
return ascii;
|
|
31
43
|
}
|
|
32
44
|
export function renderMermaidAsciiSafe(source, options) {
|
package/dist/stdin-buffer.d.ts
CHANGED
|
@@ -40,6 +40,9 @@ export declare class StdinBuffer extends EventEmitter<StdinBufferEventMap> {
|
|
|
40
40
|
private pasteBuffer;
|
|
41
41
|
private pendingKittyPrintableCodepoint;
|
|
42
42
|
private extendedEscFlush;
|
|
43
|
+
/** Survives across process() calls so a UTF-8 char split between two
|
|
44
|
+
* Buffer chunks decodes once, not as two replacement characters. */
|
|
45
|
+
private decoder;
|
|
43
46
|
constructor(options?: StdinBufferOptions);
|
|
44
47
|
process(data: string | Buffer): void;
|
|
45
48
|
private emitDataSequence;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdin-buffer.d.ts","sourceRoot":"","sources":["../src/stdin-buffer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;
|
|
1
|
+
{"version":3,"file":"stdin-buffer.d.ts","sourceRoot":"","sources":["../src/stdin-buffer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAgPtC,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC;IACf,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC;CACjB,CAAC;AAEF;;;GAGG;AACH,qBAAa,WAAY,SAAQ,YAAY,CAAC,mBAAmB,CAAC;IAChE,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,OAAO,CAA8C;IAC7D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,8BAA8B,CAAqB;IAC3D,OAAO,CAAC,gBAAgB,CAAS;IACjC;yEACqE;IACrE,OAAO,CAAC,OAAO,CAA8B;gBAEjC,OAAO,GAAE,kBAAuB;IAKrC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IA6H3C,OAAO,CAAC,gBAAgB;IAWxB,KAAK,IAAI,MAAM,EAAE;IAgBjB,KAAK,IAAI,IAAI;IAWb,SAAS,IAAI,MAAM;IAInB,OAAO,IAAI,IAAI;CAGhB"}
|
package/dist/stdin-buffer.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* Based on code from OpenTUI (https://github.com/anomalyco/opentui)
|
|
17
17
|
* MIT License - Copyright (c) 2025 opentui
|
|
18
18
|
*/
|
|
19
|
+
import { StringDecoder } from "node:string_decoder";
|
|
19
20
|
import { EventEmitter } from "events";
|
|
20
21
|
const ESC = "\x1b";
|
|
21
22
|
const BRACKETED_PASTE_START = "\x1b[200~";
|
|
@@ -231,6 +232,9 @@ export class StdinBuffer extends EventEmitter {
|
|
|
231
232
|
pasteBuffer = "";
|
|
232
233
|
pendingKittyPrintableCodepoint;
|
|
233
234
|
extendedEscFlush = false;
|
|
235
|
+
/** Survives across process() calls so a UTF-8 char split between two
|
|
236
|
+
* Buffer chunks decodes once, not as two replacement characters. */
|
|
237
|
+
decoder = null;
|
|
234
238
|
constructor(options = {}) {
|
|
235
239
|
super();
|
|
236
240
|
this.timeoutMs = options.timeout ?? 10;
|
|
@@ -241,16 +245,22 @@ export class StdinBuffer extends EventEmitter {
|
|
|
241
245
|
clearTimeout(this.timeout);
|
|
242
246
|
this.timeout = null;
|
|
243
247
|
}
|
|
244
|
-
// Handle high-byte conversion (for compatibility with parseKeypress)
|
|
245
|
-
// If buffer has single byte > 127, convert to ESC + (byte - 128)
|
|
248
|
+
// Handle high-byte conversion (for compatibility with parseKeypress).
|
|
249
|
+
// If buffer has single byte > 127, convert to ESC + (byte - 128).
|
|
250
|
+
// Everything else goes through a PERSISTENT StringDecoder: a UTF-8
|
|
251
|
+
// character split across two Buffer chunks must not decode as two
|
|
252
|
+
// replacement characters (emoji/CJK paste or fast typing).
|
|
246
253
|
let str;
|
|
247
254
|
if (Buffer.isBuffer(data)) {
|
|
248
255
|
if (data.length === 1 && data[0] > 127) {
|
|
249
256
|
const byte = data[0] - 128;
|
|
250
257
|
str = `\x1b${String.fromCharCode(byte)}`;
|
|
258
|
+
this.decoder = null; // resync: the hack consumed a raw byte
|
|
251
259
|
}
|
|
252
260
|
else {
|
|
253
|
-
|
|
261
|
+
if (!this.decoder)
|
|
262
|
+
this.decoder = new StringDecoder("utf8");
|
|
263
|
+
str = this.decoder.write(data);
|
|
254
264
|
}
|
|
255
265
|
}
|
|
256
266
|
else {
|
|
@@ -36,3 +36,18 @@ describe("StdinBuffer bare-ESC flush extension", () => {
|
|
|
36
36
|
expect(emitted).toEqual(["\x1b[99;1:3u"]);
|
|
37
37
|
});
|
|
38
38
|
});
|
|
39
|
+
describe("StdinBuffer cross-chunk UTF-8 (Buffer input)", () => {
|
|
40
|
+
test("a character split across two Buffer chunks decodes once", async () => {
|
|
41
|
+
const buf = new StdinBuffer({ timeout: 10 });
|
|
42
|
+
const emitted = [];
|
|
43
|
+
buf.on("data", (s) => emitted.push(s));
|
|
44
|
+
const bytes = Buffer.from("😀", "utf8"); // 4 code units
|
|
45
|
+
buf.process(bytes.subarray(0, 2));
|
|
46
|
+
buf.process(bytes.subarray(2));
|
|
47
|
+
await wait(30);
|
|
48
|
+
const joined = emitted.join("");
|
|
49
|
+
// Per-chunk toString() used to yield TWO replacement characters here.
|
|
50
|
+
expect(joined).toContain("😀");
|
|
51
|
+
expect(joined).not.toContain("\uFFFD");
|
|
52
|
+
});
|
|
53
|
+
});
|
package/dist/terminal.d.ts
CHANGED
package/dist/terminal.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../src/terminal.ts"],"names":[],"mappings":"AAeA;;gEAEgE;AAChE,eAAO,MAAM,wBAAwB,eAAoD,CAAC;AAI1F,MAAM,MAAM,mCAAmC,GAC3C;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,CAAC;AAElC,wBAAgB,wCAAwC,CACtD,QAAQ,EAAE,MAAM,GACf,mCAAmC,GAAG,SAAS,CASjD;AAMD,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,OAAO,EACxB,cAAc,EAAE,OAAO,GACtB,MAAM,CAIR;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IAEvB,KAAK,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAGnE,IAAI,IAAI,IAAI,CAAC;IAEb;;;;;OAKG;IACH,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAG3D,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAG1B,IAAI,OAAO,IAAI,MAAM,CAAC;IACtB,IAAI,IAAI,IAAI,MAAM,CAAC;IAGnB,IAAI,mBAAmB,IAAI,OAAO,CAAC;IAGnC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAG5B,UAAU,IAAI,IAAI,CAAC;IACnB,UAAU,IAAI,IAAI,CAAC;IAEnB;;;;;;;OAOG;IACH,qBAAqB,IAAI,IAAI,CAAC;IAG9B,SAAS,IAAI,IAAI,CAAC;IAClB,eAAe,IAAI,IAAI,CAAC;IACxB,WAAW,IAAI,IAAI,CAAC;IAGpB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAG9B,WAAW,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;CACpC;AAED;;GAEG;AACH,qBAAa,eAAgB,YAAW,QAAQ;IAC9C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAC,CAAyB;IAC9C,OAAO,CAAC,aAAa,CAAC,CAAa;IACnC,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,sBAAsB,CAAS;IACvC,OAAO,CAAC,sBAAsB,CAAS;IACvC,OAAO,CAAC,iCAAiC,CAAM;IAC/C,OAAO,CAAC,gCAAgC,CAAC,CAAgC;IACzE,OAAO,CAAC,WAAW,CAAC,CAAc;IAClC,OAAO,CAAC,gBAAgB,CAAC,CAAyB;IAClD,OAAO,CAAC,gBAAgB,CAAC,CAAiC;IAC1D,OAAO,CAAC,YAAY,CAaf;IAEL,IAAI,mBAAmB,IAAI,OAAO,CAEjC;IAED,IAAI,qBAAqB,IAAI,OAAO,CAEnC;IAED,KAAK,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../src/terminal.ts"],"names":[],"mappings":"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"}
|
package/dist/terminal.js
CHANGED
|
@@ -43,6 +43,8 @@ export function normalizeAppleTerminalInput(data, isAppleTerminal, isShiftPresse
|
|
|
43
43
|
*/
|
|
44
44
|
export class ProcessTerminal {
|
|
45
45
|
wasRaw = false;
|
|
46
|
+
wasEncoding = null;
|
|
47
|
+
wasFlowing = null;
|
|
46
48
|
inputHandler;
|
|
47
49
|
resizeHandler;
|
|
48
50
|
_kittyProtocolActive = false;
|
|
@@ -78,8 +80,13 @@ export class ProcessTerminal {
|
|
|
78
80
|
start(onInput, onResize) {
|
|
79
81
|
this.inputHandler = onInput;
|
|
80
82
|
this.resizeHandler = onResize;
|
|
81
|
-
// Save previous state and enable raw mode
|
|
83
|
+
// Save previous state and enable raw mode. Encoding and flow state are
|
|
84
|
+
// saved too: as a LIBRARY, stop() must leave stdin the way it found it —
|
|
85
|
+
// an embedder's next readline/prompt would otherwise sit on a paused,
|
|
86
|
+
// forced-UTF8 stream (audit P2).
|
|
82
87
|
this.wasRaw = process.stdin.isRaw || false;
|
|
88
|
+
this.wasEncoding = process.stdin.readableEncoding;
|
|
89
|
+
this.wasFlowing = process.stdin.readableFlowing;
|
|
83
90
|
if (process.stdin.setRawMode) {
|
|
84
91
|
process.stdin.setRawMode(true);
|
|
85
92
|
}
|
|
@@ -362,6 +369,14 @@ export class ProcessTerminal {
|
|
|
362
369
|
if (process.stdin.setRawMode) {
|
|
363
370
|
process.stdin.setRawMode(this.wasRaw);
|
|
364
371
|
}
|
|
372
|
+
// Restore the encoding/flow we borrowed. Flow: resume only if the
|
|
373
|
+
// stream was flowing before us. Encoding: a null (Buffer-mode) restore
|
|
374
|
+
// is not expressible in the typed surface (setEncoding lacks null);
|
|
375
|
+
// utf8-mode stdin is compatible with readline/prompt, so leaving it is
|
|
376
|
+
// the documented ceiling rather than a cast around the type.
|
|
377
|
+
process.stdin.setEncoding(this.wasEncoding ?? undefined);
|
|
378
|
+
if (this.wasFlowing)
|
|
379
|
+
process.stdin.resume();
|
|
365
380
|
}
|
|
366
381
|
write(data) {
|
|
367
382
|
process.stdout.write(data);
|
package/dist/theme.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** TUI color tokens. Every SGR color decision in the TUI routes through
|
|
2
|
+
* `tuiTheme`, so a future theme feature swaps this one object instead of
|
|
3
|
+
* hunting escape codes across renderers.
|
|
4
|
+
*
|
|
5
|
+
* The default theme ports omp's "obsidian dark" palette (oh-my-pi
|
|
6
|
+
* theme/defaults/obsidian.json): warm-black neutrals, a violet accent, jade
|
|
7
|
+
* success, crimson error. Values are 24-bit-color SGR strings; terminals
|
|
8
|
+
* without truecolor degrade per their own palette. Attributes (bold,
|
|
9
|
+
* italic, underline, strike) are NOT themed — a theme recolors, it does not
|
|
10
|
+
* restyle structure.
|
|
11
|
+
*
|
|
12
|
+
* Ten color tokens, each a ROLE a renderer can name without knowing the
|
|
13
|
+
* palette: one brand accent, three verdict colors, one informational, two
|
|
14
|
+
* text tiers, three surfaces. Anything finer (a second orange, a separate
|
|
15
|
+
* heading tint) was tried and collapsed — tokens nobody can name from the
|
|
16
|
+
* sitting surface are taxonomy, not theme. */
|
|
17
|
+
export interface TuiTheme {
|
|
18
|
+
/** Brand accent: block titles, spinner + sweep band, selected markers,
|
|
19
|
+
* inline code, the banner. obsidian violet. */
|
|
20
|
+
readonly accent: string;
|
|
21
|
+
/** Paths, links, notice lines, informational chrome. obsidian cyan. */
|
|
22
|
+
readonly info: string;
|
|
23
|
+
/** Success marks, diff added, clean git. obsidian jade. */
|
|
24
|
+
readonly success: string;
|
|
25
|
+
/** Errors, failures, diff removed. obsidian crimson. */
|
|
26
|
+
readonly error: string;
|
|
27
|
+
/** Warnings and pressure (dirty git, hot context). obsidian gold. */
|
|
28
|
+
readonly warning: string;
|
|
29
|
+
/** Secondary text: timestamps, meta, settled rows, hints, quotes. */
|
|
30
|
+
readonly dim: string;
|
|
31
|
+
/** Faintest marks: markdown markers, hr, quote bars — structure that
|
|
32
|
+
* should sit below the dim tier. */
|
|
33
|
+
readonly faint: string;
|
|
34
|
+
/** Selected-row / chip / meter surface. obsidian glass. Inside an overlay
|
|
35
|
+
* this is ALSO the selection contrast against bgOverlay. */
|
|
36
|
+
readonly bgPanel: string;
|
|
37
|
+
/** Full-overlay surface. obsidian smoke. */
|
|
38
|
+
readonly bgOverlay: string;
|
|
39
|
+
/** "Running jobs" chip surface — jade sunk toward the panel tone. */
|
|
40
|
+
readonly bgChipOk: string;
|
|
41
|
+
}
|
|
42
|
+
export declare const obsidianDarkTheme: TuiTheme;
|
|
43
|
+
/** The active theme. Single swap point for the future theme feature
|
|
44
|
+
* (settings key → assign another TuiTheme here, re-render). */
|
|
45
|
+
export declare const tuiTheme: TuiTheme;
|
|
46
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;+CAe+C;AAE/C,MAAM,WAAW,QAAQ;IACvB;oDACgD;IAChD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;yCACqC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;iEAC6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,4CAA4C;IAC5C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AA0BD,eAAO,MAAM,iBAAiB,EAAE,QAW/B,CAAC;AAEF;gEACgE;AAChE,eAAO,MAAM,QAAQ,EAAE,QAA4B,CAAC"}
|
package/dist/theme.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** TUI color tokens. Every SGR color decision in the TUI routes through
|
|
2
|
+
* `tuiTheme`, so a future theme feature swaps this one object instead of
|
|
3
|
+
* hunting escape codes across renderers.
|
|
4
|
+
*
|
|
5
|
+
* The default theme ports omp's "obsidian dark" palette (oh-my-pi
|
|
6
|
+
* theme/defaults/obsidian.json): warm-black neutrals, a violet accent, jade
|
|
7
|
+
* success, crimson error. Values are 24-bit-color SGR strings; terminals
|
|
8
|
+
* without truecolor degrade per their own palette. Attributes (bold,
|
|
9
|
+
* italic, underline, strike) are NOT themed — a theme recolors, it does not
|
|
10
|
+
* restyle structure.
|
|
11
|
+
*
|
|
12
|
+
* Ten color tokens, each a ROLE a renderer can name without knowing the
|
|
13
|
+
* palette: one brand accent, three verdict colors, one informational, two
|
|
14
|
+
* text tiers, three surfaces. Anything finer (a second orange, a separate
|
|
15
|
+
* heading tint) was tried and collapsed — tokens nobody can name from the
|
|
16
|
+
* sitting surface are taxonomy, not theme. */
|
|
17
|
+
/** "#rrggbb" → 24-bit foreground SGR. Module-private: themes are declared as
|
|
18
|
+
* hex constants and materialized once; call sites never build SGR strings. */
|
|
19
|
+
function fg(hex) {
|
|
20
|
+
return `\u001b[38;2;${parseInt(hex.slice(1, 3), 16)};${parseInt(hex.slice(3, 5), 16)};${parseInt(hex.slice(5, 7), 16)}m`;
|
|
21
|
+
}
|
|
22
|
+
/** "#rrggbb" → 24-bit background SGR. */
|
|
23
|
+
function bg(hex) {
|
|
24
|
+
return `\u001b[48;2;${parseInt(hex.slice(1, 3), 16)};${parseInt(hex.slice(3, 5), 16)};${parseInt(hex.slice(5, 7), 16)}m`;
|
|
25
|
+
}
|
|
26
|
+
/** omp obsidian dark, as hex — kept visible for diffing against upstream. */
|
|
27
|
+
const OBSIDIAN = {
|
|
28
|
+
glass: "#1a1816",
|
|
29
|
+
smoke: "#2b2825",
|
|
30
|
+
violet: "#9d7aff",
|
|
31
|
+
jade: "#52e8a0",
|
|
32
|
+
crimson: "#ff5570",
|
|
33
|
+
cyan: "#5cd9ff",
|
|
34
|
+
gold: "#ffc942",
|
|
35
|
+
muted: "#8a857f",
|
|
36
|
+
dim: "#4a4642",
|
|
37
|
+
};
|
|
38
|
+
export const obsidianDarkTheme = {
|
|
39
|
+
accent: fg(OBSIDIAN.violet),
|
|
40
|
+
info: fg(OBSIDIAN.cyan),
|
|
41
|
+
success: fg(OBSIDIAN.jade),
|
|
42
|
+
error: fg(OBSIDIAN.crimson),
|
|
43
|
+
warning: fg(OBSIDIAN.gold),
|
|
44
|
+
dim: fg(OBSIDIAN.muted),
|
|
45
|
+
faint: fg(OBSIDIAN.dim),
|
|
46
|
+
bgPanel: bg(OBSIDIAN.glass),
|
|
47
|
+
bgOverlay: bg(OBSIDIAN.smoke),
|
|
48
|
+
bgChipOk: bg("#20362b"),
|
|
49
|
+
};
|
|
50
|
+
/** The active theme. Single swap point for the future theme feature
|
|
51
|
+
* (settings key → assign another TuiTheme here, re-render). */
|
|
52
|
+
export const tuiTheme = obsidianDarkTheme;
|
|
@@ -48,6 +48,98 @@ describe("TUI provider native scrollback", () => {
|
|
|
48
48
|
expect(scroll.filter((l) => l.startsWith("H"))).toEqual(["H0", "H1", "H2"]);
|
|
49
49
|
expect(vt.getViewport().slice(-5)).toEqual(["V0", "V1", "V2", "V3", "V4"]);
|
|
50
50
|
});
|
|
51
|
+
test("requestRender(true) repaints the screen but never purges scrollback", async () => {
|
|
52
|
+
const vt = new VirtualTerminal(20, 5);
|
|
53
|
+
const tui = new TUI(vt);
|
|
54
|
+
let frame = 0;
|
|
55
|
+
tui.setFrameProvider({
|
|
56
|
+
renderFrame() {
|
|
57
|
+
frame++;
|
|
58
|
+
const viewport = frame <= 2 ? ["V0", "V1", "V2", "V3", "V4"] : ["W0", "W1", "W2", "W3", "W4"];
|
|
59
|
+
if (frame === 1)
|
|
60
|
+
return { viewport, history: { id: 1, rows: ["H0", "H1"] } };
|
|
61
|
+
return { viewport };
|
|
62
|
+
},
|
|
63
|
+
acknowledgeHistory() { },
|
|
64
|
+
});
|
|
65
|
+
tui.start();
|
|
66
|
+
// frame 1 carries history, its ack recurses into frame 2; the frame
|
|
67
|
+
// counter is the deterministic drain signal.
|
|
68
|
+
while (frame < 2)
|
|
69
|
+
await vt.waitForRender();
|
|
70
|
+
expect(vt.getScrollBuffer().some((l) => l.startsWith("H0"))).toBe(true);
|
|
71
|
+
// The production triggers: transcript reconcile reset (/new, resume)
|
|
72
|
+
// and PTY overlay exit. Faking a width change here used to emit CSI 3 J
|
|
73
|
+
// and wipe the committed history.
|
|
74
|
+
tui.requestRender(true);
|
|
75
|
+
while (frame < 3)
|
|
76
|
+
await vt.waitForRender();
|
|
77
|
+
expect(vt.getScrollBuffer().some((l) => l.startsWith("H0"))).toBe(true);
|
|
78
|
+
expect(vt.getViewport().some((l) => l.startsWith("W0"))).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
test("a real width change replays the committed history at the new width", async () => {
|
|
81
|
+
const vt = new VirtualTerminal(20, 5);
|
|
82
|
+
const tui = new TUI(vt);
|
|
83
|
+
let replayed = 0;
|
|
84
|
+
let frame = 0;
|
|
85
|
+
let frontier = 0;
|
|
86
|
+
let nextId = 1;
|
|
87
|
+
let historyRows = ["H0-0123456789abcdef", "H1-0123456789abcdef"];
|
|
88
|
+
tui.setFrameProvider({
|
|
89
|
+
beginHistoryReplay() {
|
|
90
|
+
replayed++;
|
|
91
|
+
frontier = 0;
|
|
92
|
+
nextId = 100;
|
|
93
|
+
// Re-laid-out at the new width, like a re-wrapping transcript.
|
|
94
|
+
historyRows = ["H0-0123", "H1-0123"];
|
|
95
|
+
},
|
|
96
|
+
renderFrame() {
|
|
97
|
+
frame++;
|
|
98
|
+
if (frontier < historyRows.length) {
|
|
99
|
+
const rows = historyRows.slice(frontier);
|
|
100
|
+
frontier += rows.length;
|
|
101
|
+
return { viewport: ["V*"], history: { id: nextId++, rows } };
|
|
102
|
+
}
|
|
103
|
+
return { viewport: ["V*"] };
|
|
104
|
+
},
|
|
105
|
+
acknowledgeHistory() { },
|
|
106
|
+
});
|
|
107
|
+
tui.start();
|
|
108
|
+
while (frame < 2)
|
|
109
|
+
await vt.waitForRender();
|
|
110
|
+
expect(vt.getScrollBuffer().some((l) => l.includes("H0-0123456789abcdef"))).toBe(true);
|
|
111
|
+
vt.resize(10, 5);
|
|
112
|
+
// Replay frame re-offers the whole prefix (frame 3) and its ack recurses
|
|
113
|
+
// once more (frame 4) before the stream settles.
|
|
114
|
+
while (frame < 4)
|
|
115
|
+
await vt.waitForRender();
|
|
116
|
+
// The purge happened (old-width rows gone) but the provider replayed
|
|
117
|
+
// its committed prefix, so the history survives re-wrapped.
|
|
118
|
+
expect(replayed).toBe(1);
|
|
119
|
+
const scroll = vt.getScrollBuffer().join("\n");
|
|
120
|
+
expect(scroll).not.toContain("H0-0123456789abcdef");
|
|
121
|
+
expect(scroll).toContain("H0-0123");
|
|
122
|
+
});
|
|
123
|
+
test("stop() flushes the frame provider (not only root children)", async () => {
|
|
124
|
+
const vt = new VirtualTerminal(20, 5);
|
|
125
|
+
const tui = new TUI(vt);
|
|
126
|
+
let flushed = 0;
|
|
127
|
+
tui.setFrameProvider({
|
|
128
|
+
renderFrame() {
|
|
129
|
+
return { viewport: ["V0", "V1", "V2", "V3", "V4"] };
|
|
130
|
+
},
|
|
131
|
+
acknowledgeHistory() { },
|
|
132
|
+
beginHistoryFlush() {
|
|
133
|
+
flushed++;
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
tui.start();
|
|
137
|
+
await vt.waitForRender();
|
|
138
|
+
tui.stop();
|
|
139
|
+
// The provider is not a root child; without the explicit call its
|
|
140
|
+
// pending history batch never drained on exit.
|
|
141
|
+
expect(flushed).toBe(1);
|
|
142
|
+
});
|
|
51
143
|
});
|
|
52
144
|
describe("adaptive render backpressure (omp #4145 port)", () => {
|
|
53
145
|
test("a slow frame pushes the next ordinary paint out proportionally", async () => {
|
package/dist/tui.d.ts
CHANGED
|
@@ -220,6 +220,9 @@ export declare class TUI extends Container {
|
|
|
220
220
|
private providerForceRepaint;
|
|
221
221
|
private fullRedrawCount;
|
|
222
222
|
private stopped;
|
|
223
|
+
/** True once stop() ran: late async teardown (a pty overlay's deferred
|
|
224
|
+
* cleanup) must not write terminal modes into the user's restored shell. */
|
|
225
|
+
get isStopped(): boolean;
|
|
223
226
|
private pendingOsc11BackgroundReplies;
|
|
224
227
|
private pendingOsc11BackgroundQueries;
|
|
225
228
|
private terminalColorSchemeListeners;
|
package/dist/tui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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"}
|
package/dist/tui.js
CHANGED
|
@@ -155,6 +155,11 @@ export class TUI extends Container {
|
|
|
155
155
|
providerForceRepaint = false;
|
|
156
156
|
fullRedrawCount = 0;
|
|
157
157
|
stopped = false;
|
|
158
|
+
/** True once stop() ran: late async teardown (a pty overlay's deferred
|
|
159
|
+
* cleanup) must not write terminal modes into the user's restored shell. */
|
|
160
|
+
get isStopped() {
|
|
161
|
+
return this.stopped;
|
|
162
|
+
}
|
|
158
163
|
pendingOsc11BackgroundReplies = 0;
|
|
159
164
|
pendingOsc11BackgroundQueries = [];
|
|
160
165
|
terminalColorSchemeListeners = new Set();
|
|
@@ -518,6 +523,9 @@ export class TUI extends Container {
|
|
|
518
523
|
for (const child of this.children) {
|
|
519
524
|
child.beginHistoryFlush?.();
|
|
520
525
|
}
|
|
526
|
+
// The frame provider is NOT a root child — flush it explicitly, or the
|
|
527
|
+
// provider's pending history batch never reaches the scrollback on exit.
|
|
528
|
+
this.frameProvider?.beginHistoryFlush?.();
|
|
521
529
|
if (this.renderTimer) {
|
|
522
530
|
clearTimeout(this.renderTimer);
|
|
523
531
|
this.renderTimer = undefined;
|
|
@@ -537,18 +545,31 @@ export class TUI extends Container {
|
|
|
537
545
|
}
|
|
538
546
|
this.terminal.write("\r\n");
|
|
539
547
|
}
|
|
548
|
+
else if (this.frameProvider && this.providerWindow.length > 0) {
|
|
549
|
+
// Provider mode never fills previousLines; the last frame placed the
|
|
550
|
+
// viewport at providerViewportTop. Park below it so shell output after
|
|
551
|
+
// exit does not land on the last frame's row.
|
|
552
|
+
const lastRow = this.providerViewportTop + this.providerWindow.length;
|
|
553
|
+
this.terminal.write(`\x1b[${lastRow + 1};1H`);
|
|
554
|
+
this.terminal.write("\r\n");
|
|
555
|
+
}
|
|
540
556
|
this.terminal.showCursor();
|
|
541
557
|
this.terminal.stop();
|
|
542
558
|
}
|
|
543
559
|
requestRender(force = false) {
|
|
544
560
|
if (force) {
|
|
561
|
+
// Forced repaint clears the SCREEN, never the user's native
|
|
562
|
+
// scrollback. Faking a resize here (previousWidth=-1) used to make
|
|
563
|
+
// the renderer treat it as a width change and purge scrollback with
|
|
564
|
+
// CSI 3 J — after a transcript reset or a PTY overlay exit the
|
|
565
|
+
// committed history vanished. providerForceRepaint drives the clear
|
|
566
|
+
// in both render paths; only a REAL width change may purge.
|
|
545
567
|
this.previousLines = [];
|
|
546
|
-
this.previousWidth = -1; // -1 triggers widthChanged, forcing a full clear
|
|
547
|
-
this.previousHeight = -1; // -1 triggers heightChanged, forcing a full clear
|
|
548
568
|
this.cursorRow = 0;
|
|
549
569
|
this.hardwareCursorRow = 0;
|
|
550
570
|
this.maxLinesRendered = 0;
|
|
551
571
|
this.previousViewportTop = 0;
|
|
572
|
+
this.providerForceRepaint = true;
|
|
552
573
|
if (this.renderTimer) {
|
|
553
574
|
clearTimeout(this.renderTimer);
|
|
554
575
|
this.renderTimer = undefined;
|
|
@@ -1054,6 +1075,13 @@ export class TUI extends Container {
|
|
|
1054
1075
|
const provider = this.frameProvider;
|
|
1055
1076
|
if (!provider || width <= 0 || height <= 0)
|
|
1056
1077
|
return;
|
|
1078
|
+
// A REAL width change rewraps everything; the purge below (CSI 3 J)
|
|
1079
|
+
// drops the old-width scrollback rows, so the provider must replay its
|
|
1080
|
+
// committed prefix at the new width first or that history is lost
|
|
1081
|
+
// forever (the provider's frontier still says "already delivered").
|
|
1082
|
+
if (this.previousWidth !== 0 && this.previousWidth !== width) {
|
|
1083
|
+
provider.beginHistoryReplay?.();
|
|
1084
|
+
}
|
|
1057
1085
|
const plan = provider.renderFrame({ columns: width, rows: height });
|
|
1058
1086
|
let viewport = [...plan.viewport];
|
|
1059
1087
|
if (viewport.length > height)
|
|
@@ -1083,8 +1111,14 @@ export class TUI extends Container {
|
|
|
1083
1111
|
: Math.min(this.providerViewportTop, Math.max(0, height - 1));
|
|
1084
1112
|
const newTop = Math.max(0, Math.min(startTop + historyRows.length, height - rows));
|
|
1085
1113
|
let buffer = "\x1b[?2026h";
|
|
1086
|
-
if (destructiveReset)
|
|
1087
|
-
buffer += "\x1b[H\x1b[
|
|
1114
|
+
if (destructiveReset) {
|
|
1115
|
+
buffer += "\x1b[H\x1b[2J";
|
|
1116
|
+
// Purge scrollback only when a rewrap actually misaligns the rows
|
|
1117
|
+
// above (width change). A plain repaint reset (didReset from the
|
|
1118
|
+
// reconciler) must keep the user's committed history.
|
|
1119
|
+
if (widthChanged)
|
|
1120
|
+
buffer += "\x1b[3J";
|
|
1121
|
+
}
|
|
1088
1122
|
// Frame advance = history rows appended this frame. After those appends
|
|
1089
1123
|
// the screen content that sits under new viewport slot i is the OLD
|
|
1090
1124
|
// window's row (i + advance) — both when the appends scrolled the
|
|
@@ -1272,6 +1306,15 @@ export class TUI extends Container {
|
|
|
1272
1306
|
const msg = `[${new Date().toISOString()}] fullRender: ${reason} (prev=${this.previousLines.length}, new=${newLines.length}, height=${height})\n`;
|
|
1273
1307
|
fs.appendFileSync(logPath, msg);
|
|
1274
1308
|
};
|
|
1309
|
+
// Forced repaint (requestRender(true)): full clear of the SCREEN, but
|
|
1310
|
+
// the user's native scrollback survives — only a real width change
|
|
1311
|
+
// takes the clearScrollback route below.
|
|
1312
|
+
if (this.providerForceRepaint) {
|
|
1313
|
+
logRedraw("forced repaint");
|
|
1314
|
+
fullRender(true);
|
|
1315
|
+
this.providerForceRepaint = false;
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1275
1318
|
// First render - just output everything without clearing (assumes clean screen)
|
|
1276
1319
|
if (this.previousLines.length === 0 && !widthChanged && !heightChanged) {
|
|
1277
1320
|
logRedraw("first render");
|
package/package.json
CHANGED
package/dist/mouse.d.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/** SGR mouse report parsing (`\x1b[<button;col;rowM` / `…m`).
|
|
2
|
-
*
|
|
3
|
-
* Mouse tracking (modes 1000 + 1006) is enabled by the APPLICATION (oma
|
|
4
|
-
* enables it for the whole session so the wheel can scroll the transcript —
|
|
5
|
-
* our TUI keeps no native-scrollback copy of history). Consumers get 0-based
|
|
6
|
-
* col/row for direct indexing into rendered lines.
|
|
7
|
-
*
|
|
8
|
-
* ponytail: wheel-only consumer for now; click/hover routing (pi's
|
|
9
|
-
* SelectListMouseTarget helpers) can be ported when an overlay needs it.
|
|
10
|
-
*
|
|
11
|
-
* Ported from pi's packages/tui/src/mouse.ts. */
|
|
12
|
-
/** A decoded SGR mouse report. */
|
|
13
|
-
export interface SgrMouseEvent {
|
|
14
|
-
/** Raw button code (bit 32 = motion, bit 64 = wheel, low bits = button). */
|
|
15
|
-
button: number;
|
|
16
|
-
/** 0-based column of the event. */
|
|
17
|
-
col: number;
|
|
18
|
-
/** 0-based row of the event. */
|
|
19
|
-
row: number;
|
|
20
|
-
/** True for a release report (`m` suffix). */
|
|
21
|
-
release: boolean;
|
|
22
|
-
/** Wheel direction: -1 up, 1 down, null when not a wheel event. */
|
|
23
|
-
wheel: -1 | 1 | null;
|
|
24
|
-
/** True when the pointer moved (hover or drag) rather than clicked. */
|
|
25
|
-
motion: boolean;
|
|
26
|
-
/** True for a left-button press (not motion, not release, not wheel). */
|
|
27
|
-
leftClick: boolean;
|
|
28
|
-
}
|
|
29
|
-
/** Decode an SGR mouse report, or return null when `data` is not one.
|
|
30
|
-
* Callers on hot keypress paths should pre-check `data.startsWith("\x1b[<")`
|
|
31
|
-
* before paying for the regex. */
|
|
32
|
-
export declare function parseSgrMouse(data: string): SgrMouseEvent | null;
|
|
33
|
-
/** Handler invoked with a decoded SGR event; returning `false` reports unhandled. */
|
|
34
|
-
export type SgrMouseHandler = (event: SgrMouseEvent) => boolean | undefined;
|
|
35
|
-
/** Decode an SGR mouse report and forward it to `handler`. Returns `false`
|
|
36
|
-
* when `data` is not an SGR mouse report (or fails to parse), so callers can
|
|
37
|
-
* fall through to other input handling. Centralizes the repeated
|
|
38
|
-
* `data.startsWith("\x1b[<")` + `parseSgrMouse()` pattern. */
|
|
39
|
-
export declare function routeSgrMouseInput(data: string, handler: SgrMouseHandler): boolean;
|
|
40
|
-
//# sourceMappingURL=mouse.d.ts.map
|
package/dist/mouse.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mouse.d.ts","sourceRoot":"","sources":["../src/mouse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;iDAUiD;AAEjD,kCAAkC;AAClC,MAAM,WAAW,aAAa;IAC5B,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,mEAAmE;IACnE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IACrB,uEAAuE;IACvE,MAAM,EAAE,OAAO,CAAC;IAChB,yEAAyE;IACzE,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;mCAEmC;AACnC,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAWhE;AAED,qFAAqF;AACrF,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,GAAG,SAAS,CAAC;AAE5E;;;+DAG+D;AAC/D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAKlF"}
|
package/dist/mouse.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/** SGR mouse report parsing (`\x1b[<button;col;rowM` / `…m`).
|
|
2
|
-
*
|
|
3
|
-
* Mouse tracking (modes 1000 + 1006) is enabled by the APPLICATION (oma
|
|
4
|
-
* enables it for the whole session so the wheel can scroll the transcript —
|
|
5
|
-
* our TUI keeps no native-scrollback copy of history). Consumers get 0-based
|
|
6
|
-
* col/row for direct indexing into rendered lines.
|
|
7
|
-
*
|
|
8
|
-
* ponytail: wheel-only consumer for now; click/hover routing (pi's
|
|
9
|
-
* SelectListMouseTarget helpers) can be ported when an overlay needs it.
|
|
10
|
-
*
|
|
11
|
-
* Ported from pi's packages/tui/src/mouse.ts. */
|
|
12
|
-
/** Decode an SGR mouse report, or return null when `data` is not one.
|
|
13
|
-
* Callers on hot keypress paths should pre-check `data.startsWith("\x1b[<")`
|
|
14
|
-
* before paying for the regex. */
|
|
15
|
-
export function parseSgrMouse(data) {
|
|
16
|
-
const match = /^\x1b\[<(\d+);(\d+);(\d+)([Mm])$/.exec(data);
|
|
17
|
-
if (!match)
|
|
18
|
-
return null;
|
|
19
|
-
const button = Number(match[1]);
|
|
20
|
-
const col = Number(match[2]) - 1;
|
|
21
|
-
const row = Number(match[3]) - 1;
|
|
22
|
-
const release = match[4] === "m";
|
|
23
|
-
const wheel = button & 64 ? (button & 1 ? 1 : -1) : null;
|
|
24
|
-
const motion = (button & 32) !== 0 && wheel === null;
|
|
25
|
-
const leftClick = !release && wheel === null && !motion && (button & 3) === 0;
|
|
26
|
-
return { button, col, row, release, wheel, motion, leftClick };
|
|
27
|
-
}
|
|
28
|
-
/** Decode an SGR mouse report and forward it to `handler`. Returns `false`
|
|
29
|
-
* when `data` is not an SGR mouse report (or fails to parse), so callers can
|
|
30
|
-
* fall through to other input handling. Centralizes the repeated
|
|
31
|
-
* `data.startsWith("\x1b[<")` + `parseSgrMouse()` pattern. */
|
|
32
|
-
export function routeSgrMouseInput(data, handler) {
|
|
33
|
-
if (!data.startsWith("\x1b[<"))
|
|
34
|
-
return false;
|
|
35
|
-
const event = parseSgrMouse(data);
|
|
36
|
-
if (!event)
|
|
37
|
-
return false;
|
|
38
|
-
return handler(event) !== false;
|
|
39
|
-
}
|
package/dist/mouse.test.d.ts
DELETED
package/dist/mouse.test.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mouse.test.d.ts","sourceRoot":"","sources":["../src/mouse.test.ts"],"names":[],"mappings":""}
|
package/dist/mouse.test.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import { parseSgrMouse, routeSgrMouseInput } from "./mouse.js";
|
|
3
|
-
describe("parseSgrMouse", () => {
|
|
4
|
-
test("wheel up (button 64) and wheel down (button 65)", () => {
|
|
5
|
-
const up = parseSgrMouse("\x1b[<64;10;5M");
|
|
6
|
-
expect(up).toMatchObject({ button: 64, col: 9, row: 4, wheel: -1, release: false });
|
|
7
|
-
const down = parseSgrMouse("\x1b[<65;1;1M");
|
|
8
|
-
expect(down).toMatchObject({ button: 65, wheel: 1, col: 0, row: 0 });
|
|
9
|
-
});
|
|
10
|
-
test("left click press vs release vs motion", () => {
|
|
11
|
-
expect(parseSgrMouse("\x1b[<0;3;3M")).toMatchObject({ leftClick: true, motion: false });
|
|
12
|
-
expect(parseSgrMouse("\x1b[<0;3;3m")).toMatchObject({ release: true, leftClick: false });
|
|
13
|
-
expect(parseSgrMouse("\x1b[<32;3;3M")).toMatchObject({ motion: true, leftClick: false });
|
|
14
|
-
});
|
|
15
|
-
test("non-mouse input returns null", () => {
|
|
16
|
-
expect(parseSgrMouse("\x1b[A")).toBeNull();
|
|
17
|
-
expect(parseSgrMouse("\x1b[5~")).toBeNull();
|
|
18
|
-
expect(parseSgrMouse("x")).toBeNull();
|
|
19
|
-
});
|
|
20
|
-
});
|
|
21
|
-
describe("routeSgrMouseInput", () => {
|
|
22
|
-
test("routes wheel and reports consumed; falls through on other input", () => {
|
|
23
|
-
const wheels = [];
|
|
24
|
-
const consumed = routeSgrMouseInput("\x1b[<64;1;1M", (event) => {
|
|
25
|
-
if (event.wheel)
|
|
26
|
-
wheels.push(event.wheel);
|
|
27
|
-
return true;
|
|
28
|
-
});
|
|
29
|
-
expect(consumed).toBe(true);
|
|
30
|
-
// Not an SGR report: handler must not run.
|
|
31
|
-
expect(routeSgrMouseInput("\x1b[5~", () => {
|
|
32
|
-
wheels.push(99);
|
|
33
|
-
})).toBe(false);
|
|
34
|
-
expect(wheels).toEqual([-1]);
|
|
35
|
-
});
|
|
36
|
-
});
|