@textui/terminal 0.1.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/LICENSE +21 -0
- package/README.md +83 -0
- package/dist/ansi.d.ts +84 -0
- package/dist/ansi.d.ts.map +1 -0
- package/dist/ansi.js +102 -0
- package/dist/capabilities.d.ts +22 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +130 -0
- package/dist/capture.d.ts +24 -0
- package/dist/capture.d.ts.map +1 -0
- package/dist/capture.js +72 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/input.d.ts +28 -0
- package/dist/input.d.ts.map +1 -0
- package/dist/input.js +357 -0
- package/dist/node.d.ts +99 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +233 -0
- package/dist/svg.d.ts +74 -0
- package/dist/svg.d.ts.map +1 -0
- package/dist/svg.js +235 -0
- package/dist/virtual.d.ts +65 -0
- package/dist/virtual.d.ts.map +1 -0
- package/dist/virtual.js +137 -0
- package/dist/writer.d.ts +19 -0
- package/dist/writer.d.ts.map +1 -0
- package/dist/writer.js +173 -0
- package/package.json +62 -0
- package/src/ansi.ts +120 -0
- package/src/capabilities.ts +140 -0
- package/src/capture.ts +101 -0
- package/src/index.ts +17 -0
- package/src/input.ts +394 -0
- package/src/node.ts +329 -0
- package/src/svg.ts +352 -0
- package/src/virtual.ts +185 -0
- package/src/writer.ts +202 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Softov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# @textui/terminal
|
|
2
|
+
|
|
3
|
+
What [`@textui/core`](https://github.com/softov/textui/tree/main/packages/core) needs to reach an actual terminal: adapters,
|
|
4
|
+
capability detection, ANSI writing and input decoding.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm install @textui/terminal
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { createApp } from '@textui/core';
|
|
12
|
+
import { createNodeTerminal } from '@textui/terminal';
|
|
13
|
+
|
|
14
|
+
const app = createApp({ terminal: createNodeTerminal(), root: <App /> });
|
|
15
|
+
await app.start();
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Two adapters
|
|
19
|
+
|
|
20
|
+
`createNodeTerminal()` is the real one - stdin, stdout, resize, and the signal
|
|
21
|
+
handling that puts the screen back the way it found it when the process dies.
|
|
22
|
+
|
|
23
|
+
`createVirtualTerminal()` has no tty at all. It is what the test harness and
|
|
24
|
+
`--static` run on, and it is the reason a component that only works
|
|
25
|
+
interactively is a component nobody can test cheaply.
|
|
26
|
+
|
|
27
|
+
## Capabilities are detected, and can be lied to
|
|
28
|
+
|
|
29
|
+
Unicode level, colour depth, mouse, hyperlinks, the kitty keyboard protocol -
|
|
30
|
+
detection is right almost always, and the times it is not are the times nobody
|
|
31
|
+
is watching. So every capability can be forced, which is how you see the
|
|
32
|
+
terminal somebody else is sitting at:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
createNodeTerminal({ capabilities: { unicode: 'ascii', colors: 4 } });
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Under the kitty protocol, `ctrl+shift+f` is a distinct stroke from `ctrl+f`.
|
|
39
|
+
Without it the terminal sends the same byte for both, and no amount of decoding
|
|
40
|
+
recovers the difference.
|
|
41
|
+
|
|
42
|
+
## A frame you can keep
|
|
43
|
+
|
|
44
|
+
The screen is the output, so the next redraw destroys the frame that was wrong.
|
|
45
|
+
Two functions write one out instead - both from the buffer the runtime last
|
|
46
|
+
painted, neither needing a tty.
|
|
47
|
+
|
|
48
|
+
`captureBuffer` gives a frame a terminal can replay: every cell in order, no
|
|
49
|
+
cursor control, so it can go in a file or an issue. `colors: false` strips the
|
|
50
|
+
colour, which is the copy a diff can read.
|
|
51
|
+
|
|
52
|
+
`bufferToSvg` gives one a repository page can show, because an `.ans` file is
|
|
53
|
+
only a screenshot on a terminal:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
const svg = bufferToSvg(app.buffer(), {
|
|
57
|
+
background: app.theme.colors.canvas,
|
|
58
|
+
foreground: app.theme.colors.text,
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Self-contained - no font, no stylesheet, no script, nothing fetched - which is
|
|
63
|
+
what survives GitHub's image proxy. And it is text, so a committed screenshot
|
|
64
|
+
diffs and CI can check it instead of somebody re-taking it.
|
|
65
|
+
|
|
66
|
+
## What it needs from a stream
|
|
67
|
+
|
|
68
|
+
`TerminalInput` and `TerminalOutput`, which say what the adapter uses rather
|
|
69
|
+
than which stream it is - `setRawMode`, `columns`, `write`, and half a dozen
|
|
70
|
+
more. `process.stdin` and `process.stdout` satisfy them, so nothing changes for
|
|
71
|
+
a caller, and so do the streams of runtimes that are not node.
|
|
72
|
+
|
|
73
|
+
That is also why the published types name no Node interfaces: a package with no
|
|
74
|
+
dependencies should not need `@types/node` installed to compile.
|
|
75
|
+
|
|
76
|
+
## Runtime
|
|
77
|
+
|
|
78
|
+
No dependencies beyond `@textui/core`. Uses `process` for stdio and signals, and
|
|
79
|
+
no other Node API. Node 22+ and Bun.
|
|
80
|
+
|
|
81
|
+
## Documentation
|
|
82
|
+
|
|
83
|
+
<https://softov.github.io/textui/>
|
package/dist/ansi.d.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ANSI escape sequences.
|
|
3
|
+
*
|
|
4
|
+
* Everything the writer can emit is named here, so a capability check happens
|
|
5
|
+
* once - at the adapter - rather than scattered through the render path.
|
|
6
|
+
* Sequences are written with `\x1b` escapes rather than literal bytes so this
|
|
7
|
+
* file stays readable in a diff.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ESC = "\u001B";
|
|
10
|
+
export declare const CSI = "\u001B[";
|
|
11
|
+
export declare const OSC = "\u001B]";
|
|
12
|
+
export declare const ST = "\u001B\\";
|
|
13
|
+
export declare const BEL = "\u0007";
|
|
14
|
+
export declare const cursorTo: (x: number, y: number) => string;
|
|
15
|
+
export declare const cursorHome = "\u001B[H";
|
|
16
|
+
export declare const cursorHide = "\u001B[?25l";
|
|
17
|
+
export declare const cursorShow = "\u001B[?25h";
|
|
18
|
+
export declare const cursorSave = "\u001B7";
|
|
19
|
+
export declare const cursorRestore = "\u001B8";
|
|
20
|
+
export declare const cursorUp: (n?: number) => string;
|
|
21
|
+
export declare const cursorDown: (n?: number) => string;
|
|
22
|
+
export declare const cursorForward: (n?: number) => string;
|
|
23
|
+
export declare const cursorBack: (n?: number) => string;
|
|
24
|
+
export declare const cursorColumn: (x: number) => string;
|
|
25
|
+
/** Cursor shapes, for a text field that wants a bar rather than a block. */
|
|
26
|
+
export declare const cursorShape: (shape: "block" | "underline" | "bar", blinking?: boolean) => string;
|
|
27
|
+
export declare const eraseLine = "\u001B[2K";
|
|
28
|
+
export declare const eraseLineRight = "\u001B[0K";
|
|
29
|
+
export declare const eraseScreen = "\u001B[2J";
|
|
30
|
+
export declare const eraseDown = "\u001B[0J";
|
|
31
|
+
export declare const scrollUp: (n?: number) => string;
|
|
32
|
+
export declare const altScreenEnter = "\u001B[?1049h";
|
|
33
|
+
export declare const altScreenLeave = "\u001B[?1049l";
|
|
34
|
+
export declare const bracketedPasteOn = "\u001B[?2004h";
|
|
35
|
+
export declare const bracketedPasteOff = "\u001B[?2004l";
|
|
36
|
+
export declare const focusEventsOn = "\u001B[?1004h";
|
|
37
|
+
export declare const focusEventsOff = "\u001B[?1004l";
|
|
38
|
+
/** SGR mouse reporting: any-event tracking plus extended coordinates. */
|
|
39
|
+
export declare const mouseOn = "\u001B[?1000h\u001B[?1002h\u001B[?1003h\u001B[?1006h";
|
|
40
|
+
export declare const mouseOff = "\u001B[?1006l\u001B[?1003l\u001B[?1002l\u001B[?1000l";
|
|
41
|
+
/** Click and drag only - no motion events, which are noisy over ssh. */
|
|
42
|
+
export declare const mouseButtonsOn = "\u001B[?1000h\u001B[?1002h\u001B[?1006h";
|
|
43
|
+
export declare const mouseButtonsOff = "\u001B[?1006l\u001B[?1002l\u001B[?1000l";
|
|
44
|
+
/** DEC 2026: draw the whole frame before showing any of it. */
|
|
45
|
+
export declare const syncStart = "\u001B[?2026h";
|
|
46
|
+
export declare const syncEnd = "\u001B[?2026l";
|
|
47
|
+
/** Kitty keyboard protocol - disambiguates ctrl+i from tab, and so on. */
|
|
48
|
+
export declare const kittyKeyboardPush = "\u001B[>1u";
|
|
49
|
+
export declare const kittyKeyboardPop = "\u001B[<u";
|
|
50
|
+
export declare const wrapOff = "\u001B[?7l";
|
|
51
|
+
export declare const wrapOn = "\u001B[?7h";
|
|
52
|
+
export declare const queryDeviceAttributes = "\u001B[c";
|
|
53
|
+
export declare const queryCursorPosition = "\u001B[6n";
|
|
54
|
+
/** XTGETTCAP for truecolor support. */
|
|
55
|
+
export declare const queryTruecolor = "\u001BP+q524742\u001B\\";
|
|
56
|
+
export declare const querySync = "\u001B[?2026$p";
|
|
57
|
+
export declare const setTitle: (title: string) => string;
|
|
58
|
+
export declare const link: (url: string, text: string) => string;
|
|
59
|
+
export declare const linkOpen: (url: string) => string;
|
|
60
|
+
export declare const linkClose = "\u001B]8;;\u001B\\";
|
|
61
|
+
/** OSC 52: put text on the system clipboard, base64-encoded. */
|
|
62
|
+
export declare const clipboardWrite: (text: string) => string;
|
|
63
|
+
export declare const reset = "\u001B[0m";
|
|
64
|
+
export declare const SGR: {
|
|
65
|
+
readonly reset: 0;
|
|
66
|
+
readonly bold: 1;
|
|
67
|
+
readonly dim: 2;
|
|
68
|
+
readonly italic: 3;
|
|
69
|
+
readonly underline: 4;
|
|
70
|
+
readonly blink: 5;
|
|
71
|
+
readonly inverse: 7;
|
|
72
|
+
readonly hidden: 8;
|
|
73
|
+
readonly strike: 9;
|
|
74
|
+
readonly noBold: 22;
|
|
75
|
+
readonly noItalic: 23;
|
|
76
|
+
readonly noUnderline: 24;
|
|
77
|
+
readonly noBlink: 25;
|
|
78
|
+
readonly noInverse: 27;
|
|
79
|
+
readonly noHidden: 28;
|
|
80
|
+
readonly noStrike: 29;
|
|
81
|
+
readonly fgDefault: 39;
|
|
82
|
+
readonly bgDefault: 49;
|
|
83
|
+
};
|
|
84
|
+
//# sourceMappingURL=ansi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ansi.d.ts","sourceRoot":"","sources":["../src/ansi.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,GAAG,WAAS,CAAC;AAC1B,eAAO,MAAM,GAAG,YAAU,CAAC;AAC3B,eAAO,MAAM,GAAG,YAAU,CAAC;AAC3B,eAAO,MAAM,EAAE,aAAW,CAAC;AAC3B,eAAO,MAAM,GAAG,WAAS,CAAC;AAG1B,eAAO,MAAM,QAAQ,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MAAoC,CAAC;AACrF,eAAO,MAAM,UAAU,aAAY,CAAC;AACpC,eAAO,MAAM,UAAU,gBAAe,CAAC;AACvC,eAAO,MAAM,UAAU,gBAAe,CAAC;AACvC,eAAO,MAAM,UAAU,YAAY,CAAC;AACpC,eAAO,MAAM,aAAa,YAAY,CAAC;AACvC,eAAO,MAAM,QAAQ,GAAI,UAAK,KAAG,MAAuB,CAAC;AACzD,eAAO,MAAM,UAAU,GAAI,UAAK,KAAG,MAAuB,CAAC;AAC3D,eAAO,MAAM,aAAa,GAAI,UAAK,KAAG,MAAuB,CAAC;AAC9D,eAAO,MAAM,UAAU,GAAI,UAAK,KAAG,MAAuB,CAAC;AAC3D,eAAO,MAAM,YAAY,GAAI,GAAG,MAAM,KAAG,MAA2B,CAAC;AAErE,4EAA4E;AAC5E,eAAO,MAAM,WAAW,GACtB,OAAO,OAAO,GAAG,WAAW,GAAG,KAAK,EACpC,kBAAe,KACd,MAGF,CAAC;AAGF,eAAO,MAAM,SAAS,cAAa,CAAC;AACpC,eAAO,MAAM,cAAc,cAAa,CAAC;AACzC,eAAO,MAAM,WAAW,cAAa,CAAC;AACtC,eAAO,MAAM,SAAS,cAAa,CAAC;AACpC,eAAO,MAAM,QAAQ,GAAI,UAAK,KAAG,MAAuB,CAAC;AAGzD,eAAO,MAAM,cAAc,kBAAiB,CAAC;AAC7C,eAAO,MAAM,cAAc,kBAAiB,CAAC;AAC7C,eAAO,MAAM,gBAAgB,kBAAiB,CAAC;AAC/C,eAAO,MAAM,iBAAiB,kBAAiB,CAAC;AAChD,eAAO,MAAM,aAAa,kBAAiB,CAAC;AAC5C,eAAO,MAAM,cAAc,kBAAiB,CAAC;AAE7C,yEAAyE;AACzE,eAAO,MAAM,OAAO,yDAAqD,CAAC;AAC1E,eAAO,MAAM,QAAQ,yDAAqD,CAAC;AAC3E,wEAAwE;AACxE,eAAO,MAAM,cAAc,4CAAyC,CAAC;AACrE,eAAO,MAAM,eAAe,4CAAyC,CAAC;AAEtE,+DAA+D;AAC/D,eAAO,MAAM,SAAS,kBAAiB,CAAC;AACxC,eAAO,MAAM,OAAO,kBAAiB,CAAC;AAEtC,0EAA0E;AAC1E,eAAO,MAAM,iBAAiB,eAAc,CAAC;AAC7C,eAAO,MAAM,gBAAgB,cAAa,CAAC;AAE3C,eAAO,MAAM,OAAO,eAAc,CAAC;AACnC,eAAO,MAAM,MAAM,eAAc,CAAC;AAGlC,eAAO,MAAM,qBAAqB,aAAY,CAAC;AAC/C,eAAO,MAAM,mBAAmB,cAAa,CAAC;AAC9C,uCAAuC;AACvC,eAAO,MAAM,cAAc,4BAA4B,CAAC;AACxD,eAAO,MAAM,SAAS,mBAAkB,CAAC;AAGzC,eAAO,MAAM,QAAQ,GAAI,OAAO,MAAM,KAAG,MAA+C,CAAC;AACzF,eAAO,MAAM,IAAI,GAAI,KAAK,MAAM,EAAE,MAAM,MAAM,KAAG,MACS,CAAC;AAC3D,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM,KAAG,MAA6C,CAAC;AACrF,eAAO,MAAM,SAAS,uBAAmB,CAAC;AAE1C,gEAAgE;AAChE,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,KAAG,MAK7C,CAAC;AASF,eAAO,MAAM,KAAK,cAAa,CAAC;AAEhC,eAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;;CAmBN,CAAC"}
|
package/dist/ansi.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ANSI escape sequences.
|
|
3
|
+
*
|
|
4
|
+
* Everything the writer can emit is named here, so a capability check happens
|
|
5
|
+
* once - at the adapter - rather than scattered through the render path.
|
|
6
|
+
* Sequences are written with `\x1b` escapes rather than literal bytes so this
|
|
7
|
+
* file stays readable in a diff.
|
|
8
|
+
*/
|
|
9
|
+
export const ESC = '\x1b';
|
|
10
|
+
export const CSI = '\x1b[';
|
|
11
|
+
export const OSC = '\x1b]';
|
|
12
|
+
export const ST = '\x1b\\';
|
|
13
|
+
export const BEL = '\x07';
|
|
14
|
+
// --- cursor ---
|
|
15
|
+
export const cursorTo = (x, y) => `${CSI}${y + 1};${x + 1}H`;
|
|
16
|
+
export const cursorHome = `${CSI}H`;
|
|
17
|
+
export const cursorHide = `${CSI}?25l`;
|
|
18
|
+
export const cursorShow = `${CSI}?25h`;
|
|
19
|
+
export const cursorSave = `${ESC}7`;
|
|
20
|
+
export const cursorRestore = `${ESC}8`;
|
|
21
|
+
export const cursorUp = (n = 1) => `${CSI}${n}A`;
|
|
22
|
+
export const cursorDown = (n = 1) => `${CSI}${n}B`;
|
|
23
|
+
export const cursorForward = (n = 1) => `${CSI}${n}C`;
|
|
24
|
+
export const cursorBack = (n = 1) => `${CSI}${n}D`;
|
|
25
|
+
export const cursorColumn = (x) => `${CSI}${x + 1}G`;
|
|
26
|
+
/** Cursor shapes, for a text field that wants a bar rather than a block. */
|
|
27
|
+
export const cursorShape = (shape, blinking = true) => {
|
|
28
|
+
const base = shape === 'block' ? 1 : shape === 'underline' ? 3 : 5;
|
|
29
|
+
return `${CSI}${blinking ? base : base + 1} q`;
|
|
30
|
+
};
|
|
31
|
+
// --- erasing ---
|
|
32
|
+
export const eraseLine = `${CSI}2K`;
|
|
33
|
+
export const eraseLineRight = `${CSI}0K`;
|
|
34
|
+
export const eraseScreen = `${CSI}2J`;
|
|
35
|
+
export const eraseDown = `${CSI}0J`;
|
|
36
|
+
export const scrollUp = (n = 1) => `${CSI}${n}S`;
|
|
37
|
+
// --- modes ---
|
|
38
|
+
export const altScreenEnter = `${CSI}?1049h`;
|
|
39
|
+
export const altScreenLeave = `${CSI}?1049l`;
|
|
40
|
+
export const bracketedPasteOn = `${CSI}?2004h`;
|
|
41
|
+
export const bracketedPasteOff = `${CSI}?2004l`;
|
|
42
|
+
export const focusEventsOn = `${CSI}?1004h`;
|
|
43
|
+
export const focusEventsOff = `${CSI}?1004l`;
|
|
44
|
+
/** SGR mouse reporting: any-event tracking plus extended coordinates. */
|
|
45
|
+
export const mouseOn = `${CSI}?1000h${CSI}?1002h${CSI}?1003h${CSI}?1006h`;
|
|
46
|
+
export const mouseOff = `${CSI}?1006l${CSI}?1003l${CSI}?1002l${CSI}?1000l`;
|
|
47
|
+
/** Click and drag only - no motion events, which are noisy over ssh. */
|
|
48
|
+
export const mouseButtonsOn = `${CSI}?1000h${CSI}?1002h${CSI}?1006h`;
|
|
49
|
+
export const mouseButtonsOff = `${CSI}?1006l${CSI}?1002l${CSI}?1000l`;
|
|
50
|
+
/** DEC 2026: draw the whole frame before showing any of it. */
|
|
51
|
+
export const syncStart = `${CSI}?2026h`;
|
|
52
|
+
export const syncEnd = `${CSI}?2026l`;
|
|
53
|
+
/** Kitty keyboard protocol - disambiguates ctrl+i from tab, and so on. */
|
|
54
|
+
export const kittyKeyboardPush = `${CSI}>1u`;
|
|
55
|
+
export const kittyKeyboardPop = `${CSI}<u`;
|
|
56
|
+
export const wrapOff = `${CSI}?7l`;
|
|
57
|
+
export const wrapOn = `${CSI}?7h`;
|
|
58
|
+
// --- queries ---
|
|
59
|
+
export const queryDeviceAttributes = `${CSI}c`;
|
|
60
|
+
export const queryCursorPosition = `${CSI}6n`;
|
|
61
|
+
/** XTGETTCAP for truecolor support. */
|
|
62
|
+
export const queryTruecolor = `${ESC}P+q524742${ESC}\\`;
|
|
63
|
+
export const querySync = `${CSI}?2026$p`;
|
|
64
|
+
// --- osc ---
|
|
65
|
+
export const setTitle = (title) => `${OSC}0;${sanitizeOsc(title)}${BEL}`;
|
|
66
|
+
export const link = (url, text) => `${OSC}8;;${sanitizeOsc(url)}${ST}${text}${OSC}8;;${ST}`;
|
|
67
|
+
export const linkOpen = (url) => `${OSC}8;;${sanitizeOsc(url)}${ST}`;
|
|
68
|
+
export const linkClose = `${OSC}8;;${ST}`;
|
|
69
|
+
/** OSC 52: put text on the system clipboard, base64-encoded. */
|
|
70
|
+
export const clipboardWrite = (text) => {
|
|
71
|
+
const b64 = typeof globalThis.btoa === 'function'
|
|
72
|
+
? globalThis.btoa(unescape(encodeURIComponent(text)))
|
|
73
|
+
: Buffer.from(text, 'utf8').toString('base64');
|
|
74
|
+
return `${OSC}52;c;${b64}${BEL}`;
|
|
75
|
+
};
|
|
76
|
+
/** A string inside an OSC must not contain a terminator of its own. */
|
|
77
|
+
function sanitizeOsc(text) {
|
|
78
|
+
// eslint-disable-next-line no-control-regex
|
|
79
|
+
return text.replace(/[\x00-\x1f\x7f]/g, '');
|
|
80
|
+
}
|
|
81
|
+
// --- SGR ---
|
|
82
|
+
export const reset = `${CSI}0m`;
|
|
83
|
+
export const SGR = {
|
|
84
|
+
reset: 0,
|
|
85
|
+
bold: 1,
|
|
86
|
+
dim: 2,
|
|
87
|
+
italic: 3,
|
|
88
|
+
underline: 4,
|
|
89
|
+
blink: 5,
|
|
90
|
+
inverse: 7,
|
|
91
|
+
hidden: 8,
|
|
92
|
+
strike: 9,
|
|
93
|
+
noBold: 22,
|
|
94
|
+
noItalic: 23,
|
|
95
|
+
noUnderline: 24,
|
|
96
|
+
noBlink: 25,
|
|
97
|
+
noInverse: 27,
|
|
98
|
+
noHidden: 28,
|
|
99
|
+
noStrike: 29,
|
|
100
|
+
fgDefault: 39,
|
|
101
|
+
bgDefault: 49,
|
|
102
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CapabilityOverrides, TerminalCapabilities, ColorDepth, UnicodeLevel } from '@textui/core';
|
|
2
|
+
export interface DetectionInput {
|
|
3
|
+
env: Record<string, string | undefined>;
|
|
4
|
+
isTTY: boolean;
|
|
5
|
+
columns?: number;
|
|
6
|
+
rows?: number;
|
|
7
|
+
platform?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Capability detection.
|
|
11
|
+
*
|
|
12
|
+
* Detection is best-effort and deliberately conservative: claiming a
|
|
13
|
+
* capability the terminal lacks corrupts the frame, while missing one only
|
|
14
|
+
* costs polish. Anything detection cannot settle, an adapter override can.
|
|
15
|
+
*/
|
|
16
|
+
export declare function detectColorDepth(env: Record<string, string | undefined>, isTTY: boolean): ColorDepth;
|
|
17
|
+
export declare function detectUnicode(env: Record<string, string | undefined>): UnicodeLevel;
|
|
18
|
+
export declare function detectCapabilities(input: DetectionInput): TerminalCapabilities;
|
|
19
|
+
export declare function applyOverrides(base: TerminalCapabilities, overrides: CapabilityOverrides | undefined): TerminalCapabilities;
|
|
20
|
+
/** Describe the environment, for `textui doctor` and the inspector. */
|
|
21
|
+
export declare function describeEnvironment(input: DetectionInput): Record<string, string>;
|
|
22
|
+
//# sourceMappingURL=capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGxG,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACxC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,GAAG,UAAU,CA4BpG;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,YAAY,CAYnF;AAWD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,oBAAoB,CA8C9E;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,oBAAoB,EAC1B,SAAS,EAAE,mBAAmB,GAAG,SAAS,GACzC,oBAAoB,CAEtB;AAED,uEAAuE;AACvE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYjF"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { MINIMAL_CAPABILITIES } from '@textui/core';
|
|
2
|
+
/**
|
|
3
|
+
* Capability detection.
|
|
4
|
+
*
|
|
5
|
+
* Detection is best-effort and deliberately conservative: claiming a
|
|
6
|
+
* capability the terminal lacks corrupts the frame, while missing one only
|
|
7
|
+
* costs polish. Anything detection cannot settle, an adapter override can.
|
|
8
|
+
*/
|
|
9
|
+
export function detectColorDepth(env, isTTY) {
|
|
10
|
+
if (env.NO_COLOR !== undefined && env.NO_COLOR !== '')
|
|
11
|
+
return 0;
|
|
12
|
+
if (env.FORCE_COLOR !== undefined) {
|
|
13
|
+
const level = Number.parseInt(env.FORCE_COLOR, 10);
|
|
14
|
+
if (env.FORCE_COLOR === 'true')
|
|
15
|
+
return 24;
|
|
16
|
+
if (level === 0)
|
|
17
|
+
return 0;
|
|
18
|
+
if (level === 1)
|
|
19
|
+
return 4;
|
|
20
|
+
if (level === 2)
|
|
21
|
+
return 8;
|
|
22
|
+
if (level >= 3)
|
|
23
|
+
return 24;
|
|
24
|
+
}
|
|
25
|
+
if (!isTTY)
|
|
26
|
+
return 0;
|
|
27
|
+
const term = env.TERM ?? '';
|
|
28
|
+
if (term === 'dumb')
|
|
29
|
+
return 0;
|
|
30
|
+
const colorterm = (env.COLORTERM ?? '').toLowerCase();
|
|
31
|
+
if (colorterm === 'truecolor' || colorterm === '24bit')
|
|
32
|
+
return 24;
|
|
33
|
+
const program = env.TERM_PROGRAM ?? '';
|
|
34
|
+
if (['iTerm.app', 'WezTerm', 'vscode', 'Hyper', 'ghostty'].includes(program))
|
|
35
|
+
return 24;
|
|
36
|
+
if (env.WT_SESSION)
|
|
37
|
+
return 24;
|
|
38
|
+
if (env.KITTY_WINDOW_ID)
|
|
39
|
+
return 24;
|
|
40
|
+
if (env.ALACRITTY_LOG || term.startsWith('alacritty'))
|
|
41
|
+
return 24;
|
|
42
|
+
if (term.includes('256'))
|
|
43
|
+
return 8;
|
|
44
|
+
if (term.includes('color') || term.startsWith('xterm') || term.startsWith('screen'))
|
|
45
|
+
return 4;
|
|
46
|
+
if (term === '')
|
|
47
|
+
return 0;
|
|
48
|
+
return 4;
|
|
49
|
+
}
|
|
50
|
+
export function detectUnicode(env) {
|
|
51
|
+
const locale = env.LC_ALL ?? env.LC_CTYPE ?? env.LANG ?? '';
|
|
52
|
+
if (!/utf-?8/i.test(locale)) {
|
|
53
|
+
// Windows Terminal and modern macOS terminals are UTF-8 without saying so.
|
|
54
|
+
if (env.WT_SESSION || env.TERM_PROGRAM === 'iTerm.app' || env.TERM_PROGRAM === 'Apple_Terminal') {
|
|
55
|
+
return 'full';
|
|
56
|
+
}
|
|
57
|
+
return 'ascii';
|
|
58
|
+
}
|
|
59
|
+
const term = env.TERM ?? '';
|
|
60
|
+
if (term === 'linux')
|
|
61
|
+
return 'bmp';
|
|
62
|
+
return 'full';
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Some terminals report a TERM their multiplexer chose. tmux and screen pass
|
|
66
|
+
* most sequences through but swallow a few, so they are treated as capable
|
|
67
|
+
* with the known gaps closed.
|
|
68
|
+
*/
|
|
69
|
+
function inMultiplexer(env) {
|
|
70
|
+
return Boolean(env.TMUX) || (env.TERM ?? '').startsWith('screen');
|
|
71
|
+
}
|
|
72
|
+
export function detectCapabilities(input) {
|
|
73
|
+
const { env, isTTY } = input;
|
|
74
|
+
const term = env.TERM ?? '';
|
|
75
|
+
if (!isTTY || term === 'dumb') {
|
|
76
|
+
return { ...MINIMAL_CAPABILITIES, colorDepth: detectColorDepth(env, isTTY) };
|
|
77
|
+
}
|
|
78
|
+
const colorDepth = detectColorDepth(env, isTTY);
|
|
79
|
+
const unicode = detectUnicode(env);
|
|
80
|
+
const mux = inMultiplexer(env);
|
|
81
|
+
const program = env.TERM_PROGRAM ?? '';
|
|
82
|
+
// Terminals that speak the kitty keyboard protocol, which is what makes
|
|
83
|
+
// `ctrl+enter` a different key from `enter` rather than the same byte.
|
|
84
|
+
//
|
|
85
|
+
// VS Code belongs here: its terminal is xterm.js, which has implemented the
|
|
86
|
+
// protocol since 6.1, and `terminal.integrated.enableKittyKeyboardProtocol`
|
|
87
|
+
// defaults to on. Without it in this list nothing ever pushes `CSI > 1 u`,
|
|
88
|
+
// so the terminal keeps sending legacy codes and every modified enter,
|
|
89
|
+
// tab and escape arrives as its unmodified twin.
|
|
90
|
+
const kitty = Boolean(env.KITTY_WINDOW_ID) || program === 'WezTerm'
|
|
91
|
+
|| program === 'ghostty' || program === 'vscode';
|
|
92
|
+
const modern = kitty || program === 'iTerm.app' || Boolean(env.WT_SESSION) ||
|
|
93
|
+
term.startsWith('alacritty') || program === 'vscode';
|
|
94
|
+
return {
|
|
95
|
+
colorDepth,
|
|
96
|
+
unicode,
|
|
97
|
+
wideChars: unicode !== 'ascii',
|
|
98
|
+
mouse: true,
|
|
99
|
+
wheel: true,
|
|
100
|
+
focusEvents: true,
|
|
101
|
+
paste: true,
|
|
102
|
+
// tmux rewrites OSC 8, and Apple Terminal ignores it.
|
|
103
|
+
hyperlinks: modern && !mux && program !== 'Apple_Terminal',
|
|
104
|
+
clipboard: modern || mux,
|
|
105
|
+
altScreen: true,
|
|
106
|
+
cursor: true,
|
|
107
|
+
// Synchronized output is safe when supported and harmless when not, but
|
|
108
|
+
// tmux below 3.4 mangles it, so it is off inside a multiplexer.
|
|
109
|
+
synchronizedOutput: modern && !mux,
|
|
110
|
+
title: true,
|
|
111
|
+
kittyKeyboard: kitty && !mux,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
export function applyOverrides(base, overrides) {
|
|
115
|
+
return overrides ? { ...base, ...overrides } : base;
|
|
116
|
+
}
|
|
117
|
+
/** Describe the environment, for `textui doctor` and the inspector. */
|
|
118
|
+
export function describeEnvironment(input) {
|
|
119
|
+
const { env } = input;
|
|
120
|
+
return {
|
|
121
|
+
TERM: env.TERM ?? '(unset)',
|
|
122
|
+
COLORTERM: env.COLORTERM ?? '(unset)',
|
|
123
|
+
TERM_PROGRAM: env.TERM_PROGRAM ?? '(unset)',
|
|
124
|
+
LANG: env.LC_ALL ?? env.LANG ?? '(unset)',
|
|
125
|
+
multiplexer: env.TMUX ? 'tmux' : (env.TERM ?? '').startsWith('screen') ? 'screen' : 'none',
|
|
126
|
+
ssh: env.SSH_TTY || env.SSH_CONNECTION ? 'yes' : 'no',
|
|
127
|
+
tty: String(input.isTTY),
|
|
128
|
+
size: `${input.columns ?? '?'}x${input.rows ?? '?'}`,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CellBuffer, ColorDepth, TerminalCapabilities } from '@textui/core';
|
|
2
|
+
/**
|
|
3
|
+
* A frame, as a string you can keep.
|
|
4
|
+
*
|
|
5
|
+
* This is not what `Writer` does. The writer's job is to get from the frame on
|
|
6
|
+
* screen to the next one in as few bytes as it can, so what it emits is cursor
|
|
7
|
+
* moves and the differences between them - correct on a live terminal and
|
|
8
|
+
* meaningless in a file. A capture is the opposite: every cell, in order, rows
|
|
9
|
+
* separated by newlines and no cursor control at all, so it can be written to
|
|
10
|
+
* a file, piped, pasted into a bug report, or `cat`ed back with nothing else
|
|
11
|
+
* on screen having to be true.
|
|
12
|
+
*
|
|
13
|
+
* A terminal application cannot show you what it looked like when it went
|
|
14
|
+
* wrong - the screen is the output, and the next redraw destroys the evidence.
|
|
15
|
+
* This is how it hands you the evidence instead.
|
|
16
|
+
*/
|
|
17
|
+
export interface CaptureOptions {
|
|
18
|
+
/** Emit SGR colour. Off gives plain text, which is what a diff can read. */
|
|
19
|
+
colors?: boolean;
|
|
20
|
+
/** Reduce colour to this depth. Defaults to what the terminal reported. */
|
|
21
|
+
colorDepth?: ColorDepth;
|
|
22
|
+
}
|
|
23
|
+
export declare function captureBuffer(buffer: CellBuffer, capabilities: TerminalCapabilities, options?: CaptureOptions): string;
|
|
24
|
+
//# sourceMappingURL=capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../src/capture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAKjF;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,cAAc;IAC7B,4EAA4E;IAC5E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,oBAAoB,EAClC,OAAO,GAAE,cAAmB,GAC3B,MAAM,CAgER"}
|
package/dist/capture.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { COLOR_DEFAULT, packColor } from '@textui/core';
|
|
2
|
+
import { ATTR_ON, bgSequence, fgSequence } from './writer.js';
|
|
3
|
+
import * as ansi from './ansi.js';
|
|
4
|
+
export function captureBuffer(buffer, capabilities, options = {}) {
|
|
5
|
+
const depth = options.colorDepth ?? capabilities.colorDepth;
|
|
6
|
+
const colors = (options.colors ?? true) && depth > 0;
|
|
7
|
+
const rows = [];
|
|
8
|
+
for (let y = 0; y < buffer.height; y++) {
|
|
9
|
+
let row = '';
|
|
10
|
+
let fg = COLOR_DEFAULT;
|
|
11
|
+
let bg = COLOR_DEFAULT;
|
|
12
|
+
let attrs = 0;
|
|
13
|
+
// Where the row last stopped being blank. A run of default-styled spaces
|
|
14
|
+
// at the end is trailing whitespace; the same run with a background is a
|
|
15
|
+
// part of the picture, so only the first kind is trimmed.
|
|
16
|
+
let end = 0;
|
|
17
|
+
let plain = '';
|
|
18
|
+
for (let x = 0; x < buffer.width; x++) {
|
|
19
|
+
const cell = buffer.get(x, y);
|
|
20
|
+
if (!cell || cell.continuation === true)
|
|
21
|
+
continue;
|
|
22
|
+
const cellFg = packColor(cell.fg);
|
|
23
|
+
const cellBg = packColor(cell.bg);
|
|
24
|
+
const cellAttrs = cell.attrs;
|
|
25
|
+
if (colors && (cellFg !== fg || cellBg !== bg || cellAttrs !== attrs)) {
|
|
26
|
+
const codes = [];
|
|
27
|
+
// One reset and a restatement, rather than eight ways to turn things
|
|
28
|
+
// off - the same trade the writer makes, for the same reason.
|
|
29
|
+
if ((attrs & ~cellAttrs) !== 0) {
|
|
30
|
+
codes.push(ansi.SGR.reset);
|
|
31
|
+
fg = COLOR_DEFAULT;
|
|
32
|
+
bg = COLOR_DEFAULT;
|
|
33
|
+
attrs = 0;
|
|
34
|
+
}
|
|
35
|
+
for (const [bit, code] of ATTR_ON) {
|
|
36
|
+
if (cellAttrs & bit & ~attrs)
|
|
37
|
+
codes.push(code);
|
|
38
|
+
}
|
|
39
|
+
if (cellFg !== fg)
|
|
40
|
+
codes.push(fgSequence(cellFg, depth));
|
|
41
|
+
if (cellBg !== bg)
|
|
42
|
+
codes.push(bgSequence(cellBg, depth));
|
|
43
|
+
if (codes.length > 0)
|
|
44
|
+
row += `${ansi.CSI}${codes.join(';')}m`;
|
|
45
|
+
fg = cellFg;
|
|
46
|
+
bg = cellBg;
|
|
47
|
+
attrs = cellAttrs;
|
|
48
|
+
}
|
|
49
|
+
row += cell.char;
|
|
50
|
+
plain += cell.char;
|
|
51
|
+
if (cell.char !== ' ' || cellBg !== COLOR_DEFAULT || cellAttrs !== 0)
|
|
52
|
+
end = plain.length;
|
|
53
|
+
}
|
|
54
|
+
const styled = colors && (fg !== COLOR_DEFAULT || bg !== COLOR_DEFAULT || attrs !== 0);
|
|
55
|
+
if (end < plain.length) {
|
|
56
|
+
// Nothing after the last real cell, so drop it - and reset first, or the
|
|
57
|
+
// last colour bleeds to the edge of whatever terminal shows this.
|
|
58
|
+
row = trimTail(row, plain.length - end);
|
|
59
|
+
if (styled)
|
|
60
|
+
row += `${ansi.CSI}${ansi.SGR.reset}m`;
|
|
61
|
+
}
|
|
62
|
+
else if (styled) {
|
|
63
|
+
row += `${ansi.CSI}${ansi.SGR.reset}m`;
|
|
64
|
+
}
|
|
65
|
+
rows.push(row);
|
|
66
|
+
}
|
|
67
|
+
return rows.join('\n');
|
|
68
|
+
}
|
|
69
|
+
/** Drop `count` characters from the end, which are known to be plain spaces. */
|
|
70
|
+
function trimTail(row, count) {
|
|
71
|
+
return count <= 0 ? row : row.slice(0, row.length - count);
|
|
72
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * as ansi from './ansi.js';
|
|
2
|
+
export { Writer, createWriter } from './writer.js';
|
|
3
|
+
export { captureBuffer } from './capture.js';
|
|
4
|
+
export type { CaptureOptions } from './capture.js';
|
|
5
|
+
export { bufferToSvg } from './svg.js';
|
|
6
|
+
export type { SvgOptions } from './svg.js';
|
|
7
|
+
export { detectCapabilities, detectColorDepth, detectUnicode, applyOverrides, describeEnvironment, } from './capabilities.js';
|
|
8
|
+
export type { DetectionInput } from './capabilities.js';
|
|
9
|
+
export { InputDecoder, createDecoder } from './input.js';
|
|
10
|
+
export type { DecoderOptions } from './input.js';
|
|
11
|
+
export { NodeTerminalAdapter, createNodeTerminal } from './node.js';
|
|
12
|
+
export type { NodeAdapterOptions, TerminalInput, TerminalOutput, TerminalSignal } from './node.js';
|
|
13
|
+
export { VirtualTerminalAdapter, createVirtualTerminal } from './virtual.js';
|
|
14
|
+
export type { VirtualAdapterOptions } from './virtual.js';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EACL,kBAAkB,EAAE,gBAAgB,EAAE,aAAa,EACnD,cAAc,EAAE,mBAAmB,GACpC,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACzD,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACpE,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACnG,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC7E,YAAY,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * as ansi from './ansi.js';
|
|
2
|
+
export { Writer, createWriter } from './writer.js';
|
|
3
|
+
export { captureBuffer } from './capture.js';
|
|
4
|
+
export { bufferToSvg } from './svg.js';
|
|
5
|
+
export { detectCapabilities, detectColorDepth, detectUnicode, applyOverrides, describeEnvironment, } from './capabilities.js';
|
|
6
|
+
export { InputDecoder, createDecoder } from './input.js';
|
|
7
|
+
export { NodeTerminalAdapter, createNodeTerminal } from './node.js';
|
|
8
|
+
export { VirtualTerminalAdapter, createVirtualTerminal } from './virtual.js';
|
package/dist/input.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { InputEvent } from '@textui/core';
|
|
2
|
+
export interface DecoderOptions {
|
|
3
|
+
/** How long to wait before a lone ESC is reported as the escape key. */
|
|
4
|
+
escapeTimeoutMs?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class InputDecoder {
|
|
7
|
+
private emit;
|
|
8
|
+
private options;
|
|
9
|
+
private carry;
|
|
10
|
+
private pasting;
|
|
11
|
+
private pasteBuffer;
|
|
12
|
+
private escapeTimer;
|
|
13
|
+
constructor(emit: (event: InputEvent) => void, options?: DecoderOptions);
|
|
14
|
+
/** Feed raw input. Emits zero or more events. */
|
|
15
|
+
feed(chunk: string): void;
|
|
16
|
+
private clearEscapeTimer;
|
|
17
|
+
/** Consume one event's worth of bytes. Returns how many were used. */
|
|
18
|
+
private step;
|
|
19
|
+
private stepPlain;
|
|
20
|
+
private stepPaste;
|
|
21
|
+
/** `ESC O P` - the application-cursor form of F1..F4 and the arrows. */
|
|
22
|
+
private stepSs3;
|
|
23
|
+
private stepCsi;
|
|
24
|
+
/** Drop any half-read sequence. After releasing the terminal. */
|
|
25
|
+
reset(): void;
|
|
26
|
+
}
|
|
27
|
+
export declare function createDecoder(emit: (event: InputEvent) => void, options?: DecoderOptions): InputDecoder;
|
|
28
|
+
//# sourceMappingURL=input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAwB,MAAM,cAAc,CAAC;AAiErE,MAAM,WAAW,cAAc;IAC7B,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,qBAAa,YAAY;IAOrB,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,OAAO;IAPjB,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,WAAW,CAA8C;gBAGvD,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,EACjC,OAAO,GAAE,cAAmB;IAGtC,iDAAiD;IACjD,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAqBzB,OAAO,CAAC,gBAAgB;IAOxB,sEAAsE;IACtE,OAAO,CAAC,IAAI;IAyDZ,OAAO,CAAC,SAAS;IA8CjB,OAAO,CAAC,SAAS;IAkBjB,wEAAwE;IACxE,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,OAAO;IA8Ff,iEAAiE;IACjE,KAAK,IAAI,IAAI;CAMd;AA4CD,wBAAgB,aAAa,CAC3B,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,EACjC,OAAO,CAAC,EAAE,cAAc,GACvB,YAAY,CAEd"}
|