@gajae-code/tui 0.1.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/CHANGELOG.md +818 -0
- package/README.md +704 -0
- package/dist/types/autocomplete.d.ts +76 -0
- package/dist/types/bracketed-paste.d.ts +26 -0
- package/dist/types/components/box.d.ts +15 -0
- package/dist/types/components/cancellable-loader.d.ts +21 -0
- package/dist/types/components/editor.d.ts +101 -0
- package/dist/types/components/image.d.ts +16 -0
- package/dist/types/components/input.d.ts +16 -0
- package/dist/types/components/loader.d.ts +13 -0
- package/dist/types/components/markdown.d.ts +61 -0
- package/dist/types/components/select-list.d.ts +46 -0
- package/dist/types/components/settings-list.d.ts +39 -0
- package/dist/types/components/spacer.d.ts +11 -0
- package/dist/types/components/tab-bar.d.ts +56 -0
- package/dist/types/components/text.d.ts +13 -0
- package/dist/types/components/truncated-text.d.ts +10 -0
- package/dist/types/editor-component.d.ts +36 -0
- package/dist/types/fuzzy.d.ts +15 -0
- package/dist/types/index.d.ts +25 -0
- package/dist/types/keybindings.d.ts +189 -0
- package/dist/types/keys.d.ts +208 -0
- package/dist/types/kill-ring.d.ts +27 -0
- package/dist/types/stdin-buffer.d.ts +43 -0
- package/dist/types/symbols.d.ts +23 -0
- package/dist/types/terminal-capabilities.d.ts +75 -0
- package/dist/types/terminal.d.ts +61 -0
- package/dist/types/ttyid.d.ts +9 -0
- package/dist/types/tui.d.ts +161 -0
- package/dist/types/utils.d.ts +74 -0
- package/package.json +73 -0
- package/src/autocomplete.ts +836 -0
- package/src/bracketed-paste.ts +47 -0
- package/src/components/box.ts +144 -0
- package/src/components/cancellable-loader.ts +40 -0
- package/src/components/editor.ts +2664 -0
- package/src/components/image.ts +90 -0
- package/src/components/input.ts +465 -0
- package/src/components/loader.ts +86 -0
- package/src/components/markdown.ts +1009 -0
- package/src/components/select-list.ts +249 -0
- package/src/components/settings-list.ts +211 -0
- package/src/components/spacer.ts +28 -0
- package/src/components/tab-bar.ts +175 -0
- package/src/components/text.ts +110 -0
- package/src/components/truncated-text.ts +61 -0
- package/src/editor-component.ts +71 -0
- package/src/fuzzy.ts +143 -0
- package/src/index.ts +39 -0
- package/src/keybindings.ts +279 -0
- package/src/keys.ts +537 -0
- package/src/kill-ring.ts +46 -0
- package/src/stdin-buffer.ts +410 -0
- package/src/symbols.ts +24 -0
- package/src/terminal-capabilities.ts +537 -0
- package/src/terminal.ts +716 -0
- package/src/ttyid.ts +66 -0
- package/src/tui.ts +1481 -0
- package/src/utils.ts +359 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { type KeyId } from "./keys";
|
|
2
|
+
/**
|
|
3
|
+
* Global keybinding registry.
|
|
4
|
+
* Downstream packages can add keybindings via declaration merging.
|
|
5
|
+
*/
|
|
6
|
+
export interface Keybindings {
|
|
7
|
+
"tui.editor.cursorUp": true;
|
|
8
|
+
"tui.editor.cursorDown": true;
|
|
9
|
+
"tui.editor.cursorLeft": true;
|
|
10
|
+
"tui.editor.cursorRight": true;
|
|
11
|
+
"tui.editor.cursorWordLeft": true;
|
|
12
|
+
"tui.editor.cursorWordRight": true;
|
|
13
|
+
"tui.editor.cursorLineStart": true;
|
|
14
|
+
"tui.editor.cursorLineEnd": true;
|
|
15
|
+
"tui.editor.jumpForward": true;
|
|
16
|
+
"tui.editor.jumpBackward": true;
|
|
17
|
+
"tui.editor.pageUp": true;
|
|
18
|
+
"tui.editor.pageDown": true;
|
|
19
|
+
"tui.editor.deleteCharBackward": true;
|
|
20
|
+
"tui.editor.deleteCharForward": true;
|
|
21
|
+
"tui.editor.deleteWordBackward": true;
|
|
22
|
+
"tui.editor.deleteWordForward": true;
|
|
23
|
+
"tui.editor.deleteToLineStart": true;
|
|
24
|
+
"tui.editor.deleteToLineEnd": true;
|
|
25
|
+
"tui.editor.yank": true;
|
|
26
|
+
"tui.editor.yankPop": true;
|
|
27
|
+
"tui.editor.undo": true;
|
|
28
|
+
"tui.input.newLine": true;
|
|
29
|
+
"tui.input.submit": true;
|
|
30
|
+
"tui.input.tab": true;
|
|
31
|
+
"tui.input.copy": true;
|
|
32
|
+
"tui.select.up": true;
|
|
33
|
+
"tui.select.down": true;
|
|
34
|
+
"tui.select.pageUp": true;
|
|
35
|
+
"tui.select.pageDown": true;
|
|
36
|
+
"tui.select.confirm": true;
|
|
37
|
+
"tui.select.cancel": true;
|
|
38
|
+
}
|
|
39
|
+
export type Keybinding = keyof Keybindings;
|
|
40
|
+
export type { KeyId };
|
|
41
|
+
export interface KeybindingDefinition {
|
|
42
|
+
defaultKeys: KeyId | KeyId[];
|
|
43
|
+
description?: string;
|
|
44
|
+
}
|
|
45
|
+
export type KeybindingDefinitions = Record<string, KeybindingDefinition>;
|
|
46
|
+
export type KeybindingsConfig = Record<string, KeyId | KeyId[] | undefined>;
|
|
47
|
+
export declare const TUI_KEYBINDINGS: {
|
|
48
|
+
readonly "tui.editor.cursorUp": {
|
|
49
|
+
readonly defaultKeys: "up";
|
|
50
|
+
readonly description: "Move cursor up";
|
|
51
|
+
};
|
|
52
|
+
readonly "tui.editor.cursorDown": {
|
|
53
|
+
readonly defaultKeys: "down";
|
|
54
|
+
readonly description: "Move cursor down";
|
|
55
|
+
};
|
|
56
|
+
readonly "tui.editor.cursorLeft": {
|
|
57
|
+
readonly defaultKeys: ["left", "ctrl+b"];
|
|
58
|
+
readonly description: "Move cursor left";
|
|
59
|
+
};
|
|
60
|
+
readonly "tui.editor.cursorRight": {
|
|
61
|
+
readonly defaultKeys: ["right", "ctrl+f"];
|
|
62
|
+
readonly description: "Move cursor right";
|
|
63
|
+
};
|
|
64
|
+
readonly "tui.editor.cursorWordLeft": {
|
|
65
|
+
readonly defaultKeys: ["alt+left", "ctrl+left", "alt+b"];
|
|
66
|
+
readonly description: "Move cursor word left";
|
|
67
|
+
};
|
|
68
|
+
readonly "tui.editor.cursorWordRight": {
|
|
69
|
+
readonly defaultKeys: ["alt+right", "ctrl+right", "alt+f"];
|
|
70
|
+
readonly description: "Move cursor word right";
|
|
71
|
+
};
|
|
72
|
+
readonly "tui.editor.cursorLineStart": {
|
|
73
|
+
readonly defaultKeys: ["home", "ctrl+a"];
|
|
74
|
+
readonly description: "Move to line start";
|
|
75
|
+
};
|
|
76
|
+
readonly "tui.editor.cursorLineEnd": {
|
|
77
|
+
readonly defaultKeys: ["end", "ctrl+e"];
|
|
78
|
+
readonly description: "Move to line end";
|
|
79
|
+
};
|
|
80
|
+
readonly "tui.editor.jumpForward": {
|
|
81
|
+
readonly defaultKeys: "ctrl+]";
|
|
82
|
+
readonly description: "Jump forward to character";
|
|
83
|
+
};
|
|
84
|
+
readonly "tui.editor.jumpBackward": {
|
|
85
|
+
readonly defaultKeys: "ctrl+alt+]";
|
|
86
|
+
readonly description: "Jump backward to character";
|
|
87
|
+
};
|
|
88
|
+
readonly "tui.editor.pageUp": {
|
|
89
|
+
readonly defaultKeys: "pageUp";
|
|
90
|
+
readonly description: "Page up";
|
|
91
|
+
};
|
|
92
|
+
readonly "tui.editor.pageDown": {
|
|
93
|
+
readonly defaultKeys: "pageDown";
|
|
94
|
+
readonly description: "Page down";
|
|
95
|
+
};
|
|
96
|
+
readonly "tui.editor.deleteCharBackward": {
|
|
97
|
+
readonly defaultKeys: "backspace";
|
|
98
|
+
readonly description: "Delete character backward";
|
|
99
|
+
};
|
|
100
|
+
readonly "tui.editor.deleteCharForward": {
|
|
101
|
+
readonly defaultKeys: ["delete", "ctrl+d"];
|
|
102
|
+
readonly description: "Delete character forward";
|
|
103
|
+
};
|
|
104
|
+
readonly "tui.editor.deleteWordBackward": {
|
|
105
|
+
readonly defaultKeys: ["ctrl+w", "alt+backspace", "ctrl+backspace"];
|
|
106
|
+
readonly description: "Delete word backward";
|
|
107
|
+
};
|
|
108
|
+
readonly "tui.editor.deleteWordForward": {
|
|
109
|
+
readonly defaultKeys: ["alt+delete", "alt+d"];
|
|
110
|
+
readonly description: "Delete word forward";
|
|
111
|
+
};
|
|
112
|
+
readonly "tui.editor.deleteToLineStart": {
|
|
113
|
+
readonly defaultKeys: "ctrl+u";
|
|
114
|
+
readonly description: "Delete to line start";
|
|
115
|
+
};
|
|
116
|
+
readonly "tui.editor.deleteToLineEnd": {
|
|
117
|
+
readonly defaultKeys: "ctrl+k";
|
|
118
|
+
readonly description: "Delete to line end";
|
|
119
|
+
};
|
|
120
|
+
readonly "tui.editor.yank": {
|
|
121
|
+
readonly defaultKeys: "ctrl+y";
|
|
122
|
+
readonly description: "Yank";
|
|
123
|
+
};
|
|
124
|
+
readonly "tui.editor.yankPop": {
|
|
125
|
+
readonly defaultKeys: "alt+y";
|
|
126
|
+
readonly description: "Yank pop";
|
|
127
|
+
};
|
|
128
|
+
readonly "tui.editor.undo": {
|
|
129
|
+
readonly defaultKeys: ["ctrl+-", "ctrl+_"];
|
|
130
|
+
readonly description: "Undo";
|
|
131
|
+
};
|
|
132
|
+
readonly "tui.input.newLine": {
|
|
133
|
+
readonly defaultKeys: "shift+enter";
|
|
134
|
+
readonly description: "Insert newline";
|
|
135
|
+
};
|
|
136
|
+
readonly "tui.input.submit": {
|
|
137
|
+
readonly defaultKeys: "enter";
|
|
138
|
+
readonly description: "Submit input";
|
|
139
|
+
};
|
|
140
|
+
readonly "tui.input.tab": {
|
|
141
|
+
readonly defaultKeys: "tab";
|
|
142
|
+
readonly description: "Tab / autocomplete";
|
|
143
|
+
};
|
|
144
|
+
readonly "tui.input.copy": {
|
|
145
|
+
readonly defaultKeys: "ctrl+c";
|
|
146
|
+
readonly description: "Copy selection";
|
|
147
|
+
};
|
|
148
|
+
readonly "tui.select.up": {
|
|
149
|
+
readonly defaultKeys: "up";
|
|
150
|
+
readonly description: "Move selection up";
|
|
151
|
+
};
|
|
152
|
+
readonly "tui.select.down": {
|
|
153
|
+
readonly defaultKeys: "down";
|
|
154
|
+
readonly description: "Move selection down";
|
|
155
|
+
};
|
|
156
|
+
readonly "tui.select.pageUp": {
|
|
157
|
+
readonly defaultKeys: "pageUp";
|
|
158
|
+
readonly description: "Selection page up";
|
|
159
|
+
};
|
|
160
|
+
readonly "tui.select.pageDown": {
|
|
161
|
+
readonly defaultKeys: "pageDown";
|
|
162
|
+
readonly description: "Selection page down";
|
|
163
|
+
};
|
|
164
|
+
readonly "tui.select.confirm": {
|
|
165
|
+
readonly defaultKeys: "enter";
|
|
166
|
+
readonly description: "Confirm selection";
|
|
167
|
+
};
|
|
168
|
+
readonly "tui.select.cancel": {
|
|
169
|
+
readonly defaultKeys: ["escape", "ctrl+c"];
|
|
170
|
+
readonly description: "Cancel selection";
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
export interface KeybindingConflict {
|
|
174
|
+
key: KeyId;
|
|
175
|
+
keybindings: string[];
|
|
176
|
+
}
|
|
177
|
+
export declare class KeybindingsManager {
|
|
178
|
+
#private;
|
|
179
|
+
constructor(definitions: KeybindingDefinitions, userBindings?: KeybindingsConfig);
|
|
180
|
+
matches(data: string, keybinding: Keybinding): boolean;
|
|
181
|
+
getKeys(keybinding: Keybinding): KeyId[];
|
|
182
|
+
getDefinition(keybinding: Keybinding): KeybindingDefinition;
|
|
183
|
+
getConflicts(): KeybindingConflict[];
|
|
184
|
+
setUserBindings(userBindings: KeybindingsConfig): void;
|
|
185
|
+
getUserBindings(): KeybindingsConfig;
|
|
186
|
+
getResolvedBindings(): KeybindingsConfig;
|
|
187
|
+
}
|
|
188
|
+
export declare function setKeybindings(keybindings: KeybindingsManager): void;
|
|
189
|
+
export declare function getKeybindings(): KeybindingsManager;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyboard input handling for terminal applications.
|
|
3
|
+
*
|
|
4
|
+
* Supports both legacy terminal sequences and Kitty keyboard protocol.
|
|
5
|
+
* See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/
|
|
6
|
+
* Reference: https://github.com/sst/opentui/blob/7da92b4088aebfe27b9f691c04163a48821e49fd/packages/core/src/lib/parse.keypress.ts
|
|
7
|
+
*
|
|
8
|
+
* Symbol keys are also supported, however some ctrl+symbol combos
|
|
9
|
+
* overlap with ASCII codes, e.g. ctrl+[ = ESC.
|
|
10
|
+
* See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/#legacy-ctrl-mapping-of-ascii-keys
|
|
11
|
+
* Those can still be * used for ctrl+shift combos
|
|
12
|
+
*
|
|
13
|
+
* API:
|
|
14
|
+
* - matchesKey(data, keyId) - Check if input matches a key identifier
|
|
15
|
+
* - parseKey(data) - Parse input and return the key identifier
|
|
16
|
+
* - Key - Helper object for creating typed key identifiers
|
|
17
|
+
* - setKittyProtocolActive(active) - Set global Kitty protocol state
|
|
18
|
+
* - isKittyProtocolActive() - Query global Kitty protocol state
|
|
19
|
+
*/
|
|
20
|
+
import type { KeyEventType } from "@gajae-code/natives";
|
|
21
|
+
declare function isWindowsTerminalSession(): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Raw 0x08 (BS) is ambiguous in legacy terminals.
|
|
24
|
+
*
|
|
25
|
+
* - Windows Terminal uses it for Ctrl+Backspace.
|
|
26
|
+
* - Some legacy terminals and tmux setups send it for plain Backspace.
|
|
27
|
+
*
|
|
28
|
+
* Prefer explicit Kitty / CSI-u / modifyOtherKeys sequences whenever they are
|
|
29
|
+
* available. Fall back to a Windows Terminal heuristic only for raw BS bytes.
|
|
30
|
+
*/
|
|
31
|
+
declare function matchesRawBackspace(data: string, expectedModifier: number): boolean;
|
|
32
|
+
export { isWindowsTerminalSession, matchesRawBackspace };
|
|
33
|
+
/**
|
|
34
|
+
* Set the global Kitty keyboard protocol state.
|
|
35
|
+
* Called by ProcessTerminal after detecting protocol support.
|
|
36
|
+
*/
|
|
37
|
+
export declare function setKittyProtocolActive(active: boolean): void;
|
|
38
|
+
/**
|
|
39
|
+
* Query whether Kitty keyboard protocol is currently active.
|
|
40
|
+
*/
|
|
41
|
+
export declare function isKittyProtocolActive(): boolean;
|
|
42
|
+
type Letter = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z";
|
|
43
|
+
type Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
|
|
44
|
+
type SymbolKey = "`" | "-" | "=" | "[" | "]" | "\\" | ";" | "'" | "," | "." | "/" | "!" | "@" | "#" | "$" | "%" | "^" | "&" | "*" | "(" | ")" | "_" | "+" | "|" | "~" | "{" | "}" | ":" | "<" | ">" | "?";
|
|
45
|
+
type SpecialKey = "escape" | "esc" | "enter" | "return" | "tab" | "space" | "backspace" | "delete" | "insert" | "clear" | "home" | "end" | "pageUp" | "pageDown" | "up" | "down" | "left" | "right" | "f1" | "f2" | "f3" | "f4" | "f5" | "f6" | "f7" | "f8" | "f9" | "f10" | "f11" | "f12";
|
|
46
|
+
type BaseKey = Letter | Digit | SymbolKey | SpecialKey;
|
|
47
|
+
type ModifierName = "ctrl" | "shift" | "alt" | "super";
|
|
48
|
+
type ModifiedKeyId<Key extends string, RemainingModifiers extends ModifierName = ModifierName> = {
|
|
49
|
+
[M in RemainingModifiers]: `${M}+${Key}` | `${M}+${ModifiedKeyId<Key, Exclude<RemainingModifiers, M>>}`;
|
|
50
|
+
}[RemainingModifiers];
|
|
51
|
+
/**
|
|
52
|
+
* Union type of all valid key identifiers.
|
|
53
|
+
* Provides autocomplete and catches typos at compile time.
|
|
54
|
+
*/
|
|
55
|
+
export type KeyId = BaseKey | ModifiedKeyId<BaseKey>;
|
|
56
|
+
/**
|
|
57
|
+
* Typed helper for constructing key identifiers with autocomplete.
|
|
58
|
+
*
|
|
59
|
+
* The runtime values are just the canonical key-name strings (so `Key.enter`
|
|
60
|
+
* is literally `"enter"`); the value of `Key` over a bag of magic strings is
|
|
61
|
+
* that each property is typed to the exact `KeyId` literal it produces and the
|
|
62
|
+
* modifier methods return precisely-typed concatenations (e.g. `Key.ctrl("c")`
|
|
63
|
+
* is `"ctrl+c"`, not just `string`). This mirrors the upstream
|
|
64
|
+
* `@mariozechner/pi-tui` `Key` export verbatim so plugins built against any
|
|
65
|
+
* scope alias (`@mariozechner`, `@earendil-works`, `@gajae-code`) keep working
|
|
66
|
+
* once the specifier shim remaps them to this package.
|
|
67
|
+
*/
|
|
68
|
+
export declare const Key: {
|
|
69
|
+
readonly escape: "escape";
|
|
70
|
+
readonly esc: "esc";
|
|
71
|
+
readonly enter: "enter";
|
|
72
|
+
readonly return: "return";
|
|
73
|
+
readonly tab: "tab";
|
|
74
|
+
readonly space: "space";
|
|
75
|
+
readonly backspace: "backspace";
|
|
76
|
+
readonly delete: "delete";
|
|
77
|
+
readonly insert: "insert";
|
|
78
|
+
readonly clear: "clear";
|
|
79
|
+
readonly home: "home";
|
|
80
|
+
readonly end: "end";
|
|
81
|
+
readonly pageUp: "pageUp";
|
|
82
|
+
readonly pageDown: "pageDown";
|
|
83
|
+
readonly up: "up";
|
|
84
|
+
readonly down: "down";
|
|
85
|
+
readonly left: "left";
|
|
86
|
+
readonly right: "right";
|
|
87
|
+
readonly f1: "f1";
|
|
88
|
+
readonly f2: "f2";
|
|
89
|
+
readonly f3: "f3";
|
|
90
|
+
readonly f4: "f4";
|
|
91
|
+
readonly f5: "f5";
|
|
92
|
+
readonly f6: "f6";
|
|
93
|
+
readonly f7: "f7";
|
|
94
|
+
readonly f8: "f8";
|
|
95
|
+
readonly f9: "f9";
|
|
96
|
+
readonly f10: "f10";
|
|
97
|
+
readonly f11: "f11";
|
|
98
|
+
readonly f12: "f12";
|
|
99
|
+
readonly backtick: "`";
|
|
100
|
+
readonly hyphen: "-";
|
|
101
|
+
readonly equals: "=";
|
|
102
|
+
readonly leftbracket: "[";
|
|
103
|
+
readonly rightbracket: "]";
|
|
104
|
+
readonly backslash: "\\";
|
|
105
|
+
readonly semicolon: ";";
|
|
106
|
+
readonly quote: "'";
|
|
107
|
+
readonly comma: ",";
|
|
108
|
+
readonly period: ".";
|
|
109
|
+
readonly slash: "/";
|
|
110
|
+
readonly exclamation: "!";
|
|
111
|
+
readonly at: "@";
|
|
112
|
+
readonly hash: "#";
|
|
113
|
+
readonly dollar: "$";
|
|
114
|
+
readonly percent: "%";
|
|
115
|
+
readonly caret: "^";
|
|
116
|
+
readonly ampersand: "&";
|
|
117
|
+
readonly asterisk: "*";
|
|
118
|
+
readonly leftparen: "(";
|
|
119
|
+
readonly rightparen: ")";
|
|
120
|
+
readonly underscore: "_";
|
|
121
|
+
readonly plus: "+";
|
|
122
|
+
readonly pipe: "|";
|
|
123
|
+
readonly tilde: "~";
|
|
124
|
+
readonly leftbrace: "{";
|
|
125
|
+
readonly rightbrace: "}";
|
|
126
|
+
readonly colon: ":";
|
|
127
|
+
readonly lessthan: "<";
|
|
128
|
+
readonly greaterthan: ">";
|
|
129
|
+
readonly question: "?";
|
|
130
|
+
readonly ctrl: <K extends BaseKey>(key: K) => `ctrl+${K}`;
|
|
131
|
+
readonly shift: <K extends BaseKey>(key: K) => `shift+${K}`;
|
|
132
|
+
readonly alt: <K extends BaseKey>(key: K) => `alt+${K}`;
|
|
133
|
+
readonly super: <K extends BaseKey>(key: K) => `super+${K}`;
|
|
134
|
+
readonly ctrlShift: <K extends BaseKey>(key: K) => `ctrl+shift+${K}`;
|
|
135
|
+
readonly shiftCtrl: <K extends BaseKey>(key: K) => `shift+ctrl+${K}`;
|
|
136
|
+
readonly ctrlAlt: <K extends BaseKey>(key: K) => `ctrl+alt+${K}`;
|
|
137
|
+
readonly altCtrl: <K extends BaseKey>(key: K) => `alt+ctrl+${K}`;
|
|
138
|
+
readonly shiftAlt: <K extends BaseKey>(key: K) => `shift+alt+${K}`;
|
|
139
|
+
readonly altShift: <K extends BaseKey>(key: K) => `alt+shift+${K}`;
|
|
140
|
+
readonly ctrlSuper: <K extends BaseKey>(key: K) => `ctrl+super+${K}`;
|
|
141
|
+
readonly superCtrl: <K extends BaseKey>(key: K) => `super+ctrl+${K}`;
|
|
142
|
+
readonly shiftSuper: <K extends BaseKey>(key: K) => `shift+super+${K}`;
|
|
143
|
+
readonly superShift: <K extends BaseKey>(key: K) => `super+shift+${K}`;
|
|
144
|
+
readonly altSuper: <K extends BaseKey>(key: K) => `alt+super+${K}`;
|
|
145
|
+
readonly superAlt: <K extends BaseKey>(key: K) => `super+alt+${K}`;
|
|
146
|
+
readonly ctrlShiftAlt: <K extends BaseKey>(key: K) => `ctrl+shift+alt+${K}`;
|
|
147
|
+
readonly ctrlShiftSuper: <K extends BaseKey>(key: K) => `ctrl+shift+super+${K}`;
|
|
148
|
+
};
|
|
149
|
+
interface ParsedKittySequence {
|
|
150
|
+
codepoint: number;
|
|
151
|
+
shiftedKey?: number;
|
|
152
|
+
baseLayoutKey?: number;
|
|
153
|
+
modifier: number;
|
|
154
|
+
eventType?: KeyEventType;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Check if the input is a key release event.
|
|
158
|
+
* Only meaningful when Kitty keyboard protocol with flag 2 is active.
|
|
159
|
+
* Returns false if Kitty protocol is not active.
|
|
160
|
+
*/
|
|
161
|
+
export declare function isKeyRelease(data: string): boolean;
|
|
162
|
+
/**
|
|
163
|
+
* Check if the input is a key repeat event.
|
|
164
|
+
* Only meaningful when Kitty keyboard protocol with flag 2 is active.
|
|
165
|
+
* Returns false if Kitty protocol is not active.
|
|
166
|
+
*/
|
|
167
|
+
export declare function isKeyRepeat(data: string): boolean;
|
|
168
|
+
export declare function parseKittySequence(data: string): ParsedKittySequence | null;
|
|
169
|
+
/**
|
|
170
|
+
* Extract printable text from raw terminal input.
|
|
171
|
+
*
|
|
172
|
+
* Handles Kitty CSI-u text-producing keys so text-entry components can treat
|
|
173
|
+
* keypad digits, keypad operators, and shifted symbols the same as direct character input.
|
|
174
|
+
*/
|
|
175
|
+
export declare function extractPrintableText(data: string): string | undefined;
|
|
176
|
+
/**
|
|
177
|
+
* Decode terminal input into the printable character it represents.
|
|
178
|
+
*
|
|
179
|
+
* Tries Kitty CSI-u first, then falls back to xterm modifyOtherKeys. Returns
|
|
180
|
+
* undefined for control sequences and modifier-only events.
|
|
181
|
+
*/
|
|
182
|
+
export declare function decodePrintableKey(data: string): string | undefined;
|
|
183
|
+
/**
|
|
184
|
+
* Match input data against a key identifier string.
|
|
185
|
+
*
|
|
186
|
+
* Supported key identifiers:
|
|
187
|
+
* - Single keys: "escape", "tab", "enter", "backspace", "delete", "home", "end", "space"
|
|
188
|
+
* - Arrow keys: "up", "down", "left", "right"
|
|
189
|
+
* - Ctrl combinations: "ctrl+c", "ctrl+z", etc.
|
|
190
|
+
* - Shift combinations: "shift+tab", "shift+enter"
|
|
191
|
+
* - Alt combinations: "alt+enter", "alt+backspace"
|
|
192
|
+
* - Combined modifiers: "shift+ctrl+p", "ctrl+alt+x"
|
|
193
|
+
*
|
|
194
|
+
* Use the Key helper for autocomplete: Key.ctrl("c"), Key.escape, Key.ctrlShift("p")
|
|
195
|
+
*
|
|
196
|
+
* @param data - Raw input data from terminal
|
|
197
|
+
* @param keyId - Key identifier (e.g., "ctrl+c", "escape", Key.ctrl("c"))
|
|
198
|
+
*/
|
|
199
|
+
export declare function matchesKey(data: string, keyId: KeyId): boolean;
|
|
200
|
+
/**
|
|
201
|
+
* Parse terminal input and return a normalized key identifier.
|
|
202
|
+
*
|
|
203
|
+
* Returns key names like "escape", "ctrl+c", "shift+tab", "alt+enter".
|
|
204
|
+
* Returns undefined if the input is not a recognized key sequence.
|
|
205
|
+
*
|
|
206
|
+
* @param data - Raw input data from terminal
|
|
207
|
+
*/
|
|
208
|
+
export declare function parseKey(data: string): string | undefined;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ring buffer for Emacs-style kill/yank operations.
|
|
3
|
+
*
|
|
4
|
+
* Tracks killed (deleted) text entries. Consecutive kills can accumulate
|
|
5
|
+
* into a single entry. Supports yank (paste most recent) and yank-pop
|
|
6
|
+
* (cycle through older entries).
|
|
7
|
+
*/
|
|
8
|
+
export declare class KillRing {
|
|
9
|
+
#private;
|
|
10
|
+
/**
|
|
11
|
+
* Add text to the kill ring.
|
|
12
|
+
*
|
|
13
|
+
* @param text - The killed text to add
|
|
14
|
+
* @param opts - Push options
|
|
15
|
+
* @param opts.prepend - If accumulating, prepend (backward deletion) or append (forward deletion)
|
|
16
|
+
* @param opts.accumulate - Merge with the most recent entry instead of creating a new one
|
|
17
|
+
*/
|
|
18
|
+
push(text: string, opts: {
|
|
19
|
+
prepend: boolean;
|
|
20
|
+
accumulate?: boolean;
|
|
21
|
+
}): void;
|
|
22
|
+
/** Get most recent entry without modifying the ring. */
|
|
23
|
+
peek(): string | undefined;
|
|
24
|
+
/** Move last entry to front (for yank-pop cycling). */
|
|
25
|
+
rotate(): void;
|
|
26
|
+
get length(): number;
|
|
27
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StdinBuffer buffers input and emits complete sequences.
|
|
3
|
+
*
|
|
4
|
+
* This is necessary because stdin data events can arrive in partial chunks,
|
|
5
|
+
* especially for escape sequences like mouse events. Without buffering,
|
|
6
|
+
* partial sequences can be misinterpreted as regular keypresses.
|
|
7
|
+
*
|
|
8
|
+
* For example, the mouse SGR sequence `\x1b[<35;20;5m` might arrive as:
|
|
9
|
+
* - Event 1: `\x1b`
|
|
10
|
+
* - Event 2: `[<35`
|
|
11
|
+
* - Event 3: `;20;5m`
|
|
12
|
+
*
|
|
13
|
+
* The buffer accumulates these until a complete sequence is detected.
|
|
14
|
+
* Call the `process()` method to feed input data.
|
|
15
|
+
*
|
|
16
|
+
* Based on code from OpenTUI (https://github.com/anomalyco/opentui)
|
|
17
|
+
* MIT License - Copyright (c) 2025 opentui
|
|
18
|
+
*/
|
|
19
|
+
import { EventEmitter } from "events";
|
|
20
|
+
export type StdinBufferOptions = {
|
|
21
|
+
/**
|
|
22
|
+
* Maximum time to wait for sequence completion (default: 10ms)
|
|
23
|
+
* After this time, the buffer is flushed even if incomplete
|
|
24
|
+
*/
|
|
25
|
+
timeout?: number;
|
|
26
|
+
};
|
|
27
|
+
export type StdinBufferEventMap = {
|
|
28
|
+
data: [string];
|
|
29
|
+
paste: [string];
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Buffers stdin input and emits complete sequences via the 'data' event.
|
|
33
|
+
* Handles partial escape sequences that arrive across multiple chunks.
|
|
34
|
+
*/
|
|
35
|
+
export declare class StdinBuffer extends EventEmitter<StdinBufferEventMap> {
|
|
36
|
+
#private;
|
|
37
|
+
constructor(options?: StdinBufferOptions);
|
|
38
|
+
process(data: string | Buffer): void;
|
|
39
|
+
flush(): string[];
|
|
40
|
+
clear(): void;
|
|
41
|
+
getBuffer(): string;
|
|
42
|
+
destroy(): void;
|
|
43
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface BoxSymbols {
|
|
2
|
+
topLeft: string;
|
|
3
|
+
topRight: string;
|
|
4
|
+
bottomLeft: string;
|
|
5
|
+
bottomRight: string;
|
|
6
|
+
horizontal: string;
|
|
7
|
+
vertical: string;
|
|
8
|
+
teeDown: string;
|
|
9
|
+
teeUp: string;
|
|
10
|
+
teeLeft: string;
|
|
11
|
+
teeRight: string;
|
|
12
|
+
cross: string;
|
|
13
|
+
}
|
|
14
|
+
export interface SymbolTheme {
|
|
15
|
+
cursor: string;
|
|
16
|
+
inputCursor: string;
|
|
17
|
+
boxRound: Omit<BoxSymbols, "teeDown" | "teeUp" | "teeLeft" | "teeRight" | "cross">;
|
|
18
|
+
boxSharp: BoxSymbols;
|
|
19
|
+
table: BoxSymbols;
|
|
20
|
+
quoteBorder: string;
|
|
21
|
+
hrChar: string;
|
|
22
|
+
spinnerFrames: string[];
|
|
23
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export declare enum ImageProtocol {
|
|
2
|
+
Kitty = "\u001B_G",
|
|
3
|
+
Iterm2 = "\u001B]1337;File=",
|
|
4
|
+
Sixel = "\u001BPq"
|
|
5
|
+
}
|
|
6
|
+
export declare enum NotifyProtocol {
|
|
7
|
+
Bell = "\u0007",
|
|
8
|
+
Osc99 = "\u001B]99;;",
|
|
9
|
+
Osc9 = "\u001B]9;"
|
|
10
|
+
}
|
|
11
|
+
export type TerminalId = "kitty" | "ghostty" | "wezterm" | "iterm2" | "vscode" | "alacritty" | "base" | "trueColor";
|
|
12
|
+
/** Terminal capability details used for rendering and protocol selection. */
|
|
13
|
+
export declare class TerminalInfo {
|
|
14
|
+
readonly id: TerminalId;
|
|
15
|
+
readonly imageProtocol: ImageProtocol | null;
|
|
16
|
+
readonly trueColor: boolean;
|
|
17
|
+
readonly hyperlinks: boolean;
|
|
18
|
+
readonly notifyProtocol: NotifyProtocol;
|
|
19
|
+
constructor(id: TerminalId, imageProtocol: ImageProtocol | null, trueColor: boolean, hyperlinks: boolean, notifyProtocol?: NotifyProtocol);
|
|
20
|
+
isImageLine(line: string): boolean;
|
|
21
|
+
formatNotification(message: string): string;
|
|
22
|
+
sendNotification(message: string): void;
|
|
23
|
+
}
|
|
24
|
+
export declare function isNotificationSuppressed(): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Returns true when running in Windows Terminal with known SIXEL support.
|
|
27
|
+
*
|
|
28
|
+
* Windows Terminal introduced SIXEL support in preview 1.22.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isWindowsTerminalPreviewSixelSupported(env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): boolean;
|
|
31
|
+
export declare const TERMINAL_ID: TerminalId;
|
|
32
|
+
export declare const TERMINAL: TerminalInfo;
|
|
33
|
+
/**
|
|
34
|
+
* Override terminal image protocol at runtime after capability probes complete.
|
|
35
|
+
*/
|
|
36
|
+
export declare function setTerminalImageProtocol(imageProtocol: ImageProtocol | null): void;
|
|
37
|
+
export declare function getTerminalInfo(terminalId: TerminalId): TerminalInfo;
|
|
38
|
+
export interface CellDimensions {
|
|
39
|
+
widthPx: number;
|
|
40
|
+
heightPx: number;
|
|
41
|
+
}
|
|
42
|
+
export interface ImageDimensions {
|
|
43
|
+
widthPx: number;
|
|
44
|
+
heightPx: number;
|
|
45
|
+
}
|
|
46
|
+
export interface ImageRenderOptions {
|
|
47
|
+
maxWidthCells?: number;
|
|
48
|
+
maxHeightCells?: number;
|
|
49
|
+
preserveAspectRatio?: boolean;
|
|
50
|
+
}
|
|
51
|
+
export declare function getCellDimensions(): CellDimensions;
|
|
52
|
+
export declare function setCellDimensions(dims: CellDimensions): void;
|
|
53
|
+
export declare function encodeKitty(base64Data: string, options?: {
|
|
54
|
+
columns?: number;
|
|
55
|
+
rows?: number;
|
|
56
|
+
imageId?: number;
|
|
57
|
+
}): string;
|
|
58
|
+
export declare function encodeITerm2(base64Data: string, options?: {
|
|
59
|
+
width?: number | string;
|
|
60
|
+
height?: number | string;
|
|
61
|
+
name?: string;
|
|
62
|
+
preserveAspectRatio?: boolean;
|
|
63
|
+
inline?: boolean;
|
|
64
|
+
}): string;
|
|
65
|
+
export declare function calculateImageRows(imageDimensions: ImageDimensions, targetWidthCells: number, cellDimensions?: CellDimensions): number;
|
|
66
|
+
export declare function getPngDimensions(base64Data: string): ImageDimensions | null;
|
|
67
|
+
export declare function getJpegDimensions(base64Data: string): ImageDimensions | null;
|
|
68
|
+
export declare function getGifDimensions(base64Data: string): ImageDimensions | null;
|
|
69
|
+
export declare function getWebpDimensions(base64Data: string): ImageDimensions | null;
|
|
70
|
+
export declare function getImageDimensions(base64Data: string, mimeType: string): ImageDimensions | null;
|
|
71
|
+
export declare function renderImage(base64Data: string, imageDimensions: ImageDimensions, options?: ImageRenderOptions): {
|
|
72
|
+
sequence: string;
|
|
73
|
+
rows: number;
|
|
74
|
+
} | null;
|
|
75
|
+
export declare function imageFallback(mimeType: string, dimensions?: ImageDimensions, filename?: string): string;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emergency terminal restore - call this from signal/crash handlers
|
|
3
|
+
* Resets terminal state without requiring access to the ProcessTerminal instance
|
|
4
|
+
*/
|
|
5
|
+
export declare function emergencyTerminalRestore(): void;
|
|
6
|
+
/** Terminal-reported appearance (dark/light mode). */
|
|
7
|
+
export type TerminalAppearance = "dark" | "light";
|
|
8
|
+
export interface Terminal {
|
|
9
|
+
start(onInput: (data: string) => void, onResize: () => void): void;
|
|
10
|
+
stop(): void;
|
|
11
|
+
/**
|
|
12
|
+
* Drain stdin before exiting to prevent Kitty key release events from
|
|
13
|
+
* leaking to the parent shell over slow SSH connections.
|
|
14
|
+
* @param maxMs - Maximum time to drain (default: 1000ms)
|
|
15
|
+
* @param idleMs - Exit early if no input arrives within this time (default: 50ms)
|
|
16
|
+
*/
|
|
17
|
+
drainInput(maxMs?: number, idleMs?: number): Promise<void>;
|
|
18
|
+
write(data: string): void;
|
|
19
|
+
get columns(): number;
|
|
20
|
+
get rows(): number;
|
|
21
|
+
get kittyProtocolActive(): boolean;
|
|
22
|
+
moveBy(lines: number): void;
|
|
23
|
+
hideCursor(): void;
|
|
24
|
+
showCursor(): void;
|
|
25
|
+
clearLine(): void;
|
|
26
|
+
clearFromCursor(): void;
|
|
27
|
+
clearScreen(): void;
|
|
28
|
+
setTitle(title: string): void;
|
|
29
|
+
setProgress(active: boolean): void;
|
|
30
|
+
/**
|
|
31
|
+
* Register a callback for terminal appearance (dark/light) changes.
|
|
32
|
+
* Detection uses OSC 11 background color query with Mode 2031 as a change trigger.
|
|
33
|
+
* Fires when the detected appearance changes, including the initial detection.
|
|
34
|
+
*/
|
|
35
|
+
onAppearanceChange(callback: (appearance: TerminalAppearance) => void): void;
|
|
36
|
+
/** The last detected terminal appearance, or undefined if not yet known. */
|
|
37
|
+
get appearance(): TerminalAppearance | undefined;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Real terminal using process.stdin/stdout
|
|
41
|
+
*/
|
|
42
|
+
export declare class ProcessTerminal implements Terminal {
|
|
43
|
+
#private;
|
|
44
|
+
get kittyProtocolActive(): boolean;
|
|
45
|
+
get appearance(): TerminalAppearance | undefined;
|
|
46
|
+
onAppearanceChange(callback: (appearance: TerminalAppearance) => void): void;
|
|
47
|
+
start(onInput: (data: string) => void, onResize: () => void): void;
|
|
48
|
+
drainInput(maxMs?: number, idleMs?: number): Promise<void>;
|
|
49
|
+
stop(): void;
|
|
50
|
+
write(data: string): void;
|
|
51
|
+
get columns(): number;
|
|
52
|
+
get rows(): number;
|
|
53
|
+
moveBy(lines: number): void;
|
|
54
|
+
hideCursor(): void;
|
|
55
|
+
showCursor(): void;
|
|
56
|
+
clearLine(): void;
|
|
57
|
+
clearFromCursor(): void;
|
|
58
|
+
clearScreen(): void;
|
|
59
|
+
setTitle(title: string): void;
|
|
60
|
+
setProgress(active: boolean): void;
|
|
61
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Resolve the TTY device path for stdin (fd 0) via POSIX `ttyname(3)`. */
|
|
2
|
+
export declare function getTtyPath(): string | null;
|
|
3
|
+
/**
|
|
4
|
+
* Get a stable identifier for the current terminal.
|
|
5
|
+
* Uses the TTY device path (e.g., /dev/pts/3), falling back to environment
|
|
6
|
+
* variables for terminal multiplexers or terminal emulators.
|
|
7
|
+
* Returns null if no terminal can be identified (e.g., piped input).
|
|
8
|
+
*/
|
|
9
|
+
export declare function getTerminalId(): string | null;
|