ink 6.7.0 → 6.8.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/build/ansi-tokenizer.d.ts +38 -0
- package/build/ansi-tokenizer.js +316 -0
- package/build/ansi-tokenizer.js.map +1 -0
- package/build/components/App.d.ts +1 -1
- package/build/components/App.js +60 -29
- package/build/components/App.js.map +1 -1
- package/build/components/AppContext.d.ts +5 -1
- package/build/components/AppContext.js.map +1 -1
- package/build/components/Cursor.d.ts +83 -0
- package/build/components/Cursor.js +53 -0
- package/build/components/Cursor.js.map +1 -0
- package/build/dom.js +5 -4
- package/build/dom.js.map +1 -1
- package/build/index.d.ts +2 -0
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/build/ink.d.ts +7 -3
- package/build/ink.js +151 -50
- package/build/ink.js.map +1 -1
- package/build/input-parser.d.ts +7 -0
- package/build/input-parser.js +154 -0
- package/build/input-parser.js.map +1 -0
- package/build/layout.d.ts +7 -0
- package/build/layout.js +33 -0
- package/build/layout.js.map +1 -0
- package/build/output.d.ts +1 -0
- package/build/output.js +38 -5
- package/build/output.js.map +1 -1
- package/build/reconciler.js +12 -2
- package/build/reconciler.js.map +1 -1
- package/build/render-to-string.d.ts +38 -0
- package/build/render-to-string.js +115 -0
- package/build/render-to-string.js.map +1 -0
- package/build/render.d.ts +12 -1
- package/build/render.js.map +1 -1
- package/build/sanitize-ansi.d.ts +2 -0
- package/build/sanitize-ansi.js +27 -0
- package/build/sanitize-ansi.js.map +1 -0
- package/build/squash-text-nodes.js +2 -1
- package/build/squash-text-nodes.js.map +1 -1
- package/build/utils.d.ts +2 -0
- package/build/utils.js +4 -0
- package/build/utils.js.map +1 -0
- package/package.json +10 -7
- package/readme.md +125 -13
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import React, { type RefObject } from 'react';
|
|
2
|
+
import { type DOMElement, type CursorAnchorMode } from '../dom.js';
|
|
3
|
+
export type Props = {
|
|
4
|
+
/**
|
|
5
|
+
Optional reference to anchor cursor coordinates to a different element.
|
|
6
|
+
|
|
7
|
+
By default, `anchorRef` uses `anchor="textEnd"` behavior to follow the rendered end of that element's text, including wrapping and wide characters.
|
|
8
|
+
|
|
9
|
+
Use this for inputs where the cursor should stay at the visible end of text.
|
|
10
|
+
|
|
11
|
+
If `anchorRef` is set but currently unresolved, Ink hides the cursor for that frame unless `anchor="flow"` is used.
|
|
12
|
+
|
|
13
|
+
If multiple `<Cursor>` components are rendered in one frame, the last rendered one controls terminal cursor position.
|
|
14
|
+
*/
|
|
15
|
+
readonly anchorRef?: RefObject<DOMElement | null>;
|
|
16
|
+
/**
|
|
17
|
+
Anchor mode used to resolve cursor coordinates.
|
|
18
|
+
|
|
19
|
+
- `'flow'`: Anchor to `<Cursor />` position in layout flow.
|
|
20
|
+
Use this when you place `<Cursor />` exactly where it should appear.
|
|
21
|
+
|
|
22
|
+
- `'origin'`: Anchor to content origin (top-left) of `anchorRef` or parent when no `anchorRef` is provided.
|
|
23
|
+
Use this for manual `x/y` positioning.
|
|
24
|
+
|
|
25
|
+
- `'textEnd'`: Anchor to rendered end of text for `anchorRef` or parent when no `anchorRef` is provided.
|
|
26
|
+
Use this when cursor should follow wrapped text.
|
|
27
|
+
|
|
28
|
+
Defaults to `'flow'` when `anchorRef` is omitted and `'textEnd'` when `anchorRef` is provided.
|
|
29
|
+
|
|
30
|
+
`'flow'` is the default without `anchorRef` to avoid coupling cursor position to surrounding sibling text changes.
|
|
31
|
+
*/
|
|
32
|
+
readonly anchor?: CursorAnchorMode;
|
|
33
|
+
/**
|
|
34
|
+
Horizontal offset from resolved anchor position.
|
|
35
|
+
*/
|
|
36
|
+
readonly x?: number;
|
|
37
|
+
/**
|
|
38
|
+
Vertical offset from resolved anchor position.
|
|
39
|
+
*/
|
|
40
|
+
readonly y?: number;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
Declaratively position the terminal cursor relative to a container.
|
|
44
|
+
|
|
45
|
+
Use this component when building reusable inputs where absolute root coordinates are inconvenient.
|
|
46
|
+
|
|
47
|
+
`<Cursor>` must not be rendered inside `<Text>`.
|
|
48
|
+
|
|
49
|
+
@example
|
|
50
|
+
```jsx
|
|
51
|
+
import {Box, Cursor, Text} from 'ink';
|
|
52
|
+
import {useRef} from 'react';
|
|
53
|
+
|
|
54
|
+
const prompt = '> ';
|
|
55
|
+
const value = 'hello';
|
|
56
|
+
|
|
57
|
+
const Example = () => {
|
|
58
|
+
return (
|
|
59
|
+
<Box flexDirection="row">
|
|
60
|
+
<Text>{prompt}</Text>
|
|
61
|
+
<Text>{value}</Text>
|
|
62
|
+
<Cursor />
|
|
63
|
+
</Box>
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```jsx
|
|
69
|
+
const ExampleWithAnchor = () => {
|
|
70
|
+
const lineReference = useRef();
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<Box flexDirection="column">
|
|
74
|
+
<Box ref={lineReference}>
|
|
75
|
+
<Text>{`${prompt}${value}`}</Text>
|
|
76
|
+
</Box>
|
|
77
|
+
<Cursor anchorRef={lineReference} />
|
|
78
|
+
</Box>
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
```
|
|
82
|
+
*/
|
|
83
|
+
export default function Cursor({ anchorRef, anchor, x, y }: Props): React.JSX.Element;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
Declaratively position the terminal cursor relative to a container.
|
|
4
|
+
|
|
5
|
+
Use this component when building reusable inputs where absolute root coordinates are inconvenient.
|
|
6
|
+
|
|
7
|
+
`<Cursor>` must not be rendered inside `<Text>`.
|
|
8
|
+
|
|
9
|
+
@example
|
|
10
|
+
```jsx
|
|
11
|
+
import {Box, Cursor, Text} from 'ink';
|
|
12
|
+
import {useRef} from 'react';
|
|
13
|
+
|
|
14
|
+
const prompt = '> ';
|
|
15
|
+
const value = 'hello';
|
|
16
|
+
|
|
17
|
+
const Example = () => {
|
|
18
|
+
return (
|
|
19
|
+
<Box flexDirection="row">
|
|
20
|
+
<Text>{prompt}</Text>
|
|
21
|
+
<Text>{value}</Text>
|
|
22
|
+
<Cursor />
|
|
23
|
+
</Box>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```jsx
|
|
29
|
+
const ExampleWithAnchor = () => {
|
|
30
|
+
const lineReference = useRef();
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<Box flexDirection="column">
|
|
34
|
+
<Box ref={lineReference}>
|
|
35
|
+
<Text>{`${prompt}${value}`}</Text>
|
|
36
|
+
</Box>
|
|
37
|
+
<Cursor anchorRef={lineReference} />
|
|
38
|
+
</Box>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
*/
|
|
43
|
+
export default function Cursor({ anchorRef, anchor, x = 0, y = 0 }) {
|
|
44
|
+
const normalizedAnchorReference = anchorRef ?? undefined;
|
|
45
|
+
const normalizedAnchor = anchor ?? (normalizedAnchorReference ? 'textEnd' : 'flow');
|
|
46
|
+
return (React.createElement("ink-cursor", { internal_cursor: {
|
|
47
|
+
anchorRef: normalizedAnchorReference,
|
|
48
|
+
anchor: normalizedAnchor,
|
|
49
|
+
x,
|
|
50
|
+
y,
|
|
51
|
+
} }));
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=Cursor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Cursor.js","sourceRoot":"","sources":["../../src/components/Cursor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuB,MAAM,OAAO,CAAC;AAmD5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwCE;AACF,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,EAAC,SAAS,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAQ;IACtE,MAAM,yBAAyB,GAC9B,SAAS,IAAI,SAAS,CAAC;IACxB,MAAM,gBAAgB,GACrB,MAAM,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAE5D,OAAO,CACN,oCACC,eAAe,EAAE;YAChB,SAAS,EAAE,yBAAyB;YACpC,MAAM,EAAE,gBAAgB;YACxB,CAAC;YACD,CAAC;SACD,GACA,CACF,CAAC;AACH,CAAC"}
|
package/build/dom.js
CHANGED
|
@@ -42,11 +42,12 @@ export const insertBeforeNode = (node, newChildNode, beforeChildNode) => {
|
|
|
42
42
|
if (newChildNode.yogaNode) {
|
|
43
43
|
node.yogaNode?.insertChild(newChildNode.yogaNode, index);
|
|
44
44
|
}
|
|
45
|
-
return;
|
|
46
45
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
else {
|
|
47
|
+
node.childNodes.push(newChildNode);
|
|
48
|
+
if (newChildNode.yogaNode) {
|
|
49
|
+
node.yogaNode?.insertChild(newChildNode.yogaNode, node.yogaNode.getChildCount());
|
|
50
|
+
}
|
|
50
51
|
}
|
|
51
52
|
if (node.nodeName === 'ink-text' || node.nodeName === 'ink-virtual-text') {
|
|
52
53
|
markNodeAsDirty(node);
|
package/build/dom.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dom.js","sourceRoot":"","sources":["../src/dom.ts"],"names":[],"mappings":"AAAA,OAAO,IAA6B,MAAM,aAAa,CAAC;AACxD,OAAO,WAAW,MAAM,mBAAmB,CAAC;AAE5C,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,eAAe,MAAM,wBAAwB,CAAC;AAoFrD,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,QAAsB,EAAc,EAAE;IAChE,MAAM,IAAI,GAAe;QACxB,QAAQ;QACR,KAAK,EAAE,EAAE;QACT,UAAU,EAAE,EAAE;QACd,UAAU,EAAE,EAAE;QACd,UAAU,EAAE,SAAS;QACrB,QAAQ,EAAE,QAAQ,KAAK,kBAAkB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;QAC1E,gEAAgE;QAChE,sBAAsB,EAAE,EAAE;KAC1B,CAAC;IAEF,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;QAC7B,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAC9B,IAAgB,EAChB,SAAqB,EACd,EAAE;IACT,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;QAC1B,eAAe,CAAC,SAAS,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAClD,CAAC;IAED,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAEhC,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC;QACxB,IAAI,CAAC,QAAQ,EAAE,WAAW,CACzB,SAAS,CAAC,QAAQ,EAClB,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAC7B,CAAC;IACH,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,KAAK,UAAU,IAAI,IAAI,CAAC,QAAQ,KAAK,kBAAkB,EAAE,CAAC;QAC1E,eAAe,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;AACF,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC/B,IAAgB,EAChB,YAAqB,EACrB,eAAwB,EACjB,EAAE;IACT,IAAI,YAAY,CAAC,UAAU,EAAE,CAAC;QAC7B,eAAe,CAAC,YAAY,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IACxD,CAAC;IAED,YAAY,CAAC,UAAU,GAAG,IAAI,CAAC;IAE/B,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IACvD,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QAChB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC;QAC/C,IAAI,YAAY,CAAC,QAAQ,EAAE,CAAC;YAC3B,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC1D,CAAC;
|
|
1
|
+
{"version":3,"file":"dom.js","sourceRoot":"","sources":["../src/dom.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export type { RenderOptions, Instance } from './render.js';
|
|
2
2
|
export { default as render } from './render.js';
|
|
3
|
+
export type { RenderToStringOptions } from './render-to-string.js';
|
|
4
|
+
export { default as renderToString } from './render-to-string.js';
|
|
3
5
|
export type { Props as BoxProps } from './components/Box.js';
|
|
4
6
|
export { default as Box } from './components/Box.js';
|
|
5
7
|
export type { Props as TextProps } from './components/Text.js';
|
package/build/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { default as render } from './render.js';
|
|
2
|
+
export { default as renderToString } from './render-to-string.js';
|
|
2
3
|
export { default as Box } from './components/Box.js';
|
|
3
4
|
export { default as Text } from './components/Text.js';
|
|
4
5
|
export { default as Static } from './components/Static.js';
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAC,OAAO,IAAI,GAAG,EAAC,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAC,OAAO,IAAI,IAAI,EAAC,MAAM,sBAAsB,CAAC;AAMrD,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,2BAA2B,CAAC;AAE/D,OAAO,EAAC,OAAO,IAAI,OAAO,EAAC,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAC,OAAO,IAAI,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAC,OAAO,IAAI,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAC,OAAO,IAAI,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAC,OAAO,IAAI,eAAe,EAAC,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAC,OAAO,IAAI,wBAAwB,EAAC,MAAM,yCAAyC,CAAC;AAC5F,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAAC,OAAO,IAAI,cAAc,EAAC,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAC,UAAU,EAAE,cAAc,EAAC,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAC,OAAO,IAAI,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAEhE,OAAO,EAAC,OAAO,IAAI,GAAG,EAAC,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAC,OAAO,IAAI,IAAI,EAAC,MAAM,sBAAsB,CAAC;AAMrD,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,2BAA2B,CAAC;AAE/D,OAAO,EAAC,OAAO,IAAI,OAAO,EAAC,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAC,OAAO,IAAI,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAC,OAAO,IAAI,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAC,OAAO,IAAI,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAC,OAAO,IAAI,eAAe,EAAC,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAC,OAAO,IAAI,wBAAwB,EAAC,MAAM,yCAAyC,CAAC;AAC5F,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAAC,OAAO,IAAI,cAAc,EAAC,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAC,UAAU,EAAE,cAAc,EAAC,MAAM,qBAAqB,CAAC"}
|
package/build/ink.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export type Options = {
|
|
|
19
19
|
patchConsole: boolean;
|
|
20
20
|
onRender?: (metrics: RenderMetrics) => void;
|
|
21
21
|
isScreenReaderEnabled?: boolean;
|
|
22
|
-
waitUntilExit?: () => Promise<
|
|
22
|
+
waitUntilExit?: () => Promise<unknown>;
|
|
23
23
|
maxFps?: number;
|
|
24
24
|
incrementalRendering?: boolean;
|
|
25
25
|
/**
|
|
@@ -49,6 +49,7 @@ export default class Ink {
|
|
|
49
49
|
private readonly throttledLog;
|
|
50
50
|
private readonly isScreenReaderEnabled;
|
|
51
51
|
private isUnmounted;
|
|
52
|
+
private isUnmounting;
|
|
52
53
|
private lastOutput;
|
|
53
54
|
private lastOutputToRender;
|
|
54
55
|
private lastOutputHeight;
|
|
@@ -57,18 +58,21 @@ export default class Ink {
|
|
|
57
58
|
private readonly rootNode;
|
|
58
59
|
private fullStaticOutput;
|
|
59
60
|
private exitPromise?;
|
|
61
|
+
private exitResult;
|
|
60
62
|
private beforeExitHandler?;
|
|
61
63
|
private restoreConsole?;
|
|
62
64
|
private readonly unsubscribeResize?;
|
|
63
65
|
private readonly throttledOnRender?;
|
|
66
|
+
private hasPendingThrottledRender;
|
|
64
67
|
private kittyProtocolEnabled;
|
|
65
68
|
private cancelKittyDetection?;
|
|
66
69
|
constructor(options: Options);
|
|
67
70
|
getTerminalWidth: () => number;
|
|
68
71
|
resized: () => void;
|
|
69
|
-
resolveExitPromise: () => void;
|
|
72
|
+
resolveExitPromise: (result?: unknown) => void;
|
|
70
73
|
rejectExitPromise: (reason?: Error) => void;
|
|
71
74
|
unsubscribeExit: () => void;
|
|
75
|
+
handleAppExit: (errorOrResult?: unknown) => void;
|
|
72
76
|
setCursorPosition: (position: CursorPosition | undefined) => void;
|
|
73
77
|
restoreLastOutput: () => void;
|
|
74
78
|
calculateLayout: () => void;
|
|
@@ -77,7 +81,7 @@ export default class Ink {
|
|
|
77
81
|
writeToStdout(data: string): void;
|
|
78
82
|
writeToStderr(data: string): void;
|
|
79
83
|
unmount(error?: Error | number | null): void;
|
|
80
|
-
waitUntilExit(): Promise<
|
|
84
|
+
waitUntilExit(): Promise<unknown>;
|
|
81
85
|
clear(): void;
|
|
82
86
|
patchConsole(): void;
|
|
83
87
|
private initKittyKeyboard;
|
package/build/ink.js
CHANGED
|
@@ -10,6 +10,7 @@ import { LegacyRoot, ConcurrentRoot } from 'react-reconciler/constants.js';
|
|
|
10
10
|
import Yoga from 'yoga-layout';
|
|
11
11
|
import wrapAnsi from 'wrap-ansi';
|
|
12
12
|
import terminalSize from 'terminal-size';
|
|
13
|
+
import { isDev } from './utils.js';
|
|
13
14
|
import reconciler from './reconciler.js';
|
|
14
15
|
import render from './renderer.js';
|
|
15
16
|
import * as dom from './dom.js';
|
|
@@ -20,6 +21,65 @@ import App from './components/App.js';
|
|
|
20
21
|
import { accessibilityContext as AccessibilityContext } from './components/AccessibilityContext.js';
|
|
21
22
|
import { resolveFlags, } from './kitty-keyboard.js';
|
|
22
23
|
const noop = () => { };
|
|
24
|
+
const kittyQueryEscapeByte = 0x1b;
|
|
25
|
+
const kittyQueryOpenBracketByte = 0x5b;
|
|
26
|
+
const kittyQueryQuestionMarkByte = 0x3f;
|
|
27
|
+
const kittyQueryLetterByte = 0x75;
|
|
28
|
+
const zeroByte = 0x30;
|
|
29
|
+
const nineByte = 0x39;
|
|
30
|
+
const isDigitByte = (byte) => byte >= zeroByte && byte <= nineByte;
|
|
31
|
+
const matchKittyQueryResponse = (buffer, startIndex) => {
|
|
32
|
+
if (buffer[startIndex] !== kittyQueryEscapeByte ||
|
|
33
|
+
buffer[startIndex + 1] !== kittyQueryOpenBracketByte ||
|
|
34
|
+
buffer[startIndex + 2] !== kittyQueryQuestionMarkByte) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
let index = startIndex + 3;
|
|
38
|
+
const digitsStartIndex = index;
|
|
39
|
+
while (index < buffer.length && isDigitByte(buffer[index])) {
|
|
40
|
+
index++;
|
|
41
|
+
}
|
|
42
|
+
if (index === digitsStartIndex) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
if (index === buffer.length) {
|
|
46
|
+
return { state: 'partial' };
|
|
47
|
+
}
|
|
48
|
+
if (buffer[index] === kittyQueryLetterByte) {
|
|
49
|
+
return { state: 'complete', endIndex: index };
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
};
|
|
53
|
+
const hasCompleteKittyQueryResponse = (buffer) => {
|
|
54
|
+
for (let index = 0; index < buffer.length; index++) {
|
|
55
|
+
const match = matchKittyQueryResponse(buffer, index);
|
|
56
|
+
if (match?.state === 'complete') {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
};
|
|
62
|
+
const stripKittyQueryResponsesAndTrailingPartial = (buffer) => {
|
|
63
|
+
const keptBytes = [];
|
|
64
|
+
let index = 0;
|
|
65
|
+
while (index < buffer.length) {
|
|
66
|
+
const match = matchKittyQueryResponse(buffer, index);
|
|
67
|
+
if (match?.state === 'complete') {
|
|
68
|
+
index = match.endIndex + 1;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (match?.state === 'partial') {
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
keptBytes.push(buffer[index]);
|
|
75
|
+
index++;
|
|
76
|
+
}
|
|
77
|
+
return keptBytes;
|
|
78
|
+
};
|
|
79
|
+
const isErrorInput = (value) => {
|
|
80
|
+
return (value instanceof Error ||
|
|
81
|
+
Object.prototype.toString.call(value) === '[object Error]');
|
|
82
|
+
};
|
|
23
83
|
export default class Ink {
|
|
24
84
|
/**
|
|
25
85
|
Whether this instance is using concurrent rendering mode.
|
|
@@ -32,6 +92,7 @@ export default class Ink {
|
|
|
32
92
|
isScreenReaderEnabled;
|
|
33
93
|
// Ignore last render after unmounting a tree to prevent empty output before exit
|
|
34
94
|
isUnmounted;
|
|
95
|
+
isUnmounting;
|
|
35
96
|
lastOutput;
|
|
36
97
|
lastOutputToRender;
|
|
37
98
|
lastOutputHeight;
|
|
@@ -42,10 +103,12 @@ export default class Ink {
|
|
|
42
103
|
// so that it's rerendered every time, not just new static parts, like in non-debug mode
|
|
43
104
|
fullStaticOutput;
|
|
44
105
|
exitPromise;
|
|
106
|
+
exitResult;
|
|
45
107
|
beforeExitHandler;
|
|
46
108
|
restoreConsole;
|
|
47
109
|
unsubscribeResize;
|
|
48
110
|
throttledOnRender;
|
|
111
|
+
hasPendingThrottledRender = false;
|
|
49
112
|
kittyProtocolEnabled = false;
|
|
50
113
|
cancelKittyDetection;
|
|
51
114
|
constructor(options) {
|
|
@@ -68,7 +131,10 @@ export default class Ink {
|
|
|
68
131
|
leading: true,
|
|
69
132
|
trailing: true,
|
|
70
133
|
});
|
|
71
|
-
this.rootNode.onRender =
|
|
134
|
+
this.rootNode.onRender = () => {
|
|
135
|
+
this.hasPendingThrottledRender = true;
|
|
136
|
+
throttled();
|
|
137
|
+
};
|
|
72
138
|
this.throttledOnRender = throttled;
|
|
73
139
|
}
|
|
74
140
|
this.rootNode.onImmediateRender = this.onRender;
|
|
@@ -94,6 +160,7 @@ export default class Ink {
|
|
|
94
160
|
});
|
|
95
161
|
// Ignore last render after unmounting a tree to prevent empty output before exit
|
|
96
162
|
this.isUnmounted = false;
|
|
163
|
+
this.isUnmounting = false;
|
|
97
164
|
// Store concurrent mode setting
|
|
98
165
|
this.isConcurrent = options.concurrent ?? false;
|
|
99
166
|
// Store last output to only rerender when needed
|
|
@@ -110,14 +177,9 @@ export default class Ink {
|
|
|
110
177
|
this.container = reconciler.createContainer(this.rootNode, rootTag, null, false, null, 'id', () => { }, () => { }, () => { }, () => { });
|
|
111
178
|
// Unmount when process exits
|
|
112
179
|
this.unsubscribeExit = signalExit(this.unmount, { alwaysLast: false });
|
|
113
|
-
if (
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// Reporting React DOM's version, not Ink's
|
|
117
|
-
// See https://github.com/facebook/react/issues/16666#issuecomment-532639905
|
|
118
|
-
version: '16.13.1',
|
|
119
|
-
rendererPackageName: 'ink',
|
|
120
|
-
});
|
|
180
|
+
if (isDev()) {
|
|
181
|
+
// @ts-expect-error outdated types
|
|
182
|
+
reconciler.injectIntoDevTools();
|
|
121
183
|
}
|
|
122
184
|
if (options.patchConsole) {
|
|
123
185
|
this.patchConsole();
|
|
@@ -154,6 +216,17 @@ export default class Ink {
|
|
|
154
216
|
resolveExitPromise = () => { };
|
|
155
217
|
rejectExitPromise = () => { };
|
|
156
218
|
unsubscribeExit = () => { };
|
|
219
|
+
handleAppExit = (errorOrResult) => {
|
|
220
|
+
if (this.isUnmounted || this.isUnmounting) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (isErrorInput(errorOrResult)) {
|
|
224
|
+
this.unmount(errorOrResult);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
this.exitResult = errorOrResult;
|
|
228
|
+
this.unmount();
|
|
229
|
+
};
|
|
157
230
|
setCursorPosition = (position) => {
|
|
158
231
|
this.cursorPosition = position;
|
|
159
232
|
this.log.setCursorPosition(position);
|
|
@@ -170,6 +243,7 @@ export default class Ink {
|
|
|
170
243
|
this.rootNode.yogaNode.calculateLayout(undefined, undefined, Yoga.DIRECTION_LTR);
|
|
171
244
|
};
|
|
172
245
|
onRender = () => {
|
|
246
|
+
this.hasPendingThrottledRender = false;
|
|
173
247
|
if (this.isUnmounted) {
|
|
174
248
|
return;
|
|
175
249
|
}
|
|
@@ -283,7 +357,7 @@ export default class Ink {
|
|
|
283
357
|
};
|
|
284
358
|
render(node) {
|
|
285
359
|
const tree = (React.createElement(AccessibilityContext.Provider, { value: { isScreenReaderEnabled: this.isScreenReaderEnabled } },
|
|
286
|
-
React.createElement(App, { stdin: this.options.stdin, stdout: this.options.stdout, stderr: this.options.stderr, exitOnCtrlC: this.options.exitOnCtrlC, writeToStdout: this.writeToStdout, writeToStderr: this.writeToStderr, setCursorPosition: this.setCursorPosition, onExit: this.
|
|
360
|
+
React.createElement(App, { stdin: this.options.stdin, stdout: this.options.stdout, stderr: this.options.stderr, exitOnCtrlC: this.options.exitOnCtrlC, writeToStdout: this.writeToStdout, writeToStderr: this.writeToStderr, setCursorPosition: this.setCursorPosition, onExit: this.handleAppExit }, node)));
|
|
287
361
|
if (this.options.concurrent) {
|
|
288
362
|
// Concurrent mode: use updateContainer (async scheduling)
|
|
289
363
|
reconciler.updateContainer(tree, this.container, null, noop);
|
|
@@ -343,19 +417,44 @@ export default class Ink {
|
|
|
343
417
|
}
|
|
344
418
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
345
419
|
unmount(error) {
|
|
346
|
-
if (this.isUnmounted) {
|
|
420
|
+
if (this.isUnmounted || this.isUnmounting) {
|
|
347
421
|
return;
|
|
348
422
|
}
|
|
423
|
+
this.isUnmounting = true;
|
|
349
424
|
if (this.beforeExitHandler) {
|
|
350
425
|
process.off('beforeExit', this.beforeExitHandler);
|
|
351
426
|
this.beforeExitHandler = undefined;
|
|
352
427
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
428
|
+
const stdout = this.options.stdout;
|
|
429
|
+
const canWriteToStdout = !stdout.destroyed && !stdout.writableEnded && (stdout.writable ?? true);
|
|
430
|
+
const settleThrottle = (throttled) => {
|
|
431
|
+
if (typeof throttled.flush !== 'function') {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
if (canWriteToStdout) {
|
|
435
|
+
throttled.flush();
|
|
436
|
+
}
|
|
437
|
+
else if (typeof throttled.cancel === 'function') {
|
|
438
|
+
throttled.cancel();
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
// Clear any pending throttled render timer on unmount. When stdout is writable,
|
|
442
|
+
// flush so the final frame is emitted; otherwise cancel to avoid delayed callbacks.
|
|
443
|
+
settleThrottle(this.throttledOnRender ?? {});
|
|
444
|
+
if (canWriteToStdout) {
|
|
445
|
+
// If throttling is enabled and there is already a pending render, flushing above
|
|
446
|
+
// is sufficient. Also avoid calling onRender() again when static output already
|
|
447
|
+
// exists, as that can duplicate <Static> children output on exit (see issue #397).
|
|
448
|
+
const shouldRenderFinalFrame = !this.throttledOnRender ||
|
|
449
|
+
(!this.hasPendingThrottledRender && this.fullStaticOutput === '');
|
|
450
|
+
if (shouldRenderFinalFrame) {
|
|
451
|
+
this.calculateLayout();
|
|
452
|
+
this.onRender();
|
|
453
|
+
}
|
|
356
454
|
}
|
|
357
|
-
|
|
358
|
-
|
|
455
|
+
// Mark as unmounted after the final render but before stdout writes
|
|
456
|
+
// that could re-enter exit() via synchronous write callbacks.
|
|
457
|
+
this.isUnmounted = true;
|
|
359
458
|
this.unsubscribeExit();
|
|
360
459
|
if (typeof this.restoreConsole === 'function') {
|
|
361
460
|
this.restoreConsole();
|
|
@@ -363,33 +462,33 @@ export default class Ink {
|
|
|
363
462
|
if (typeof this.unsubscribeResize === 'function') {
|
|
364
463
|
this.unsubscribeResize();
|
|
365
464
|
}
|
|
366
|
-
// Flush any pending throttled log writes
|
|
367
|
-
const throttledLog = this.throttledLog;
|
|
368
|
-
if (typeof throttledLog.flush === 'function') {
|
|
369
|
-
throttledLog.flush();
|
|
370
|
-
}
|
|
371
465
|
// Cancel any in-progress auto-detection before checking protocol state
|
|
372
466
|
if (this.cancelKittyDetection) {
|
|
373
467
|
this.cancelKittyDetection();
|
|
374
468
|
}
|
|
375
|
-
if
|
|
376
|
-
|
|
377
|
-
|
|
469
|
+
// Flush any pending throttled log writes if possible, otherwise cancel to
|
|
470
|
+
// prevent delayed callbacks from writing to a closed stream.
|
|
471
|
+
const throttledLog = this.throttledLog;
|
|
472
|
+
settleThrottle(throttledLog);
|
|
473
|
+
if (canWriteToStdout) {
|
|
474
|
+
if (this.kittyProtocolEnabled) {
|
|
475
|
+
try {
|
|
476
|
+
this.options.stdout.write('\u001B[<u');
|
|
477
|
+
}
|
|
478
|
+
catch {
|
|
479
|
+
// Best-effort: stdout may already be destroyed during shutdown
|
|
480
|
+
}
|
|
378
481
|
}
|
|
379
|
-
|
|
380
|
-
|
|
482
|
+
// CIs don't handle erasing ansi escapes well, so it's better to
|
|
483
|
+
// only render last frame of non-static output
|
|
484
|
+
if (isInCi) {
|
|
485
|
+
this.options.stdout.write(this.lastOutput + '\n');
|
|
486
|
+
}
|
|
487
|
+
else if (!this.options.debug) {
|
|
488
|
+
this.log.done();
|
|
381
489
|
}
|
|
382
|
-
this.kittyProtocolEnabled = false;
|
|
383
|
-
}
|
|
384
|
-
// CIs don't handle erasing ansi escapes well, so it's better to
|
|
385
|
-
// only render last frame of non-static output
|
|
386
|
-
if (isInCi) {
|
|
387
|
-
this.options.stdout.write(this.lastOutput + '\n');
|
|
388
|
-
}
|
|
389
|
-
else if (!this.options.debug) {
|
|
390
|
-
this.log.done();
|
|
391
490
|
}
|
|
392
|
-
this.
|
|
491
|
+
this.kittyProtocolEnabled = false;
|
|
393
492
|
if (this.options.concurrent) {
|
|
394
493
|
// Concurrent mode: use updateContainer (async scheduling)
|
|
395
494
|
reconciler.updateContainer(null, this.container, null, noop);
|
|
@@ -408,20 +507,22 @@ export default class Ink {
|
|
|
408
507
|
// When called from signal-exit during process shutdown (error is a
|
|
409
508
|
// number or null rather than undefined/Error), resolve synchronously
|
|
410
509
|
// because the event loop is draining and async callbacks won't fire.
|
|
510
|
+
const { exitResult } = this;
|
|
411
511
|
const resolveOrReject = () => {
|
|
412
|
-
if (error
|
|
512
|
+
if (isErrorInput(error)) {
|
|
413
513
|
this.rejectExitPromise(error);
|
|
414
514
|
}
|
|
415
515
|
else {
|
|
416
|
-
this.resolveExitPromise();
|
|
516
|
+
this.resolveExitPromise(exitResult);
|
|
417
517
|
}
|
|
418
518
|
};
|
|
419
|
-
const isProcessExiting = error !== undefined && !(error
|
|
519
|
+
const isProcessExiting = error !== undefined && !isErrorInput(error);
|
|
520
|
+
const hasWritableState = stdout._writableState !== undefined ||
|
|
521
|
+
stdout.writableLength !== undefined;
|
|
420
522
|
if (isProcessExiting) {
|
|
421
523
|
resolveOrReject();
|
|
422
524
|
}
|
|
423
|
-
else if (
|
|
424
|
-
this.options.stdout.writableLength !== undefined) {
|
|
525
|
+
else if (canWriteToStdout && hasWritableState) {
|
|
425
526
|
this.options.stdout.write('', resolveOrReject);
|
|
426
527
|
}
|
|
427
528
|
else {
|
|
@@ -495,7 +596,7 @@ export default class Ink {
|
|
|
495
596
|
}
|
|
496
597
|
confirmKittySupport(flags) {
|
|
497
598
|
const { stdin, stdout } = this.options;
|
|
498
|
-
let responseBuffer =
|
|
599
|
+
let responseBuffer = [];
|
|
499
600
|
const cleanup = () => {
|
|
500
601
|
this.cancelKittyDetection = undefined;
|
|
501
602
|
clearTimeout(timer);
|
|
@@ -503,18 +604,18 @@ export default class Ink {
|
|
|
503
604
|
// Re-emit any buffered data that wasn't the protocol response,
|
|
504
605
|
// so it isn't lost from Ink's normal input pipeline.
|
|
505
606
|
// Clear responseBuffer afterwards to make cleanup idempotent.
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
if (remaining) {
|
|
607
|
+
const remaining = stripKittyQueryResponsesAndTrailingPartial(responseBuffer);
|
|
608
|
+
responseBuffer = [];
|
|
609
|
+
if (remaining.length > 0) {
|
|
510
610
|
stdin.unshift(Buffer.from(remaining));
|
|
511
611
|
}
|
|
512
612
|
};
|
|
513
613
|
const onData = (data) => {
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
614
|
+
const chunk = typeof data === 'string' ? Buffer.from(data) : data;
|
|
615
|
+
for (const byte of chunk) {
|
|
616
|
+
responseBuffer.push(byte);
|
|
617
|
+
}
|
|
618
|
+
if (hasCompleteKittyQueryResponse(responseBuffer)) {
|
|
518
619
|
cleanup();
|
|
519
620
|
if (!this.isUnmounted) {
|
|
520
621
|
this.enableKittyProtocol(flags);
|