@earendil-works/pi-tui 0.87.0 → 0.99.0
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/README.md +49 -5
- package/dist/alt-screen-search.d.ts.map +1 -1
- package/dist/alt-screen-search.js.map +1 -1
- package/dist/autocomplete.d.ts +1 -1
- package/dist/autocomplete.d.ts.map +1 -1
- package/dist/autocomplete.js +28 -8
- package/dist/autocomplete.js.map +1 -1
- package/dist/colors.d.ts +73 -0
- package/dist/colors.d.ts.map +1 -0
- package/dist/colors.js +273 -0
- package/dist/colors.js.map +1 -0
- package/dist/components/alt-screen-flash.d.ts.map +1 -1
- package/dist/components/alt-screen-flash.js.map +1 -1
- package/dist/components/box.d.ts.map +1 -1
- package/dist/components/box.js +8 -8
- package/dist/components/box.js.map +1 -1
- package/dist/components/cancellable-loader.d.ts.map +1 -1
- package/dist/components/cancellable-loader.js.map +1 -1
- package/dist/components/editor.d.ts.map +1 -1
- package/dist/components/editor.js +4 -2
- package/dist/components/editor.js.map +1 -1
- package/dist/components/h-stack.d.ts.map +1 -1
- package/dist/components/h-stack.js.map +1 -1
- package/dist/components/image.d.ts.map +1 -1
- package/dist/components/image.js.map +1 -1
- package/dist/components/input.d.ts.map +1 -1
- package/dist/components/input.js.map +1 -1
- package/dist/components/loader.d.ts.map +1 -1
- package/dist/components/loader.js.map +1 -1
- package/dist/components/markdown.d.ts +1 -0
- package/dist/components/markdown.d.ts.map +1 -1
- package/dist/components/markdown.js +8 -2
- package/dist/components/markdown.js.map +1 -1
- package/dist/components/mouse-region.d.ts.map +1 -1
- package/dist/components/mouse-region.js.map +1 -1
- package/dist/components/scroll-view.d.ts.map +1 -1
- package/dist/components/scroll-view.js.map +1 -1
- package/dist/components/select-list.d.ts.map +1 -1
- package/dist/components/select-list.js.map +1 -1
- package/dist/components/settings-list.d.ts.map +1 -1
- package/dist/components/settings-list.js.map +1 -1
- package/dist/components/spacer.d.ts.map +1 -1
- package/dist/components/spacer.js.map +1 -1
- package/dist/components/stack.d.ts.map +1 -1
- package/dist/components/stack.js.map +1 -1
- package/dist/components/text.d.ts.map +1 -1
- package/dist/components/text.js.map +1 -1
- package/dist/components/truncated-text.d.ts.map +1 -1
- package/dist/components/truncated-text.js.map +1 -1
- package/dist/components/v-stack.d.ts.map +1 -1
- package/dist/components/v-stack.js.map +1 -1
- package/dist/editor-component.d.ts.map +1 -1
- package/dist/fuzzy.d.ts.map +1 -1
- package/dist/fuzzy.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/keybindings.d.ts.map +1 -1
- package/dist/keybindings.js.map +1 -1
- package/dist/keys.d.ts.map +1 -1
- package/dist/keys.js.map +1 -1
- package/dist/kill-ring.d.ts.map +1 -1
- package/dist/kill-ring.js.map +1 -1
- package/dist/latex.d.ts.map +1 -1
- package/dist/latex.js.map +1 -1
- package/dist/layout-node.d.ts.map +1 -1
- package/dist/layout-node.js.map +1 -1
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js.map +1 -1
- package/dist/native-modifiers.d.ts.map +1 -1
- package/dist/native-modifiers.js.map +1 -1
- package/dist/native-module-path.d.ts.map +1 -1
- package/dist/native-module-path.js.map +1 -1
- package/dist/native-platform.d.ts +2 -0
- package/dist/native-platform.d.ts.map +1 -1
- package/dist/native-platform.js.map +1 -1
- package/dist/oklab.d.ts +43 -0
- package/dist/oklab.d.ts.map +1 -0
- package/dist/oklab.js +210 -0
- package/dist/oklab.js.map +1 -0
- package/dist/stdin-buffer.d.ts.map +1 -1
- package/dist/stdin-buffer.js.map +1 -1
- package/dist/terminal-colors.d.ts +19 -2
- package/dist/terminal-colors.d.ts.map +1 -1
- package/dist/terminal-colors.js +12 -7
- package/dist/terminal-colors.js.map +1 -1
- package/dist/terminal-image.d.ts +3 -1
- package/dist/terminal-image.d.ts.map +1 -1
- package/dist/terminal-image.js +33 -9
- package/dist/terminal-image.js.map +1 -1
- package/dist/terminal.d.ts +3 -0
- package/dist/terminal.d.ts.map +1 -1
- package/dist/terminal.js +15 -8
- package/dist/terminal.js.map +1 -1
- package/dist/tui-alt-screen.d.ts +8 -4
- package/dist/tui-alt-screen.d.ts.map +1 -1
- package/dist/tui-alt-screen.js +13 -12
- package/dist/tui-alt-screen.js.map +1 -1
- package/dist/tui-main-screen.d.ts.map +1 -1
- package/dist/tui-main-screen.js.map +1 -1
- package/dist/tui.d.ts +23 -22
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +85 -66
- package/dist/tui.js.map +1 -1
- package/dist/undo-stack.d.ts.map +1 -1
- package/dist/undo-stack.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +99 -55
- package/dist/utils.js.map +1 -1
- package/dist/wheel-scroll.d.ts +23 -0
- package/dist/wheel-scroll.d.ts.map +1 -0
- package/dist/wheel-scroll.js +73 -0
- package/dist/wheel-scroll.js.map +1 -0
- package/dist/word-navigation.d.ts.map +1 -1
- package/dist/word-navigation.js.map +1 -1
- package/native/clipboard.h +40 -2
- package/native/darwin/README.md +1 -1
- package/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
- package/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
- package/native/darwin/src/darwin-platform.m +39 -0
- package/native/napi.h +2 -0
- package/package.json +2 -2
package/dist/tui.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { performance } from "node:perf_hooks";
|
|
5
5
|
import { isKeyRelease, matchesKey } from "./keys.js";
|
|
6
|
-
import {
|
|
6
|
+
import { parseOscColorResponse, parseTerminalColorSchemeReport, } from "./terminal-colors.js";
|
|
7
7
|
import { getCapabilities, isImageLine, setCellDimensions } from "./terminal-image.js";
|
|
8
8
|
import { extractSegments, normalizeTerminalOutput, sliceByColumn, sliceWithWidth, visibleWidth } from "./utils.js";
|
|
9
9
|
/**
|
|
@@ -14,8 +14,13 @@ export function dispatchMouseEvent(component, event) {
|
|
|
14
14
|
const result = component.handleMouse?.(event);
|
|
15
15
|
if (!result)
|
|
16
16
|
return undefined;
|
|
17
|
-
if ("target" in result)
|
|
18
|
-
|
|
17
|
+
if ("target" in result) {
|
|
18
|
+
// The component forwarded the event to a child it hosts. Like a delegating container, it routes
|
|
19
|
+
// keys to that child itself, so it keeps keyboard focus. Focusing the child directly would leave
|
|
20
|
+
// focus on a detached component once the host removes it, e.g. a closed settings submenu.
|
|
21
|
+
const forwarded = result;
|
|
22
|
+
return forwarded.focus && component.handleInput ? { ...forwarded, focusTarget: component } : forwarded;
|
|
23
|
+
}
|
|
19
24
|
if (!result.handled && !result.capture && !result.focus)
|
|
20
25
|
return undefined;
|
|
21
26
|
return {
|
|
@@ -41,6 +46,16 @@ export function retargetMouseEvent(event, target) {
|
|
|
41
46
|
height: target.height,
|
|
42
47
|
};
|
|
43
48
|
}
|
|
49
|
+
const TERMINAL_PALETTE_SIZE = 16;
|
|
50
|
+
/** OSC 10 and 11 plus OSC 4 for every palette color. */
|
|
51
|
+
const TERMINAL_COLOR_REPLY_COUNT = 2 + TERMINAL_PALETTE_SIZE;
|
|
52
|
+
/**
|
|
53
|
+
* Default colors, palette colors 0-15, and a trailing primary device attributes (DA1) request.
|
|
54
|
+
* Every terminal answers DA1 and terminals answer in order, so the DA1 reply marks the end of
|
|
55
|
+
* the color replies, including for terminals that ignore the color queries.
|
|
56
|
+
*/
|
|
57
|
+
const TERMINAL_COLOR_QUERY = `\x1b]10;?\x07\x1b]11;?\x07${Array.from({ length: TERMINAL_PALETTE_SIZE }, (_, index) => `\x1b]4;${index};?\x07`).join("")}\x1b[c`;
|
|
58
|
+
const DEVICE_ATTRIBUTES_RESPONSE_PATTERN = /^\x1b\[\?[\d;]*c$/;
|
|
44
59
|
/** Type guard to check if a component implements Focusable */
|
|
45
60
|
export function isFocusable(component) {
|
|
46
61
|
return component !== null && "focused" in component;
|
|
@@ -171,8 +186,11 @@ export class TuiBase extends Container {
|
|
|
171
186
|
clearOnShrink = false;
|
|
172
187
|
fullRedrawCount = 0;
|
|
173
188
|
stopped = false;
|
|
174
|
-
|
|
175
|
-
|
|
189
|
+
/**
|
|
190
|
+
* Color queries waiting for their DA1 reply, oldest first. Terminals answer in order, so color
|
|
191
|
+
* replies belong to the oldest one. Queries stay here after a timeout to collect late replies.
|
|
192
|
+
*/
|
|
193
|
+
pendingTerminalColorQueries = [];
|
|
176
194
|
terminalColorSchemeListeners = new Set();
|
|
177
195
|
terminalColorSchemeNotificationsEnabled = false;
|
|
178
196
|
/** Directory for debug/crash logs. When undefined, debug logging is disabled and crash dumps fall back to the OS temp directory. */
|
|
@@ -209,7 +227,7 @@ export class TuiBase extends Container {
|
|
|
209
227
|
return;
|
|
210
228
|
this.showHardwareCursor = enabled;
|
|
211
229
|
if (!enabled) {
|
|
212
|
-
this.
|
|
230
|
+
this.hideTerminalCursor();
|
|
213
231
|
}
|
|
214
232
|
this.requestRender();
|
|
215
233
|
}
|
|
@@ -357,7 +375,7 @@ export class TuiBase extends Container {
|
|
|
357
375
|
if (!options?.nonCapturing && this.isOverlayVisible(entry)) {
|
|
358
376
|
this.setFocus(component);
|
|
359
377
|
}
|
|
360
|
-
this.
|
|
378
|
+
this.hideTerminalCursor();
|
|
361
379
|
this.requestRender();
|
|
362
380
|
// Return handle for controlling this overlay
|
|
363
381
|
return {
|
|
@@ -373,7 +391,7 @@ export class TuiBase extends Container {
|
|
|
373
391
|
this.setFocus(topVisible?.component ?? entry.preFocus);
|
|
374
392
|
}
|
|
375
393
|
if (this.overlayStack.length === 0)
|
|
376
|
-
this.
|
|
394
|
+
this.hideTerminalCursor();
|
|
377
395
|
this.requestRender();
|
|
378
396
|
}
|
|
379
397
|
},
|
|
@@ -460,9 +478,14 @@ export class TuiBase extends Container {
|
|
|
460
478
|
this.setFocus(topVisible?.component ?? overlay.preFocus);
|
|
461
479
|
}
|
|
462
480
|
if (this.overlayStack.length === 0)
|
|
463
|
-
this.
|
|
481
|
+
this.hideTerminalCursor();
|
|
464
482
|
this.requestRender();
|
|
465
483
|
}
|
|
484
|
+
/** Hide the cursor while running. After stop(), the shell owns the cursor and it must stay visible. */
|
|
485
|
+
hideTerminalCursor() {
|
|
486
|
+
if (!this.stopped)
|
|
487
|
+
this.terminal.hideCursor();
|
|
488
|
+
}
|
|
466
489
|
/** Check if there are any visible overlays */
|
|
467
490
|
hasOverlay() {
|
|
468
491
|
return this.overlayStack.some((o) => this.isOverlayVisible(o));
|
|
@@ -653,7 +676,7 @@ export class TuiBase extends Container {
|
|
|
653
676
|
}, delay);
|
|
654
677
|
}
|
|
655
678
|
handleTerminalInput(data) {
|
|
656
|
-
if (this.
|
|
679
|
+
if (this.consumeTerminalColorResponse(data)) {
|
|
657
680
|
return;
|
|
658
681
|
}
|
|
659
682
|
if (this.consumeTerminalColorSchemeReport(data)) {
|
|
@@ -726,27 +749,50 @@ export class TuiBase extends Container {
|
|
|
726
749
|
this.requestImmediateRender();
|
|
727
750
|
}
|
|
728
751
|
}
|
|
729
|
-
|
|
730
|
-
|
|
752
|
+
consumeTerminalColorResponse(data) {
|
|
753
|
+
const query = this.pendingTerminalColorQueries[0];
|
|
754
|
+
if (!query) {
|
|
731
755
|
return false;
|
|
732
756
|
}
|
|
733
|
-
if (
|
|
757
|
+
if (DEVICE_ATTRIBUTES_RESPONSE_PATTERN.test(data)) {
|
|
758
|
+
this.pendingTerminalColorQueries.shift();
|
|
759
|
+
this.completeTerminalColorQuery(query);
|
|
760
|
+
return true;
|
|
761
|
+
}
|
|
762
|
+
const response = parseOscColorResponse(data);
|
|
763
|
+
if (!response) {
|
|
734
764
|
return false;
|
|
735
765
|
}
|
|
736
|
-
const rgb =
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
query.
|
|
766
|
+
const { target, rgb } = response;
|
|
767
|
+
const key = String(target);
|
|
768
|
+
if (!query.deliver || query.replied.has(key)) {
|
|
769
|
+
return true;
|
|
770
|
+
}
|
|
771
|
+
query.replied.add(key);
|
|
772
|
+
if (target === "foreground") {
|
|
773
|
+
query.foreground = rgb;
|
|
774
|
+
}
|
|
775
|
+
else if (target === "background") {
|
|
776
|
+
query.background = rgb;
|
|
777
|
+
}
|
|
778
|
+
else if (target < TERMINAL_PALETTE_SIZE) {
|
|
779
|
+
query.palette[target] = rgb;
|
|
780
|
+
}
|
|
781
|
+
if (query.replied.size === TERMINAL_COLOR_REPLY_COUNT) {
|
|
782
|
+
this.completeTerminalColorQuery(query);
|
|
747
783
|
}
|
|
748
784
|
return true;
|
|
749
785
|
}
|
|
786
|
+
terminalColorQueryResult(query) {
|
|
787
|
+
const palette = query.palette.every((color) => color !== undefined) ? query.palette : undefined;
|
|
788
|
+
return { foreground: query.foreground, background: query.background, palette };
|
|
789
|
+
}
|
|
790
|
+
completeTerminalColorQuery(query) {
|
|
791
|
+
const deliver = query.deliver;
|
|
792
|
+
query.deliver = undefined;
|
|
793
|
+
clearTimeout(query.timer);
|
|
794
|
+
deliver?.(this.terminalColorQueryResult(query));
|
|
795
|
+
}
|
|
750
796
|
consumeTerminalColorSchemeReport(data) {
|
|
751
797
|
const scheme = parseTerminalColorSchemeReport(data);
|
|
752
798
|
if (!scheme) {
|
|
@@ -1000,55 +1046,28 @@ export class TuiBase extends Container {
|
|
|
1000
1046
|
return null;
|
|
1001
1047
|
}
|
|
1002
1048
|
/**
|
|
1003
|
-
* Query the terminal's
|
|
1004
|
-
*
|
|
1005
|
-
*
|
|
1049
|
+
* Query the terminal's theme colors: the default foreground (OSC 10), the default background
|
|
1050
|
+
* (OSC 11), and ANSI colors 0-15 (OSC 4), followed by a DA1 request that marks the end of the
|
|
1051
|
+
* replies. Resolves when the DA1 reply or all color replies arrive, or when the timeout expires.
|
|
1052
|
+
* Colors the terminal did not report are undefined; the palette is only set when all 16 arrived.
|
|
1053
|
+
* @param timeoutMs Query timeout in milliseconds, for terminals that do not answer DA1 either.
|
|
1054
|
+
* @param onLateReply Receives the replies if the query completes after the timeout, e.g. over slow links.
|
|
1006
1055
|
*/
|
|
1007
|
-
|
|
1056
|
+
queryTerminalColors({ timeoutMs, onLateReply, }) {
|
|
1008
1057
|
return new Promise((resolve) => {
|
|
1009
1058
|
const query = {
|
|
1010
|
-
|
|
1011
|
-
|
|
1059
|
+
palette: Array.from({ length: TERMINAL_PALETTE_SIZE }, () => undefined),
|
|
1060
|
+
replied: new Set(),
|
|
1061
|
+
deliver: resolve,
|
|
1012
1062
|
timer: undefined,
|
|
1013
1063
|
};
|
|
1064
|
+
// Resolve with the replies so far, and keep collecting late replies for `onLateReply`.
|
|
1014
1065
|
query.timer = setTimeout(() => {
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
}
|
|
1018
|
-
query.settled = true;
|
|
1019
|
-
query.timer = undefined;
|
|
1020
|
-
query.resolve?.(undefined);
|
|
1021
|
-
query.resolve = undefined;
|
|
1066
|
+
query.deliver = onLateReply;
|
|
1067
|
+
resolve(this.terminalColorQueryResult(query));
|
|
1022
1068
|
}, timeoutMs);
|
|
1023
|
-
this.
|
|
1024
|
-
this.
|
|
1025
|
-
this.terminal.write("\x1b]11;?\x07");
|
|
1026
|
-
});
|
|
1027
|
-
}
|
|
1028
|
-
/**
|
|
1029
|
-
* Query the terminal's color-scheme preference with DSR (`CSI ? 996 n`).
|
|
1030
|
-
* Terminals that support the color palette notification protocol reply with
|
|
1031
|
-
* `CSI ? 997 ; 1 n` for dark or `CSI ? 997 ; 2 n` for light.
|
|
1032
|
-
*/
|
|
1033
|
-
queryTerminalColorScheme({ timeoutMs }) {
|
|
1034
|
-
return new Promise((resolve) => {
|
|
1035
|
-
let settled = false;
|
|
1036
|
-
let timer;
|
|
1037
|
-
let unsubscribe = () => { };
|
|
1038
|
-
const settle = (scheme) => {
|
|
1039
|
-
if (settled)
|
|
1040
|
-
return;
|
|
1041
|
-
settled = true;
|
|
1042
|
-
if (timer) {
|
|
1043
|
-
clearTimeout(timer);
|
|
1044
|
-
timer = undefined;
|
|
1045
|
-
}
|
|
1046
|
-
unsubscribe();
|
|
1047
|
-
resolve(scheme);
|
|
1048
|
-
};
|
|
1049
|
-
unsubscribe = this.onTerminalColorSchemeChange(settle);
|
|
1050
|
-
timer = setTimeout(() => settle(undefined), timeoutMs);
|
|
1051
|
-
this.terminal.write("\x1b[?996n");
|
|
1069
|
+
this.pendingTerminalColorQueries.push(query);
|
|
1070
|
+
this.terminal.write(TERMINAL_COLOR_QUERY);
|
|
1052
1071
|
});
|
|
1053
1072
|
}
|
|
1054
1073
|
}
|