@linxiraos/pi-tui 1.0.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.
Files changed (77) hide show
  1. package/CHANGELOG.md +2219 -0
  2. package/README.md +705 -0
  3. package/dist/types/autocomplete.d.ts +116 -0
  4. package/dist/types/bracketed-paste.d.ts +51 -0
  5. package/dist/types/components/box.d.ts +31 -0
  6. package/dist/types/components/cancellable-loader.d.ts +21 -0
  7. package/dist/types/components/editor.d.ts +162 -0
  8. package/dist/types/components/image.d.ts +112 -0
  9. package/dist/types/components/input.d.ts +25 -0
  10. package/dist/types/components/loader.d.ts +25 -0
  11. package/dist/types/components/markdown.d.ts +88 -0
  12. package/dist/types/components/scroll-view.d.ts +62 -0
  13. package/dist/types/components/select-list.d.ts +69 -0
  14. package/dist/types/components/settings-list.d.ts +123 -0
  15. package/dist/types/components/spacer.d.ts +11 -0
  16. package/dist/types/components/tab-bar.d.ts +89 -0
  17. package/dist/types/components/text.d.ts +27 -0
  18. package/dist/types/components/truncated-text.d.ts +10 -0
  19. package/dist/types/deccara.d.ts +49 -0
  20. package/dist/types/desktop-notify.d.ts +52 -0
  21. package/dist/types/editor-component.d.ts +38 -0
  22. package/dist/types/fuzzy.d.ts +48 -0
  23. package/dist/types/index.d.ts +32 -0
  24. package/dist/types/keybindings.d.ts +197 -0
  25. package/dist/types/keys.d.ts +210 -0
  26. package/dist/types/kill-ring.d.ts +20 -0
  27. package/dist/types/kitty-graphics.d.ts +76 -0
  28. package/dist/types/latex-block.d.ts +8 -0
  29. package/dist/types/latex-to-unicode.d.ts +50 -0
  30. package/dist/types/loop-watchdog.d.ts +44 -0
  31. package/dist/types/mouse.d.ts +67 -0
  32. package/dist/types/stdin-buffer.d.ts +60 -0
  33. package/dist/types/symbols.d.ts +25 -0
  34. package/dist/types/terminal-capabilities.d.ts +285 -0
  35. package/dist/types/terminal.d.ts +175 -0
  36. package/dist/types/tmux.d.ts +6 -0
  37. package/dist/types/ttyid.d.ts +9 -0
  38. package/dist/types/tui.d.ts +457 -0
  39. package/dist/types/utils.d.ts +100 -0
  40. package/package.json +70 -0
  41. package/src/autocomplete.ts +1079 -0
  42. package/src/bracketed-paste.ts +123 -0
  43. package/src/components/box.ts +236 -0
  44. package/src/components/cancellable-loader.ts +40 -0
  45. package/src/components/editor.ts +3301 -0
  46. package/src/components/image.ts +460 -0
  47. package/src/components/input.ts +482 -0
  48. package/src/components/loader.ts +174 -0
  49. package/src/components/markdown.ts +3119 -0
  50. package/src/components/scroll-view.ts +227 -0
  51. package/src/components/select-list.ts +539 -0
  52. package/src/components/settings-list.ts +793 -0
  53. package/src/components/spacer.ts +32 -0
  54. package/src/components/tab-bar.ts +300 -0
  55. package/src/components/text.ts +173 -0
  56. package/src/components/truncated-text.ts +69 -0
  57. package/src/deccara.ts +314 -0
  58. package/src/desktop-notify.ts +192 -0
  59. package/src/editor-component.ts +74 -0
  60. package/src/fuzzy.ts +384 -0
  61. package/src/index.ts +51 -0
  62. package/src/keybindings.ts +346 -0
  63. package/src/keys.ts +566 -0
  64. package/src/kill-ring.ts +51 -0
  65. package/src/kitty-graphics.ts +171 -0
  66. package/src/latex-block.ts +1338 -0
  67. package/src/latex-to-unicode.ts +2017 -0
  68. package/src/loop-watchdog.ts +115 -0
  69. package/src/mouse.ts +105 -0
  70. package/src/stdin-buffer.ts +781 -0
  71. package/src/symbols.ts +26 -0
  72. package/src/terminal-capabilities.ts +1211 -0
  73. package/src/terminal.ts +1854 -0
  74. package/src/tmux.ts +14 -0
  75. package/src/ttyid.ts +84 -0
  76. package/src/tui.ts +4275 -0
  77. package/src/utils.ts +619 -0
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Kitty graphics: Unicode placeholder placement (`U=1` + U+10EEEE), with
3
+ * runtime feature state and env overrides.
4
+ *
5
+ * Unicode placeholders let a transmitted image be displayed by writing ordinary
6
+ * text cells — the placeholder char U+10EEEE plus row/column combining
7
+ * diacritics — instead of a cursor-positioned `a=p` direct placement. The image
8
+ * then participates in the normal text grid, so it survives horizontal slicing,
9
+ * reflow and overlapping draws (each cell names its own row+column, so a sliced
10
+ * row still maps to the correct sub-region). See kitty
11
+ * `docs/graphics-protocol.rst` "Unicode placeholders for relative placements".
12
+ *
13
+ * This module is intentionally free of `./terminal-capabilities` imports so the
14
+ * dependency stays one-way (capabilities → kitty-graphics) and no import cycle
15
+ * forms. Protocol gating (`imageProtocol === Kitty`) lives in the caller.
16
+ */
17
+
18
+ import { wrapTmuxPassthroughIfNeeded } from "./tmux";
19
+
20
+ /** Kitty Unicode placeholder base character (U+10EEEE, Plane 16 PUA). */
21
+ export const KITTY_PLACEHOLDER = "\u{10eeee}";
22
+
23
+ /**
24
+ * Row/column diacritics (Unicode combining class 230, no decomposition) used to
25
+ * name a placeholder cell's row and column. Index `i` → codepoint. Derived from
26
+ * kitty `gen/rowcolumn-diacritics.txt` (Unicode 6.0.0 NSM set). 297 entries, so
27
+ * a single image can address up to 297 rows/columns without ID-high-byte tricks.
28
+ */
29
+ const ROWCOLUMN_DIACRITICS: readonly number[] = [
30
+ 0x305, 0x30d, 0x30e, 0x310, 0x312, 0x33d, 0x33e, 0x33f, 0x346, 0x34a, 0x34b, 0x34c, 0x350, 0x351, 0x352, 0x357,
31
+ 0x35b, 0x363, 0x364, 0x365, 0x366, 0x367, 0x368, 0x369, 0x36a, 0x36b, 0x36c, 0x36d, 0x36e, 0x36f, 0x483, 0x484,
32
+ 0x485, 0x486, 0x487, 0x592, 0x593, 0x594, 0x595, 0x597, 0x598, 0x599, 0x59c, 0x59d, 0x59e, 0x59f, 0x5a0, 0x5a1,
33
+ 0x5a8, 0x5a9, 0x5ab, 0x5ac, 0x5af, 0x5c4, 0x610, 0x611, 0x612, 0x613, 0x614, 0x615, 0x616, 0x617, 0x657, 0x658,
34
+ 0x659, 0x65a, 0x65b, 0x65d, 0x65e, 0x6d6, 0x6d7, 0x6d8, 0x6d9, 0x6da, 0x6db, 0x6dc, 0x6df, 0x6e0, 0x6e1, 0x6e2,
35
+ 0x6e4, 0x6e7, 0x6e8, 0x6eb, 0x6ec, 0x730, 0x732, 0x733, 0x735, 0x736, 0x73a, 0x73d, 0x73f, 0x740, 0x741, 0x743,
36
+ 0x745, 0x747, 0x749, 0x74a, 0x7eb, 0x7ec, 0x7ed, 0x7ee, 0x7ef, 0x7f0, 0x7f1, 0x7f3, 0x816, 0x817, 0x818, 0x819,
37
+ 0x81b, 0x81c, 0x81d, 0x81e, 0x81f, 0x820, 0x821, 0x822, 0x823, 0x825, 0x826, 0x827, 0x829, 0x82a, 0x82b, 0x82c,
38
+ 0x82d, 0x951, 0x953, 0x954, 0xf82, 0xf83, 0xf86, 0xf87, 0x135d, 0x135e, 0x135f, 0x17dd, 0x193a, 0x1a17, 0x1a75,
39
+ 0x1a76, 0x1a77, 0x1a78, 0x1a79, 0x1a7a, 0x1a7b, 0x1a7c, 0x1b6b, 0x1b6d, 0x1b6e, 0x1b6f, 0x1b70, 0x1b71, 0x1b72,
40
+ 0x1b73, 0x1cd0, 0x1cd1, 0x1cd2, 0x1cda, 0x1cdb, 0x1ce0, 0x1dc0, 0x1dc1, 0x1dc3, 0x1dc4, 0x1dc5, 0x1dc6, 0x1dc7,
41
+ 0x1dc8, 0x1dc9, 0x1dcb, 0x1dcc, 0x1dd1, 0x1dd2, 0x1dd3, 0x1dd4, 0x1dd5, 0x1dd6, 0x1dd7, 0x1dd8, 0x1dd9, 0x1dda,
42
+ 0x1ddb, 0x1ddc, 0x1ddd, 0x1dde, 0x1ddf, 0x1de0, 0x1de1, 0x1de2, 0x1de3, 0x1de4, 0x1de5, 0x1de6, 0x1dfe, 0x20d0,
43
+ 0x20d1, 0x20d4, 0x20d5, 0x20d6, 0x20d7, 0x20db, 0x20dc, 0x20e1, 0x20e7, 0x20e9, 0x20f0, 0x2cef, 0x2cf0, 0x2cf1,
44
+ 0x2de0, 0x2de1, 0x2de2, 0x2de3, 0x2de4, 0x2de5, 0x2de6, 0x2de7, 0x2de8, 0x2de9, 0x2dea, 0x2deb, 0x2dec, 0x2ded,
45
+ 0x2dee, 0x2def, 0x2df0, 0x2df1, 0x2df2, 0x2df3, 0x2df4, 0x2df5, 0x2df6, 0x2df7, 0x2df8, 0x2df9, 0x2dfa, 0x2dfb,
46
+ 0x2dfc, 0x2dfd, 0x2dfe, 0x2dff, 0xa66f, 0xa67c, 0xa67d, 0xa6f0, 0xa6f1, 0xa8e0, 0xa8e1, 0xa8e2, 0xa8e3, 0xa8e4,
47
+ 0xa8e5, 0xa8e6, 0xa8e7, 0xa8e8, 0xa8e9, 0xa8ea, 0xa8eb, 0xa8ec, 0xa8ed, 0xa8ee, 0xa8ef, 0xa8f0, 0xa8f1, 0xaab0,
48
+ 0xaab2, 0xaab3, 0xaab7, 0xaab8, 0xaabe, 0xaabf, 0xaac1, 0xfe20, 0xfe21, 0xfe22, 0xfe23, 0xfe24, 0xfe25, 0xfe26,
49
+ 0x10a0f, 0x10a38, 0x1d185, 0x1d186, 0x1d187, 0x1d188, 0x1d189, 0x1d1aa, 0x1d1ab, 0x1d1ac, 0x1d1ad, 0x1d242, 0x1d243,
50
+ 0x1d244,
51
+ ];
52
+
53
+ /** Largest row/column index expressible with the diacritic table (one cell each). */
54
+ export const KITTY_PLACEHOLDER_MAX_CELLS = ROWCOLUMN_DIACRITICS.length;
55
+
56
+ export interface KittyGraphicsFeatures {
57
+ /** Display images via Unicode placeholders instead of direct `a=p` placement. */
58
+ unicodePlaceholders: boolean;
59
+ }
60
+
61
+ /**
62
+ * Whether the detected terminal renders Kitty Unicode placeholders (`U=1` +
63
+ * U+10EEEE with row/column diacritics).
64
+ *
65
+ * Kitty and Ghostty advertise placeholder support directly. A tmux session
66
+ * cannot use cursor-positioned placements because the outer terminal does not
67
+ * know pane scroll/reflow state, so an explicit `PI_FORCE_IMAGE_PROTOCOL=kitty`
68
+ * also opts into placeholders there — matching `timg -pk`. Automatic tmux
69
+ * fallback stays off because the unknown outer terminal may render U+10EEEE as
70
+ * literal PUA boxes (#1877).
71
+ *
72
+ * `PI_NO_KITTY_PLACEHOLDERS=1` and `PI_KITTY_PLACEHOLDERS=0` remain hard
73
+ * opt-outs; `PI_KITTY_PLACEHOLDERS=1` explicitly opts in anywhere else.
74
+ */
75
+ export function detectKittyUnicodePlaceholdersSupport(terminalId: string, env: NodeJS.ProcessEnv = Bun.env): boolean {
76
+ const offRaw = env.PI_NO_KITTY_PLACEHOLDERS?.trim().toLowerCase();
77
+ if (offRaw === "1" || offRaw === "true" || offRaw === "on" || offRaw === "yes" || offRaw === "y") return false;
78
+ const force = env.PI_KITTY_PLACEHOLDERS?.trim().toLowerCase();
79
+ if (force === "1" || force === "true" || force === "on" || force === "yes" || force === "y") return true;
80
+ if (force === "0" || force === "false" || force === "off" || force === "no" || force === "n") return false;
81
+ if (env.TMUX && env.PI_FORCE_IMAGE_PROTOCOL?.trim().toLowerCase() === "kitty") return true;
82
+ return terminalId === "kitty" || terminalId === "ghostty";
83
+ }
84
+
85
+ let features: KittyGraphicsFeatures = {
86
+ // Off until `terminal-capabilities` seeds it from the detected terminal id —
87
+ // the default-on path corrupts wezterm and tmux-passthrough sessions.
88
+ unicodePlaceholders: false,
89
+ };
90
+
91
+ export function getKittyGraphics(): Readonly<KittyGraphicsFeatures> {
92
+ return features;
93
+ }
94
+
95
+ export function setKittyGraphics(partial: Partial<KittyGraphicsFeatures>): void {
96
+ features = { ...features, ...partial };
97
+ }
98
+
99
+ /** Whether a `columns`×`rows` placeholder grid fits within the diacritic table. */
100
+ export function kittyPlaceholdersFit(columns: number, rows: number): boolean {
101
+ return columns >= 1 && rows >= 1 && columns <= KITTY_PLACEHOLDER_MAX_CELLS && rows <= KITTY_PLACEHOLDER_MAX_CELLS;
102
+ }
103
+
104
+ function diacritic(index: number): string {
105
+ const cp = ROWCOLUMN_DIACRITICS[index];
106
+ return cp === undefined ? "" : String.fromCodePoint(cp);
107
+ }
108
+
109
+ /**
110
+ * Virtual placement APC (`a=p,U=1`): tells the terminal that placeholder cells
111
+ * carrying image id `i` should display the transmitted image, scaled to fit the
112
+ * `c`×`r` cell box. Re-emitting with a stable `placementId` replaces in place.
113
+ */
114
+ export function encodeKittyVirtualPlacement(opts: {
115
+ imageId: number;
116
+ placementId?: number;
117
+ columns: number;
118
+ rows: number;
119
+ }): string {
120
+ const params = ["a=p", "U=1", "q=2", `i=${opts.imageId}`];
121
+ if (opts.placementId) params.push(`p=${opts.placementId}`);
122
+ params.push(`c=${opts.columns}`, `r=${opts.rows}`);
123
+ return wrapTmuxPassthroughIfNeeded(`\x1b_G${params.join(",")}\x1b\\`);
124
+ }
125
+
126
+ /**
127
+ * Build the placeholder cell grid as one string per row. The image id is carried
128
+ * in each row's foreground color and the placement id (if any) in its underline
129
+ * color; every cell names its explicit row+column diacritic (robust to slicing,
130
+ * unlike left-inheritance). Returns exactly `rows` strings.
131
+ */
132
+ export function encodeKittyPlaceholderGrid(opts: {
133
+ imageId: number;
134
+ placementId?: number;
135
+ columns: number;
136
+ rows: number;
137
+ }): string[] {
138
+ const fg = `\x1b[38;2;${(opts.imageId >> 16) & 0xff};${(opts.imageId >> 8) & 0xff};${opts.imageId & 0xff}m`;
139
+ const underline = opts.placementId
140
+ ? `\x1b[58:2::${(opts.placementId >> 16) & 0xff}:${(opts.placementId >> 8) & 0xff}:${opts.placementId & 0xff}m`
141
+ : "";
142
+ const reset = "\x1b[39;59m";
143
+ const lead = fg + underline;
144
+ const out: string[] = [];
145
+ for (let r = 0; r < opts.rows; r++) {
146
+ const rowDiacritic = diacritic(r);
147
+ let row = lead;
148
+ for (let c = 0; c < opts.columns; c++) {
149
+ row += KITTY_PLACEHOLDER + rowDiacritic + diacritic(c);
150
+ }
151
+ out.push(row + reset);
152
+ }
153
+ return out;
154
+ }
155
+
156
+ /**
157
+ * Full placeholder render: the virtual-placement APC prefixes line 0, and every
158
+ * line carries placeholder cells. Returns exactly `rows` lines (no cursor moves).
159
+ */
160
+ export function renderKittyPlaceholderLines(opts: {
161
+ imageId: number;
162
+ placementId?: number;
163
+ columns: number;
164
+ rows: number;
165
+ }): string[] {
166
+ const grid = encodeKittyPlaceholderGrid(opts);
167
+ if (grid.length > 0) {
168
+ grid[0] = encodeKittyVirtualPlacement(opts) + grid[0];
169
+ }
170
+ return grid;
171
+ }