@alchemy.run/sigil 0.0.0-alpha.9 → 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_NOTICES.md +28 -0
- package/dist/ansi.d.ts +53 -53
- package/dist/capabilities.js +1 -1
- package/dist/{color-policy-DlrZXC0f.js → color-policy-BAC9-TZX.js} +15 -1
- package/dist/color.d.ts +8 -8
- package/dist/{devtools-DbthxoD1.js → devtools-B_2SDRaO.js} +3 -0
- package/dist/index.d.ts +39 -37
- package/dist/index.js +189 -181
- package/dist/jsx-dev-runtime.d.ts +3 -0
- package/dist/jsx-dev-runtime.js +7 -0
- package/dist/jsx-runtime-BS_OosoY.js +42 -0
- package/dist/jsx-runtime.d.ts +2 -0
- package/dist/jsx-runtime.js +8 -0
- package/dist/react-CeO3oT_g.js +394 -0
- package/dist/react.d.ts +2 -0
- package/dist/react.js +50 -0
- package/dist/rolldown-runtime-BPOCksWG.js +24 -0
- package/dist/router.d.ts +26 -26
- package/dist/router.js +45 -42
- package/dist/{session-Cg6STjFV.js → session-DDQ5V300.js} +34 -11
- package/dist/terminal.d.ts +9 -10
- package/dist/terminal.js +1 -1
- package/dist/use-focus-B1WVNBQm.js +8383 -0
- package/package.json +27 -15
- package/src/ansi/strip.ts +2 -2
- package/src/capabilities/query.ts +22 -0
- package/src/devtools.ts +5 -0
- package/src/hooks/use-window-size.ts +10 -3
- package/src/input-parser.ts +31 -11
- package/src/jsx-dev-runtime.ts +3 -0
- package/src/jsx-runtime.ts +6 -0
- package/src/react.ts +53 -0
- package/src/reconciler.ts +51 -0
- package/src/terminal/input.ts +11 -5
- package/dist/use-focus-Basd0ksv.js +0 -1337
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alchemy.run/sigil",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.0-alpha.1",
|
|
4
4
|
"description": "React for CLIs. A self-contained fork of Ink with an integrated TypeScript Yoga layout engine.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -75,22 +75,33 @@
|
|
|
75
75
|
"import": "./dist/terminal.js",
|
|
76
76
|
"types": "./dist/terminal.d.ts",
|
|
77
77
|
"default": "./dist/terminal.js"
|
|
78
|
+
},
|
|
79
|
+
"./react": {
|
|
80
|
+
"import": "./dist/react.js",
|
|
81
|
+
"types": "./dist/react.d.ts",
|
|
82
|
+
"default": "./dist/react.js"
|
|
83
|
+
},
|
|
84
|
+
"./jsx-runtime": {
|
|
85
|
+
"import": "./dist/jsx-runtime.js",
|
|
86
|
+
"types": "./dist/jsx-runtime.d.ts",
|
|
87
|
+
"default": "./dist/jsx-runtime.js"
|
|
88
|
+
},
|
|
89
|
+
"./jsx-dev-runtime": {
|
|
90
|
+
"import": "./dist/jsx-dev-runtime.js",
|
|
91
|
+
"types": "./dist/jsx-dev-runtime.d.ts",
|
|
92
|
+
"default": "./dist/jsx-dev-runtime.js"
|
|
78
93
|
}
|
|
79
94
|
},
|
|
80
95
|
"publishConfig": {
|
|
81
96
|
"access": "public"
|
|
82
97
|
},
|
|
83
|
-
"dependencies": {
|
|
84
|
-
"react-reconciler": "^0.33.0",
|
|
85
|
-
"scheduler": "^0.27.0"
|
|
86
|
-
},
|
|
87
98
|
"devDependencies": {
|
|
88
99
|
"@slopus/ghostty-wasm": "^1.3.6",
|
|
89
|
-
"@types/node": "^
|
|
90
|
-
"@types/react": "^19.
|
|
100
|
+
"@types/node": "^26.6.1",
|
|
101
|
+
"@types/react": "^19.3.0",
|
|
91
102
|
"@types/react-reconciler": "^0.33.0",
|
|
92
|
-
"@types/scheduler": "^0.
|
|
93
|
-
"@vitest/ui": "^
|
|
103
|
+
"@types/scheduler": "^0.28.0",
|
|
104
|
+
"@vitest/ui": "^5.0.1",
|
|
94
105
|
"@xterm/addon-clipboard": "^0.2.0",
|
|
95
106
|
"@xterm/addon-fit": "^0.11.0",
|
|
96
107
|
"@xterm/addon-image": "^0.9.0",
|
|
@@ -99,18 +110,19 @@
|
|
|
99
110
|
"@xterm/addon-webgl": "^0.19.0",
|
|
100
111
|
"@xterm/headless": "^6.0.0",
|
|
101
112
|
"@xterm/xterm": "^6.0.0",
|
|
102
|
-
"react": "^19.
|
|
103
|
-
"react-devtools-core": "^
|
|
104
|
-
"
|
|
113
|
+
"react": "^19.3.0",
|
|
114
|
+
"react-devtools-core": "^8.0.0",
|
|
115
|
+
"react-reconciler": "^0.34.0",
|
|
116
|
+
"scheduler": "^0.28.0",
|
|
117
|
+
"tsx": "^4.23.13",
|
|
105
118
|
"typescript": "^7.0.2",
|
|
106
|
-
"vite": "npm:@voidzero-dev/vite-plus-core@^0.2
|
|
107
|
-
"vite-plus": "^0.2
|
|
119
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@^0.3.2",
|
|
120
|
+
"vite-plus": "^0.3.2",
|
|
108
121
|
"vitest": "4.1.11",
|
|
109
122
|
"zigpty": "^0.2.1"
|
|
110
123
|
},
|
|
111
124
|
"peerDependencies": {
|
|
112
125
|
"@types/react": ">=19.2.0",
|
|
113
|
-
"react": ">=19.2.0",
|
|
114
126
|
"react-devtools-core": ">=6.1.2"
|
|
115
127
|
},
|
|
116
128
|
"peerDependenciesMeta": {
|
package/src/ansi/strip.ts
CHANGED
|
@@ -5,8 +5,8 @@ import { stripVTControlCharacters } from "node:util";
|
|
|
5
5
|
// `\u001B[38:2::255:100:0m` — which Sigil deliberately preserves in output
|
|
6
6
|
// (see sanitize-ansi.ts) — would leave `:2::255:100:0m` behind. Remove those
|
|
7
7
|
// first, then let Node handle everything else.
|
|
8
|
-
// https://github.com/nodejs/node/pull/65379
|
|
9
|
-
// can go once the minimum supported Node version ships it.
|
|
8
|
+
// https://github.com/nodejs/node/pull/65379 fixed this upstream (Node 24.21+);
|
|
9
|
+
// this wrapper can go once the minimum supported Node version ships it.
|
|
10
10
|
const colonSgrRegex = /(?:\u001B\[|\u009B)[\d;]*:[\d;:]*m/g;
|
|
11
11
|
|
|
12
12
|
export const stripAnsi = (input: string): string =>
|
|
@@ -253,6 +253,23 @@ const winopsResponse = new RegExp(`${ESC}\\[(4|6);(\\d+);(\\d+)t`);
|
|
|
253
253
|
const colorSchemeResponse = new RegExp(`${ESC}\\[\\?997;(\\d+)n`);
|
|
254
254
|
const da1Response = new RegExp(`${ESC}\\[\\?([\\d;]*)c`);
|
|
255
255
|
|
|
256
|
+
// Also used by the normal input decoder: replies can outlive the query timeout
|
|
257
|
+
// or arrive after its DA1 sentinel. Never deliver those bytes as keystrokes.
|
|
258
|
+
const terminalResponses = [
|
|
259
|
+
oscColorResponse,
|
|
260
|
+
kittyKeyboardResponse,
|
|
261
|
+
decrqmResponse,
|
|
262
|
+
xtversionResponse,
|
|
263
|
+
xtgettcapResponse,
|
|
264
|
+
kittyGraphicsResponse,
|
|
265
|
+
winopsResponse,
|
|
266
|
+
colorSchemeResponse,
|
|
267
|
+
da1Response,
|
|
268
|
+
].map((pattern) => new RegExp(`^(?:${pattern.source})$`));
|
|
269
|
+
|
|
270
|
+
export const isTerminalQueryResponse = (sequence: string): boolean =>
|
|
271
|
+
terminalResponses.some((pattern) => pattern.test(sequence));
|
|
272
|
+
|
|
256
273
|
const buildQuery = (palette: boolean, scope: "full" | "dynamic"): string => {
|
|
257
274
|
const queries = [
|
|
258
275
|
`${OSC}10;?${BEL}`, // foreground color
|
|
@@ -346,6 +363,10 @@ export const queryTerminal = async (
|
|
|
346
363
|
|
|
347
364
|
done = true;
|
|
348
365
|
clearTimeout(timer);
|
|
366
|
+
// Stop flowing before returning buffered bytes. Without this, unshift()
|
|
367
|
+
// can discard a partial reply between removing this data listener and
|
|
368
|
+
// the application's readable listener reattaching (especially on timeout).
|
|
369
|
+
stdin.pause();
|
|
349
370
|
stdin.removeListener("data", onData);
|
|
350
371
|
|
|
351
372
|
if (paletteColors.size === paletteSize) {
|
|
@@ -505,6 +526,7 @@ export const queryTerminal = async (
|
|
|
505
526
|
// Attach before writing so immediate responses aren't missed.
|
|
506
527
|
stdin.on("data", onData);
|
|
507
528
|
const timer = setTimeout(finish, timeout);
|
|
529
|
+
stdin.resume();
|
|
508
530
|
|
|
509
531
|
stdout.write(buildQuery(palette, scope));
|
|
510
532
|
});
|
package/src/devtools.ts
CHANGED
|
@@ -70,8 +70,13 @@ Object.defineProperty(globalThis, "__REACT_DEVTOOLS_COMPONENT_FILTERS__", {
|
|
|
70
70
|
const isDevToolsReachable = () =>
|
|
71
71
|
new Promise<boolean>((resolve) => {
|
|
72
72
|
const socket = new WebSocket("ws://localhost:8097");
|
|
73
|
+
let settled = false;
|
|
73
74
|
|
|
74
75
|
const settle = (reachable: boolean) => {
|
|
76
|
+
// Node 22 can emit another error synchronously when closing a failed
|
|
77
|
+
// connection. Mark it settled before close() re-enters this handler.
|
|
78
|
+
if (settled) return;
|
|
79
|
+
settled = true;
|
|
75
80
|
clearTimeout(timeout);
|
|
76
81
|
socket.close();
|
|
77
82
|
resolve(reachable);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { useMemo } from "react";
|
|
1
|
+
import { useMemo, useSyncExternalStore } from "react";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { getCapabilities } from "#/capabilities/store.ts";
|
|
4
|
+
import { useStdinContext } from "#/hooks/use-stdin.ts";
|
|
5
|
+
import { useStdout } from "#/hooks/use-stdout.ts";
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
Dimensions of the terminal window.
|
|
@@ -23,8 +25,13 @@ A React hook that returns the current terminal window dimensions and re-renders
|
|
|
23
25
|
Reads the capabilities store, so on terminals that send in-band size reports
|
|
24
26
|
(mode 2048) the dimensions are the emulator's own, arriving after it has
|
|
25
27
|
rewrapped its screen; elsewhere they are the stream's `columns`/`rows`.
|
|
28
|
+
Subscribing to dimensions does not initiate capability queries. In-band reports
|
|
29
|
+
are used when another consumer has explicitly enabled capability discovery.
|
|
26
30
|
*/
|
|
27
31
|
export const useWindowSize = (): WindowSize => {
|
|
28
|
-
const {
|
|
32
|
+
const { stdin } = useStdinContext();
|
|
33
|
+
const { stdout } = useStdout();
|
|
34
|
+
const store = getCapabilities(stdin, stdout);
|
|
35
|
+
const { size } = useSyncExternalStore(store.subscribe, () => store.current);
|
|
29
36
|
return useMemo(() => ({ columns: size.columns, rows: size.rows }), [size.columns, size.rows]);
|
|
30
37
|
};
|
package/src/input-parser.ts
CHANGED
|
@@ -42,6 +42,12 @@ const parseCsiSequence = (
|
|
|
42
42
|
return "pending";
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
// A new Escape or Ctrl+C cancels a truncated control sequence. Keep the
|
|
46
|
+
// cancelling byte for the next event, never insert the abandoned prefix.
|
|
47
|
+
if (byte === 0x1b || byte === 0x03) {
|
|
48
|
+
return { sequence: "", nextIndex: index };
|
|
49
|
+
}
|
|
50
|
+
|
|
45
51
|
if (isCsiParameterByte(byte) || isCsiIntermediateByte(byte)) {
|
|
46
52
|
continue;
|
|
47
53
|
}
|
|
@@ -99,6 +105,25 @@ const parseControlSequence = (
|
|
|
99
105
|
return parseCsiSequence(input, startIndex, prefixLength);
|
|
100
106
|
}
|
|
101
107
|
|
|
108
|
+
// OSC, DCS and APC replies are single events, even across stdin chunks.
|
|
109
|
+
if (sequenceType === "]" || sequenceType === "P" || sequenceType === "_") {
|
|
110
|
+
for (let index = startIndex + prefixLength + 1; index < input.length; index++) {
|
|
111
|
+
if (
|
|
112
|
+
input[index] === "\u0003" ||
|
|
113
|
+
(input[index] === escape && index + 1 < input.length && input[index + 1] !== "\\")
|
|
114
|
+
) {
|
|
115
|
+
return { sequence: "", nextIndex: index };
|
|
116
|
+
}
|
|
117
|
+
const bel = sequenceType === "]" && input[index] === "\u0007";
|
|
118
|
+
const st = input[index] === escape && input[index + 1] === "\\";
|
|
119
|
+
if (bel || st) {
|
|
120
|
+
const nextIndex = index + (st ? 2 : 1);
|
|
121
|
+
return { sequence: input.slice(startIndex, nextIndex), nextIndex };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return "pending";
|
|
125
|
+
}
|
|
126
|
+
|
|
102
127
|
if (sequenceType === "O") {
|
|
103
128
|
return parseSs3Sequence(input, startIndex, prefixLength);
|
|
104
129
|
}
|
|
@@ -232,7 +257,7 @@ const parseKeypresses = (input: string): ParsedInput => {
|
|
|
232
257
|
continue;
|
|
233
258
|
}
|
|
234
259
|
|
|
235
|
-
events.push(parsedEscapeSequence.sequence);
|
|
260
|
+
if (parsedEscapeSequence.sequence.length > 0) events.push(parsedEscapeSequence.sequence);
|
|
236
261
|
index = parsedEscapeSequence.nextIndex;
|
|
237
262
|
}
|
|
238
263
|
|
|
@@ -251,6 +276,9 @@ export type InputParser = {
|
|
|
251
276
|
|
|
252
277
|
export const createInputParser = (): InputParser => {
|
|
253
278
|
let pending = "";
|
|
279
|
+
// Only ambiguous Escape/Alt prefixes may time out. Once a control
|
|
280
|
+
// sequence starts, keep it intact until its terminator arrives.
|
|
281
|
+
const hasPendingEscape = () => pending.startsWith(escape) && !/^\u001B{1,2}[[\]P_]/.test(pending);
|
|
254
282
|
|
|
255
283
|
return {
|
|
256
284
|
push(chunk) {
|
|
@@ -258,17 +286,9 @@ export const createInputParser = (): InputParser => {
|
|
|
258
286
|
pending = parsedInput.pending;
|
|
259
287
|
return parsedInput.events;
|
|
260
288
|
},
|
|
261
|
-
hasPendingEscape
|
|
262
|
-
// Don't trigger the escape flush timer while assembling a paste start
|
|
263
|
-
// marker (`\u001B[200` and then `~`) or while waiting for paste end.
|
|
264
|
-
return (
|
|
265
|
-
pending.startsWith(escape) &&
|
|
266
|
-
!pending.startsWith(pasteStart) &&
|
|
267
|
-
pending !== pasteStart.slice(0, -1)
|
|
268
|
-
);
|
|
269
|
-
},
|
|
289
|
+
hasPendingEscape,
|
|
270
290
|
flushPendingEscape() {
|
|
271
|
-
if (!
|
|
291
|
+
if (!hasPendingEscape()) {
|
|
272
292
|
return;
|
|
273
293
|
}
|
|
274
294
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// `react/jsx-runtime` is CommonJS; a star re-export carries no static names
|
|
2
|
+
// through the bundler, so the automatic-runtime surface is spelled out.
|
|
3
|
+
export { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
// `jsxImportSource` looks up the `JSX` namespace on this module to type
|
|
5
|
+
// elements and props. Type-only, so the bundle is unaffected.
|
|
6
|
+
export type { JSX } from "react/jsx-runtime";
|
package/src/react.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Sigil ships its own React. Consumers reach React's runtime through this
|
|
2
|
+
// entry (and `jsxImportSource: "@alchemy.run/sigil"`) so the hooks a component
|
|
3
|
+
// calls and the dispatcher the reconciler installs share one module identity.
|
|
4
|
+
//
|
|
5
|
+
// `@types/react` is an `export =` module, so `export *` is rejected at the type
|
|
6
|
+
// level; the runtime surface is enumerated instead. Types stay type-only
|
|
7
|
+
// imports from `react` (erased at runtime, so no identity concern).
|
|
8
|
+
export {
|
|
9
|
+
Activity,
|
|
10
|
+
Children,
|
|
11
|
+
Component,
|
|
12
|
+
Fragment,
|
|
13
|
+
Profiler,
|
|
14
|
+
PureComponent,
|
|
15
|
+
StrictMode,
|
|
16
|
+
Suspense,
|
|
17
|
+
ViewTransition,
|
|
18
|
+
act,
|
|
19
|
+
addTransitionType,
|
|
20
|
+
cache,
|
|
21
|
+
cacheSignal,
|
|
22
|
+
captureOwnerStack,
|
|
23
|
+
cloneElement,
|
|
24
|
+
createContext,
|
|
25
|
+
createElement,
|
|
26
|
+
createRef,
|
|
27
|
+
forwardRef,
|
|
28
|
+
isValidElement,
|
|
29
|
+
lazy,
|
|
30
|
+
memo,
|
|
31
|
+
startTransition,
|
|
32
|
+
use,
|
|
33
|
+
useActionState,
|
|
34
|
+
useCallback,
|
|
35
|
+
useContext,
|
|
36
|
+
useDebugValue,
|
|
37
|
+
useDeferredValue,
|
|
38
|
+
useEffect,
|
|
39
|
+
useEffectEvent,
|
|
40
|
+
useId,
|
|
41
|
+
useImperativeHandle,
|
|
42
|
+
useInsertionEffect,
|
|
43
|
+
useLayoutEffect,
|
|
44
|
+
useMemo,
|
|
45
|
+
useOptimistic,
|
|
46
|
+
useReducer,
|
|
47
|
+
useRef,
|
|
48
|
+
useState,
|
|
49
|
+
useSyncExternalStore,
|
|
50
|
+
useTransition,
|
|
51
|
+
version,
|
|
52
|
+
} from "react";
|
|
53
|
+
export { default } from "react";
|
package/src/reconciler.ts
CHANGED
|
@@ -132,6 +132,56 @@ type HostContext = {
|
|
|
132
132
|
|
|
133
133
|
let currentUpdatePriority = NoEventPriority;
|
|
134
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Host hooks react-reconciler 0.34 (React 19.3) added for View Transitions
|
|
137
|
+
* and Fragment refs. `@types/react-reconciler` (0.33) does not declare them
|
|
138
|
+
* yet, so they are spread in rather than written inline (excess-property
|
|
139
|
+
* checks would reject them on the literal).
|
|
140
|
+
*
|
|
141
|
+
* A terminal has no view transitions, so a `<ViewTransition>` commits like
|
|
142
|
+
* any other update: `startViewTransition` mirrors react-dom's fallback when
|
|
143
|
+
* the document can't animate — run the commit phases synchronously and
|
|
144
|
+
* return no transition handle. `suspendOnActiveViewTransition` is on the
|
|
145
|
+
* hot path: the reconciler calls it for every transition-lane commit, so
|
|
146
|
+
* without it `startTransition` / `useTransition` updates never land.
|
|
147
|
+
*/
|
|
148
|
+
const viewTransitionHostConfig = {
|
|
149
|
+
suspendOnActiveViewTransition() {},
|
|
150
|
+
startViewTransition(
|
|
151
|
+
_suspendedState: unknown,
|
|
152
|
+
_rootContainer: DOMElement,
|
|
153
|
+
_transitionTypes: unknown,
|
|
154
|
+
mutationCallback: () => void,
|
|
155
|
+
layoutCallback: () => void,
|
|
156
|
+
_afterMutationCallback: () => void,
|
|
157
|
+
spawnedWorkCallback: () => void,
|
|
158
|
+
_passiveCallback: () => void,
|
|
159
|
+
_errorCallback: (error: unknown) => void,
|
|
160
|
+
_blockedCallback: (reason: string) => void,
|
|
161
|
+
finishedAnimation: () => void,
|
|
162
|
+
): null {
|
|
163
|
+
mutationCallback();
|
|
164
|
+
layoutCallback();
|
|
165
|
+
finishedAnimation();
|
|
166
|
+
spawnedWorkCallback();
|
|
167
|
+
return null;
|
|
168
|
+
},
|
|
169
|
+
stopViewTransition() {},
|
|
170
|
+
createViewTransitionInstance: (name: string) => ({ name }),
|
|
171
|
+
measureInstance: () => null,
|
|
172
|
+
measureClonedInstance: () => null,
|
|
173
|
+
wasInstanceInViewport: () => false,
|
|
174
|
+
hasInstanceChanged: () => false,
|
|
175
|
+
hasInstanceAffectedParent: () => false,
|
|
176
|
+
applyViewTransitionName() {},
|
|
177
|
+
restoreViewTransitionName() {},
|
|
178
|
+
cancelViewTransitionName() {},
|
|
179
|
+
cancelRootViewTransitionName() {},
|
|
180
|
+
restoreRootViewTransitionName() {},
|
|
181
|
+
createFragmentInstance: (fiber: unknown) => ({ fiber }),
|
|
182
|
+
updateFragmentInstanceFiber() {},
|
|
183
|
+
};
|
|
184
|
+
|
|
135
185
|
export const reconciler = createReconciler<
|
|
136
186
|
ElementNames,
|
|
137
187
|
Props,
|
|
@@ -422,4 +472,5 @@ export const reconciler = createReconciler<
|
|
|
422
472
|
},
|
|
423
473
|
rendererPackageName: pkg.name,
|
|
424
474
|
rendererVersion: pkg.version,
|
|
475
|
+
...viewTransitionHostConfig,
|
|
425
476
|
});
|
package/src/terminal/input.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isTerminalQueryResponse } from "#/capabilities/query.ts";
|
|
1
2
|
import type { CapabilitiesStore } from "#/capabilities/store.ts";
|
|
2
3
|
import { createInputParser, type InputEvent } from "#/input-parser.ts";
|
|
3
4
|
|
|
@@ -25,13 +26,18 @@ export class TerminalInput {
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
push(chunk: string): InputEvent[] {
|
|
28
|
-
return this.#parser.push(chunk).
|
|
29
|
-
if (typeof event !== "string") return
|
|
30
|
-
|
|
29
|
+
return this.#parser.push(chunk).flatMap((event): InputEvent[] => {
|
|
30
|
+
if (typeof event !== "string") return [event];
|
|
31
|
+
// A user Escape immediately before a reply is not an Alt-modified key.
|
|
32
|
+
if (event.startsWith("\u001B\u001B") && isTerminalQueryResponse(event.slice(1))) {
|
|
33
|
+
return ["\u001B"];
|
|
34
|
+
}
|
|
35
|
+
if (this.#capabilities.ingest(event)) return [];
|
|
36
|
+
if (isTerminalQueryResponse(event)) return [];
|
|
31
37
|
const mouse = parseMouseEvent(event);
|
|
32
|
-
if (!mouse) return
|
|
38
|
+
if (!mouse) return [event];
|
|
33
39
|
for (const listener of this.#mouseListeners) listener(mouse);
|
|
34
|
-
return
|
|
40
|
+
return [];
|
|
35
41
|
});
|
|
36
42
|
}
|
|
37
43
|
|