@alchemy.run/sigil 0.0.0-alpha.4 → 0.0.0-alpha.6

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 (138) hide show
  1. package/README.md +21 -9
  2. package/THIRD_PARTY_NOTICES.md +39 -1
  3. package/dist/Text-BobFKi74.d.ts +452 -0
  4. package/dist/ansi.d.ts +122 -131
  5. package/dist/ansi.js +86 -6
  6. package/dist/capabilities.d.ts +5 -0
  7. package/dist/capabilities.js +3 -0
  8. package/dist/cell-_ZVhbfl0.js +44 -0
  9. package/dist/color-CkbalRqK.js +2 -0
  10. package/dist/color-policy-BMzMwV7Q.d.ts +22 -0
  11. package/dist/color-policy-SVj1pYTA.js +560 -0
  12. package/dist/color-profile-DHhQHY55.js +36 -0
  13. package/dist/color-profile-u0Nhe9Nv.d.ts +97 -0
  14. package/dist/color.d.ts +21 -0
  15. package/dist/color.js +3 -0
  16. package/dist/cursor-position-D2LAkRG0.d.ts +7 -0
  17. package/dist/detect-Bh4yGP6w.d.ts +186 -0
  18. package/dist/detect-BuTXtY6e.js +373 -0
  19. package/dist/env-YVw64yZS.js +9 -0
  20. package/dist/escapes-CB_6CWOE.d.ts +72 -0
  21. package/dist/geometry-BxXOzJgo.d.ts +11 -0
  22. package/dist/index-DZ88EXJv.d.ts +21 -0
  23. package/dist/index.d.ts +143 -498
  24. package/dist/index.js +1026 -2244
  25. package/dist/osc-CCH7xDoS.js +71 -0
  26. package/dist/osc-Cn0fw77g.d.ts +23 -0
  27. package/dist/paint-C19minOS.d.ts +81 -0
  28. package/dist/query-vaIeGOkH.d.ts +152 -0
  29. package/dist/router.d.ts +392 -0
  30. package/dist/router.js +709 -0
  31. package/dist/sample-Cqw1bjUL.js +445 -0
  32. package/dist/screen-BOSLQ8fF.d.ts +49 -0
  33. package/dist/screen-CiPytswf.js +342 -0
  34. package/dist/screen.d.ts +5 -0
  35. package/dist/screen.js +5 -0
  36. package/dist/semantic-text-style-DIMzC7xt.js +91 -0
  37. package/dist/serialize-BTkAZgw1.js +79 -0
  38. package/dist/session-aZr9O8h3.js +665 -0
  39. package/dist/sgr-BhwaWAJB.js +246 -0
  40. package/dist/store-CgrG9K4y.d.ts +72 -0
  41. package/dist/string-width-CijQwpIk.js +69 -0
  42. package/dist/strip-BvU4toXG.js +6 -0
  43. package/dist/terminal.d.ts +118 -0
  44. package/dist/terminal.js +2 -0
  45. package/dist/tokenize-AjqbvtiT.js +1242 -0
  46. package/dist/tokenize-Dx1y_l5H.d.ts +57 -0
  47. package/dist/truncate-D31fhU6i.js +562 -0
  48. package/dist/use-focus-BzqAJi0n.js +1337 -0
  49. package/package.json +41 -9
  50. package/src/ansi/chalk.ts +5 -3
  51. package/src/ansi/escapes.ts +14 -0
  52. package/src/ansi/graphemes.ts +8 -0
  53. package/src/ansi/hyperlink.ts +44 -0
  54. package/src/ansi/index.ts +3 -1
  55. package/src/ansi/osc.ts +77 -0
  56. package/src/ansi/tokenize.ts +3 -4
  57. package/src/capabilities/color-policy.ts +34 -0
  58. package/src/capabilities/detect.ts +594 -0
  59. package/src/capabilities/index.ts +37 -0
  60. package/src/capabilities/query.ts +657 -0
  61. package/src/capabilities/store.ts +379 -0
  62. package/src/color/index.ts +3 -0
  63. package/src/color/paint.ts +169 -0
  64. package/src/color/palette.ts +48 -0
  65. package/src/color/sample.ts +323 -0
  66. package/src/color.ts +1 -0
  67. package/src/components/AnsiText.tsx +42 -0
  68. package/src/components/App.tsx +98 -10
  69. package/src/components/BackgroundContext.ts +2 -3
  70. package/src/components/Box.tsx +0 -8
  71. package/src/components/CursorContext.ts +1 -1
  72. package/src/components/Hyperlink.tsx +56 -0
  73. package/src/components/TerminalOscContext.ts +25 -0
  74. package/src/components/Text.tsx +22 -45
  75. package/src/components/Transform.tsx +1 -1
  76. package/src/dom.ts +11 -2
  77. package/src/global.d.ts +3 -0
  78. package/src/hooks/use-capabilities.ts +73 -0
  79. package/src/hooks/use-cursor.ts +2 -2
  80. package/src/hooks/use-terminal-osc.ts +59 -0
  81. package/src/index.ts +45 -1
  82. package/src/ink.tsx +213 -153
  83. package/src/{render-node-to-output.ts → paint-tree.ts} +75 -48
  84. package/src/reconciler.ts +24 -3
  85. package/src/render-background.ts +36 -15
  86. package/src/render-border.ts +94 -61
  87. package/src/render-frame.ts +83 -0
  88. package/src/render-to-string.ts +21 -6
  89. package/src/render.ts +15 -6
  90. package/src/router/components.tsx +343 -0
  91. package/src/router/context.ts +41 -0
  92. package/src/router/history.ts +194 -0
  93. package/src/router/hooks.tsx +391 -0
  94. package/src/router/index.ts +34 -0
  95. package/src/router/matcher.ts +571 -0
  96. package/src/screen/ansi.ts +184 -0
  97. package/src/screen/canvas.ts +160 -0
  98. package/src/screen/cell.ts +138 -0
  99. package/src/screen/color-profile.ts +47 -0
  100. package/src/screen/geometry.ts +9 -0
  101. package/src/screen/index.ts +6 -0
  102. package/src/screen/screen.ts +305 -0
  103. package/src/screen/serialize.ts +129 -0
  104. package/src/screen.ts +1 -0
  105. package/src/semantic-text-style.ts +118 -0
  106. package/src/squash-text-nodes.ts +2 -5
  107. package/src/structured-text.ts +325 -0
  108. package/src/styles.ts +19 -14
  109. package/src/terminal/index.ts +2 -0
  110. package/src/terminal/inline-presenter.ts +120 -0
  111. package/src/terminal/input.ts +86 -0
  112. package/src/terminal/render-scheduler.ts +37 -0
  113. package/src/terminal/screen-presenter.ts +188 -0
  114. package/src/terminal/session.ts +407 -0
  115. package/src/terminal.ts +1 -0
  116. package/src/testing/browser.ts +588 -0
  117. package/src/testing/emulators.ts +205 -0
  118. package/src/testing/explorer-app/index.html +12 -0
  119. package/src/testing/explorer-app/main.ts +381 -0
  120. package/src/testing/explorer-app/style.css +194 -0
  121. package/src/testing/explorer-app/tsconfig.json +15 -0
  122. package/src/testing/explorer-app/vite-env.d.ts +1 -0
  123. package/src/testing/index.ts +26 -0
  124. package/src/testing/keys.ts +56 -0
  125. package/src/testing/live.ts +85 -0
  126. package/src/testing/matchers.ts +70 -0
  127. package/src/testing/public.ts +94 -0
  128. package/src/testing/terminal.ts +349 -0
  129. package/src/testing/vitest.ts +157 -0
  130. package/src/transform-adapter.ts +14 -0
  131. package/src/wrap-text.ts +4 -0
  132. package/dist/sgr-CMfEpjSk.d.ts +0 -91
  133. package/dist/truncate-Cr6xVFMa.js +0 -2330
  134. package/src/ansi/supports-color.ts +0 -207
  135. package/src/colorize.ts +0 -60
  136. package/src/log-update.ts +0 -370
  137. package/src/output.ts +0 -308
  138. package/src/renderer.ts +0 -73
@@ -0,0 +1,246 @@
1
+ //#region src/ansi/escapes.ts
2
+ const ESC = "\x1B";
3
+ const BEL = "\x07";
4
+ const DEL = "";
5
+ /** Control Sequence Introducer. */
6
+ const CSI = `[`;
7
+ /** Operating System Command. */
8
+ const OSC = `]`;
9
+ /** String Terminator. */
10
+ const ST = `\\`;
11
+ /** Single-byte C1 forms of CSI and ST. */
12
+ const C1_CSI = "›";
13
+ const C1_ST = "œ";
14
+ const sep = ";";
15
+ const cursorTo = (x, y) => {
16
+ if (typeof y !== "number") return CSI + (x + 1) + "G";
17
+ return CSI + (y + 1) + sep + (x + 1) + "H";
18
+ };
19
+ const cursorUp = (count = 1) => CSI + count + "A";
20
+ const cursorDown = (count = 1) => CSI + count + "B";
21
+ const cursorLeft = CSI + "G";
22
+ const cursorNextLine = CSI + "E";
23
+ const eraseEndLine = CSI + "K";
24
+ const eraseLine = CSI + "2K";
25
+ const eraseScreen = CSI + "2J";
26
+ const eraseLines = (count) => {
27
+ let clear = "";
28
+ for (let i = 0; i < count; i++) clear += eraseLine + (i < count - 1 ? cursorUp() : "");
29
+ if (count) clear += cursorLeft;
30
+ return clear;
31
+ };
32
+ const clearTerminal = `${eraseScreen}${CSI}3J${CSI}H`;
33
+ const enterAlternativeScreen = CSI + "?1049h";
34
+ const exitAlternativeScreen = CSI + "?1049l";
35
+ const cursorShow = CSI + "?25h";
36
+ const cursorHide = CSI + "?25l";
37
+ const cursorShape = (shape, blinking = true) => {
38
+ const value = {
39
+ block: blinking ? 1 : 2,
40
+ underline: blinking ? 3 : 4,
41
+ bar: blinking ? 5 : 6
42
+ }[shape];
43
+ return `${CSI}${value} q`;
44
+ };
45
+ const cursorColor = (color) => `${OSC}12;${color}`;
46
+ const resetCursorColor = `${OSC}112`;
47
+ const enableBracketedPaste = CSI + "?2004h";
48
+ const disableBracketedPaste = CSI + "?2004l";
49
+ const pasteStart = CSI + "200~";
50
+ const pasteEnd = CSI + "201~";
51
+ const bsu = CSI + "?2026h";
52
+ const esu = CSI + "?2026l";
53
+ const kittyQuery = CSI + "?u";
54
+ const pushKittyKeyboard = (flags) => `${CSI}>${flags}u`;
55
+ const popKittyKeyboard = CSI + "<u";
56
+ const link = (text, url) => [
57
+ OSC,
58
+ "8",
59
+ sep,
60
+ sep,
61
+ url,
62
+ "\x07",
63
+ text,
64
+ OSC,
65
+ "8",
66
+ sep,
67
+ sep,
68
+ "\x07"
69
+ ].join("");
70
+ const ansiEscapes = {
71
+ cursorTo,
72
+ cursorUp,
73
+ cursorDown,
74
+ cursorLeft,
75
+ cursorNextLine,
76
+ eraseEndLine,
77
+ eraseLine,
78
+ eraseScreen,
79
+ eraseLines,
80
+ clearTerminal,
81
+ enterAlternativeScreen,
82
+ exitAlternativeScreen,
83
+ cursorShow,
84
+ cursorHide,
85
+ cursorShape,
86
+ cursorColor,
87
+ resetCursorColor,
88
+ enableBracketedPaste,
89
+ disableBracketedPaste,
90
+ pasteStart,
91
+ pasteEnd,
92
+ bsu,
93
+ esu,
94
+ kittyQuery,
95
+ pushKittyKeyboard,
96
+ popKittyKeyboard,
97
+ link
98
+ };
99
+ //#endregion
100
+ //#region src/ansi/sgr.ts
101
+ const ANSI_BACKGROUND_OFFSET = 10;
102
+ const wrapAnsi16 = (offset = 0) => (code) => `${CSI}${code + offset}m`;
103
+ const wrapAnsi256 = (offset = 0) => (code) => `${CSI}${38 + offset};5;${code}m`;
104
+ const wrapAnsi16m = (offset = 0) => (red, green, blue) => `${CSI}${38 + offset};2;${red};${green};${blue}m`;
105
+ const modifierCodes = {
106
+ reset: [0, 0],
107
+ bold: [1, 22],
108
+ dim: [2, 22],
109
+ italic: [3, 23],
110
+ underline: [4, 24],
111
+ overline: [53, 55],
112
+ inverse: [7, 27],
113
+ hidden: [8, 28],
114
+ strikethrough: [9, 29]
115
+ };
116
+ const colorCodes = {
117
+ black: [30, 39],
118
+ red: [31, 39],
119
+ green: [32, 39],
120
+ yellow: [33, 39],
121
+ blue: [34, 39],
122
+ magenta: [35, 39],
123
+ cyan: [36, 39],
124
+ white: [37, 39],
125
+ blackBright: [90, 39],
126
+ gray: [90, 39],
127
+ grey: [90, 39],
128
+ redBright: [91, 39],
129
+ greenBright: [92, 39],
130
+ yellowBright: [93, 39],
131
+ blueBright: [94, 39],
132
+ magentaBright: [95, 39],
133
+ cyanBright: [96, 39],
134
+ whiteBright: [97, 39]
135
+ };
136
+ const bgColorCodes = {
137
+ bgBlack: [40, 49],
138
+ bgRed: [41, 49],
139
+ bgGreen: [42, 49],
140
+ bgYellow: [43, 49],
141
+ bgBlue: [44, 49],
142
+ bgMagenta: [45, 49],
143
+ bgCyan: [46, 49],
144
+ bgWhite: [47, 49],
145
+ bgBlackBright: [100, 49],
146
+ bgGray: [100, 49],
147
+ bgGrey: [100, 49],
148
+ bgRedBright: [101, 49],
149
+ bgGreenBright: [102, 49],
150
+ bgYellowBright: [103, 49],
151
+ bgBlueBright: [104, 49],
152
+ bgMagentaBright: [105, 49],
153
+ bgCyanBright: [106, 49],
154
+ bgWhiteBright: [107, 49]
155
+ };
156
+ const modifierNames = Object.keys(modifierCodes);
157
+ const foregroundColorNames = Object.keys(colorCodes);
158
+ const backgroundColorNames = Object.keys(bgColorCodes);
159
+ const toPairs = (codes) => {
160
+ const result = {};
161
+ for (const [name, [open, close]] of Object.entries(codes)) result[name] = {
162
+ open: `${CSI}${open}m`,
163
+ close: `${CSI}${close}m`
164
+ };
165
+ return result;
166
+ };
167
+ /**
168
+ Named SGR styles as `{open, close}` escape sequence pairs.
169
+ */
170
+ const styles = {
171
+ ...toPairs(modifierCodes),
172
+ ...toPairs(colorCodes),
173
+ ...toPairs(bgColorCodes)
174
+ };
175
+ /**
176
+ Raw SGR code numbers: open code → close code.
177
+ */
178
+ const codes = new Map([
179
+ ...Object.values(modifierCodes),
180
+ ...Object.values(colorCodes),
181
+ ...Object.values(bgColorCodes)
182
+ ].map(([open, close]) => [open, close]));
183
+ const foreground = {
184
+ close: `${CSI}39m`,
185
+ ansi: wrapAnsi16(),
186
+ ansi256: wrapAnsi256(),
187
+ ansi16m: wrapAnsi16m()
188
+ };
189
+ const background = {
190
+ close: `${CSI}49m`,
191
+ ansi: wrapAnsi16(ANSI_BACKGROUND_OFFSET),
192
+ ansi256: wrapAnsi256(ANSI_BACKGROUND_OFFSET),
193
+ ansi16m: wrapAnsi16m(ANSI_BACKGROUND_OFFSET)
194
+ };
195
+ const rgbToAnsi256 = (red, green, blue) => {
196
+ if (red === green && green === blue) {
197
+ if (red < 8) return 16;
198
+ if (red > 248) return 231;
199
+ return Math.round((red - 8) / 247 * 24) + 232;
200
+ }
201
+ return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
202
+ };
203
+ const hexToRgb = (hex) => {
204
+ const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex);
205
+ if (!matches) return [
206
+ 0,
207
+ 0,
208
+ 0
209
+ ];
210
+ let [colorString] = matches;
211
+ if (colorString.length === 3) colorString = colorString.replaceAll(/./g, "$&$&");
212
+ const integer = Number.parseInt(colorString, 16);
213
+ return [
214
+ integer >> 16 & 255,
215
+ integer >> 8 & 255,
216
+ integer & 255
217
+ ];
218
+ };
219
+ const hexToAnsi256 = (hex) => rgbToAnsi256(...hexToRgb(hex));
220
+ const ansi256ToAnsi = (code) => {
221
+ if (code < 8) return 30 + code;
222
+ if (code < 16) return 90 + (code - 8);
223
+ let red;
224
+ let green;
225
+ let blue;
226
+ if (code >= 232) {
227
+ red = ((code - 232) * 10 + 8) / 255;
228
+ green = red;
229
+ blue = red;
230
+ } else {
231
+ code -= 16;
232
+ const remainder = code % 36;
233
+ red = Math.floor(code / 36) / 5;
234
+ green = Math.floor(remainder / 6) / 5;
235
+ blue = remainder % 6 / 5;
236
+ }
237
+ const value = Math.max(red, green, blue) * 2;
238
+ if (value === 0) return 30;
239
+ let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
240
+ if (value === 2) result += 60;
241
+ return result;
242
+ };
243
+ const rgbToAnsi = (red, green, blue) => ansi256ToAnsi(rgbToAnsi256(red, green, blue));
244
+ const hexToAnsi = (hex) => ansi256ToAnsi(hexToAnsi256(hex));
245
+ //#endregion
246
+ export { cursorShape as A, eraseScreen as B, bsu as C, cursorHide as D, cursorDown as E, enableBracketedPaste as F, pasteEnd as G, exitAlternativeScreen as H, enterAlternativeScreen as I, pushKittyKeyboard as J, pasteStart as K, eraseEndLine as L, cursorTo as M, cursorUp as N, cursorLeft as O, disableBracketedPaste as P, eraseLine as R, ansiEscapes as S, cursorColor as T, kittyQuery as U, esu as V, link as W, resetCursorColor as Y, CSI as _, foreground as a, OSC as b, hexToAnsi256 as c, rgbToAnsi as d, rgbToAnsi256 as f, C1_ST as g, C1_CSI as h, codes as i, cursorShow as j, cursorNextLine as k, hexToRgb as l, BEL as m, background as n, foregroundColorNames as o, styles as p, popKittyKeyboard as q, backgroundColorNames as r, hexToAnsi as s, ansi256ToAnsi as t, modifierNames as u, DEL as v, clearTerminal as w, ST as x, ESC as y, eraseLines as z };
@@ -0,0 +1,72 @@
1
+ import { t as Capabilities } from "./detect-Bh4yGP6w.js";
2
+ //#region src/stream.d.ts
3
+ type OutputStream = NodeJS.WritableStream & {
4
+ isTTY?: boolean;
5
+ columns?: number;
6
+ rows?: number;
7
+ destroyed?: boolean;
8
+ writableEnded?: boolean;
9
+ };
10
+ //#endregion
11
+ //#region src/capabilities/store.d.ts
12
+ type StoreStdin = NodeJS.ReadableStream & {
13
+ isTTY?: boolean;
14
+ isRaw?: boolean;
15
+ setRawMode?: (mode: boolean) => void;
16
+ };
17
+ type StoreStdout = OutputStream;
18
+ type CapabilitiesStore = {
19
+ /**
20
+ The current snapshot: environment-derived detection merged with every
21
+ query answer received so far. Size is always fresh; the object identity
22
+ only changes when something actually changed, so it's safe to compare.
23
+ */
24
+ readonly current: Capabilities;
25
+ /**
26
+ Asks the terminal. The first call runs the full query; subsequent calls
27
+ re-ask only the dynamic questions (theme colors, pixel geometry) and
28
+ merge over the cached answers. No-op outside a TTY. Resolves with the
29
+ updated snapshot.
30
+ */
31
+ query: () => Promise<Capabilities>;
32
+ /**
33
+ Subscribes to snapshot changes: query answers arriving, terminal resizes
34
+ (including in-band pixel geometry), color scheme switches, and window
35
+ focus changes. While subscribers exist (and a report feed is available),
36
+ the store enables the supported report modes on the terminal and disables
37
+ them again on the last unsubscribe. Returns an unsubscribe function.
38
+ */
39
+ subscribe: (listener: (capabilities: Capabilities) => void, options?: {
40
+ resizes?: boolean;
41
+ }) => () => void;
42
+ /**
43
+ Feeds one parsed escape sequence from an input pipeline into the store.
44
+ Returns `true` when the sequence was an unsolicited terminal report
45
+ (color scheme, focus, in-band resize) and was consumed. Ink calls this
46
+ for every escape sequence it reads; standalone apps that read stdin
47
+ themselves can forward unrecognized sequences here.
48
+ */
49
+ ingest: (sequence: string) => boolean;
50
+ };
51
+ /**
52
+ The capabilities store for a stream pair. Stores are cached per stdout, so
53
+ standalone code and Ink components observing the same terminal share one
54
+ snapshot and one set of query answers.
55
+ */
56
+ declare const getCapabilities: (stdin?: StoreStdin, stdout?: StoreStdout) => CapabilitiesStore;
57
+ /**
58
+ The process's own terminal — the store for `process.stdin`/`process.stdout`.
59
+
60
+ ```ts
61
+ import { capabilities } from "@alchemy.run/sigil/capabilities";
62
+
63
+ capabilities.current.supports.hyperlinks;
64
+ const fresh = await capabilities.query();
65
+ const unsubscribe = capabilities.subscribe((caps) => {
66
+ console.log(caps.size, caps.theme.appearance);
67
+ });
68
+ ```
69
+ */
70
+ declare const capabilities: CapabilitiesStore;
71
+ //#endregion
72
+ export { OutputStream as i, capabilities as n, getCapabilities as r, CapabilitiesStore as t };
@@ -0,0 +1,69 @@
1
+ import { N as isWideNotCJKTNotEmoji, k as isFullWidth } from "./tokenize-AjqbvtiT.js";
2
+ //#region src/ansi/string-width.ts
3
+ const getCodePointsLength = (input) => {
4
+ let length = 0;
5
+ for (const _ of input) length += 1;
6
+ return length;
7
+ };
8
+ const ANSI_RE = /[\u001b\u009b][[()#;?]*[0-9;:]*[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
9
+ const CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
10
+ const CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/uy;
11
+ const TAB_RE = /\t{1,1000}/y;
12
+ const EMOJI_RE = /[\u{1F1E6}-\u{1F1FF}]{2}|\u{1F3F4}[\u{E0061}-\u{E007A}]{2}[\u{E0030}-\u{E0039}\u{E0061}-\u{E007A}]{1,3}\u{E007F}|(?:\p{Emoji}\uFE0F\u20E3?|\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation})(?:\u200D(?:\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F\u20E3?))*/uy;
13
+ const LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
14
+ const MODIFIER_RE = /\p{M}+/gu;
15
+ const ANSI_WIDTH = 0;
16
+ const CONTROL_WIDTH = 0;
17
+ const TAB_WIDTH = 8;
18
+ const EMOJI_WIDTH = 2;
19
+ const FULL_WIDTH_WIDTH = 2;
20
+ const REGULAR_WIDTH = 1;
21
+ const WIDE_WIDTH = 2;
22
+ const PARSE_BLOCKS = [
23
+ [LATIN_RE, REGULAR_WIDTH],
24
+ [ANSI_RE, ANSI_WIDTH],
25
+ [CONTROL_RE, CONTROL_WIDTH],
26
+ [TAB_RE, TAB_WIDTH],
27
+ [EMOJI_RE, EMOJI_WIDTH],
28
+ [CJKT_WIDE_RE, WIDE_WIDTH]
29
+ ];
30
+ const stringWidth = (input) => {
31
+ let indexPrev = 0;
32
+ let index = 0;
33
+ const length = input.length;
34
+ let unmatchedStart = 0;
35
+ let unmatchedEnd = 0;
36
+ let width = 0;
37
+ outer: while (true) {
38
+ if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
39
+ const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
40
+ for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
41
+ const codePoint = char.codePointAt(0) || 0;
42
+ width += isFullWidth(codePoint) ? FULL_WIDTH_WIDTH : isWideNotCJKTNotEmoji(codePoint) ? WIDE_WIDTH : REGULAR_WIDTH;
43
+ }
44
+ unmatchedStart = unmatchedEnd = 0;
45
+ }
46
+ if (index >= length) break;
47
+ for (let i = 0, l = PARSE_BLOCKS.length; i < l; i++) {
48
+ const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];
49
+ BLOCK_RE.lastIndex = index;
50
+ if (BLOCK_RE.test(input)) {
51
+ const lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
52
+ width += lengthExtra * BLOCK_WIDTH;
53
+ unmatchedStart = indexPrev;
54
+ unmatchedEnd = index;
55
+ index = indexPrev = BLOCK_RE.lastIndex;
56
+ continue outer;
57
+ }
58
+ }
59
+ index += 1;
60
+ }
61
+ return width;
62
+ };
63
+ const widestLine = (text) => {
64
+ let lineWidth = 0;
65
+ for (const line of text.split("\n")) lineWidth = Math.max(lineWidth, stringWidth(line));
66
+ return lineWidth;
67
+ };
68
+ //#endregion
69
+ export { widestLine as n, stringWidth as t };
@@ -0,0 +1,6 @@
1
+ import { stripVTControlCharacters } from "node:util";
2
+ //#region src/ansi/strip.ts
3
+ const colonSgrRegex = /(?:\u001B\[|\u009B)[\d;]*:[\d;:]*m/g;
4
+ const stripAnsi = (input) => stripVTControlCharacters(input.replaceAll(colonSgrRegex, ""));
5
+ //#endregion
6
+ export { stripAnsi as t };
@@ -0,0 +1,118 @@
1
+ import { a as CursorShape } from "./escapes-CB_6CWOE.js";
2
+ import { n as TerminalProgressState, t as ClipboardSelection } from "./osc-Cn0fw77g.js";
3
+ import { i as OutputStream, t as CapabilitiesStore } from "./store-CgrG9K4y.js";
4
+ import { t as ColorProfile } from "./color-profile-u0Nhe9Nv.js";
5
+ import { t as ColorPolicy } from "./color-policy-BMzMwV7Q.js";
6
+ import { n as Screen } from "./screen-BOSLQ8fF.js";
7
+ import { t as CursorPosition } from "./cursor-position-D2LAkRG0.js";
8
+ //#region src/input-parser.d.ts
9
+ type InputEvent = string | {
10
+ readonly paste: string;
11
+ };
12
+ //#endregion
13
+ //#region src/terminal/input.d.ts
14
+ type MouseButton = "left" | "middle" | "right" | "none" | "wheel-up" | "wheel-down";
15
+ type TerminalMouseEvent = {
16
+ readonly type: "press" | "release" | "move" | "wheel";
17
+ readonly x: number;
18
+ readonly y: number;
19
+ readonly button: MouseButton;
20
+ readonly shift: boolean;
21
+ readonly alt: boolean;
22
+ readonly ctrl: boolean;
23
+ };
24
+ /** Stateful stdin decoder that separates terminal reports from application input. */
25
+ declare class TerminalInput {
26
+ #private;
27
+ constructor(capabilities: CapabilitiesStore);
28
+ push(chunk: string): InputEvent[];
29
+ subscribeMouse(listener: (event: TerminalMouseEvent) => void): () => void;
30
+ hasPendingEscape(): boolean;
31
+ flushPendingEscape(): string | undefined;
32
+ reset(): void;
33
+ }
34
+ declare function parseMouseEvent(sequence: string): TerminalMouseEvent | undefined;
35
+ //#endregion
36
+ //#region src/terminal/session.d.ts
37
+ type TerminalSessionOptions = {
38
+ readonly stdin: NodeJS.ReadableStream;
39
+ readonly stdout: OutputStream;
40
+ readonly stderr: OutputStream;
41
+ readonly colorPolicy?: ColorPolicy;
42
+ readonly onCapabilitiesChange?: () => void;
43
+ };
44
+ type TerminalMode = {
45
+ readonly id: string;
46
+ readonly enable: string;
47
+ readonly disable: string;
48
+ };
49
+ type TerminalCursor = {
50
+ readonly position?: CursorPosition;
51
+ readonly visible: boolean;
52
+ readonly shape: CursorShape;
53
+ readonly blinking: boolean;
54
+ readonly color?: string;
55
+ };
56
+ /** Instance-scoped terminal state and lifecycle ownership. */
57
+ declare class TerminalSession {
58
+ #private;
59
+ readonly stdin: NodeJS.ReadableStream;
60
+ readonly stdout: OutputStream;
61
+ readonly stderr: OutputStream;
62
+ readonly capabilities: CapabilitiesStore;
63
+ readonly input: TerminalInput;
64
+ cursor: TerminalCursor;
65
+ suspended: boolean;
66
+ alternateScreen: boolean;
67
+ inlineScreen: boolean;
68
+ constructor(options: TerminalSessionOptions);
69
+ get colorProfile(): ColorProfile;
70
+ /** Encodes a structured frame at the terminal boundary. */
71
+ encode(screen: Screen): string;
72
+ present(screen: Screen, options?: {
73
+ readonly fullscreen?: boolean;
74
+ readonly forceRewrite?: boolean;
75
+ }): boolean;
76
+ willPresent(screen: Screen, options?: {
77
+ readonly fullscreen?: boolean;
78
+ readonly forceRewrite?: boolean;
79
+ }): boolean;
80
+ clearFrame(): void;
81
+ resetFrame(): void;
82
+ finishFrame(): void;
83
+ setColorPolicy(policy: ColorPolicy): void;
84
+ /** Writes through the session and tracks callback-based backpressure completion. */
85
+ write(data: string): boolean;
86
+ flush(): Promise<void>;
87
+ /** Copy text through OSC 52, including tmux passthrough when required. */
88
+ copyToClipboard(text: string, selection?: ClipboardSelection): boolean;
89
+ setTitle(title: string): boolean;
90
+ publishTitle(owner: symbol, title?: string): boolean;
91
+ setWorkingDirectory(directory: URL | string): boolean;
92
+ notify(title: string): boolean;
93
+ setPointerShape(shape: string): boolean;
94
+ publishProgress(owner: symbol, state: TerminalProgressState, value?: number): boolean;
95
+ /**
96
+ * Update terminal-native progress. Active progress is reset during cleanup
97
+ * so a completed or failed process cannot leave a stale terminal indicator.
98
+ */
99
+ setProgress(state: TerminalProgressState, value?: number): boolean;
100
+ enableMode(mode: TerminalMode): void;
101
+ enableMode(enable: string, disable: string): void;
102
+ disableMode(idOrDisable: string): void;
103
+ setCursor(position: CursorPosition | undefined): void;
104
+ setCursorAppearance(options: {
105
+ readonly visible?: boolean;
106
+ readonly shape?: CursorShape;
107
+ readonly blinking?: boolean;
108
+ readonly color?: string | null;
109
+ }): void;
110
+ setAlternateScreen(enabled: boolean, options?: {
111
+ hideCursor?: boolean;
112
+ }): void;
113
+ beginSuspension(): void;
114
+ resume(): void;
115
+ cleanup(): void;
116
+ }
117
+ //#endregion
118
+ export { MouseButton, TerminalCursor, TerminalInput, TerminalMode, TerminalMouseEvent, TerminalSession, TerminalSessionOptions, parseMouseEvent };
@@ -0,0 +1,2 @@
1
+ import { n as TerminalInput, r as parseMouseEvent, t as TerminalSession } from "./session-aZr9O8h3.js";
2
+ export { TerminalInput, TerminalSession, parseMouseEvent };