jeopi-tui 16.2.13
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 +1861 -0
- package/README.md +705 -0
- package/dist/types/autocomplete.d.ts +99 -0
- package/dist/types/bracketed-paste.d.ts +51 -0
- package/dist/types/components/box.d.ts +31 -0
- package/dist/types/components/cancellable-loader.d.ts +21 -0
- package/dist/types/components/editor.d.ts +155 -0
- package/dist/types/components/image.d.ts +112 -0
- package/dist/types/components/input.d.ts +23 -0
- package/dist/types/components/loader.d.ts +20 -0
- package/dist/types/components/markdown.d.ts +64 -0
- package/dist/types/components/scroll-view.d.ts +62 -0
- package/dist/types/components/select-list.d.ts +68 -0
- package/dist/types/components/settings-list.d.ts +123 -0
- package/dist/types/components/spacer.d.ts +11 -0
- package/dist/types/components/tab-bar.d.ts +89 -0
- package/dist/types/components/text.d.ts +14 -0
- package/dist/types/components/truncated-text.d.ts +10 -0
- package/dist/types/deccara.d.ts +49 -0
- package/dist/types/desktop-notify.d.ts +51 -0
- package/dist/types/editor-component.d.ts +38 -0
- package/dist/types/fuzzy.d.ts +32 -0
- package/dist/types/index.d.ts +32 -0
- package/dist/types/keybindings.d.ts +191 -0
- package/dist/types/keys.d.ts +208 -0
- package/dist/types/kill-ring.d.ts +20 -0
- package/dist/types/kitty-graphics.d.ts +79 -0
- package/dist/types/latex-block.d.ts +7 -0
- package/dist/types/latex-to-unicode.d.ts +33 -0
- package/dist/types/loop-watchdog.d.ts +39 -0
- package/dist/types/mouse.d.ts +67 -0
- package/dist/types/stdin-buffer.d.ts +60 -0
- package/dist/types/symbols.d.ts +25 -0
- package/dist/types/terminal-capabilities.d.ts +284 -0
- package/dist/types/terminal.d.ts +107 -0
- package/dist/types/ttyid.d.ts +9 -0
- package/dist/types/tui.d.ts +423 -0
- package/dist/types/utils.d.ts +95 -0
- package/package.json +73 -0
- package/src/autocomplete.ts +1026 -0
- package/src/bracketed-paste.ts +123 -0
- package/src/components/box.ts +194 -0
- package/src/components/cancellable-loader.ts +40 -0
- package/src/components/editor.ts +3092 -0
- package/src/components/image.ts +444 -0
- package/src/components/input.ts +474 -0
- package/src/components/loader.ts +103 -0
- package/src/components/markdown.ts +2068 -0
- package/src/components/scroll-view.ts +227 -0
- package/src/components/select-list.ts +531 -0
- package/src/components/settings-list.ts +793 -0
- package/src/components/spacer.ts +32 -0
- package/src/components/tab-bar.ts +300 -0
- package/src/components/text.ts +122 -0
- package/src/components/truncated-text.ts +69 -0
- package/src/deccara.ts +314 -0
- package/src/desktop-notify.ts +186 -0
- package/src/editor-component.ts +74 -0
- package/src/fuzzy.ts +356 -0
- package/src/index.ts +51 -0
- package/src/keybindings.ts +337 -0
- package/src/keys.ts +561 -0
- package/src/kill-ring.ts +51 -0
- package/src/kitty-graphics.ts +171 -0
- package/src/latex-block.ts +461 -0
- package/src/latex-to-unicode.ts +1994 -0
- package/src/loop-watchdog.ts +106 -0
- package/src/mouse.ts +105 -0
- package/src/stdin-buffer.ts +669 -0
- package/src/symbols.ts +26 -0
- package/src/terminal-capabilities.ts +1152 -0
- package/src/terminal.ts +1463 -0
- package/src/ttyid.ts +84 -0
- package/src/tui.ts +3901 -0
- package/src/utils.ts +570 -0
|
@@ -0,0 +1,191 @@
|
|
|
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", "super+alt+backspace"];
|
|
106
|
+
readonly description: "Delete word backward";
|
|
107
|
+
};
|
|
108
|
+
readonly "tui.editor.deleteWordForward": {
|
|
109
|
+
readonly defaultKeys: ["alt+delete", "alt+d", "super+alt+delete", "super+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", "ctrl+j"];
|
|
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 function canonicalKeyId(key: string): string;
|
|
178
|
+
export declare function addKeyAliases(keys: Set<string>, key: KeyId): void;
|
|
179
|
+
export declare class KeybindingsManager {
|
|
180
|
+
#private;
|
|
181
|
+
constructor(definitions: KeybindingDefinitions, userBindings?: KeybindingsConfig);
|
|
182
|
+
matches(data: string, keybinding: Keybinding): boolean;
|
|
183
|
+
getKeys(keybinding: Keybinding): KeyId[];
|
|
184
|
+
getDefinition(keybinding: Keybinding): KeybindingDefinition;
|
|
185
|
+
getConflicts(): KeybindingConflict[];
|
|
186
|
+
setUserBindings(userBindings: KeybindingsConfig): void;
|
|
187
|
+
getUserBindings(): KeybindingsConfig;
|
|
188
|
+
getResolvedBindings(): KeybindingsConfig;
|
|
189
|
+
}
|
|
190
|
+
export declare function setKeybindings(keybindings: KeybindingsManager): void;
|
|
191
|
+
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 "jeopi-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`, `@oh-my-pi`) 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,20 @@
|
|
|
1
|
+
export declare class KillRing {
|
|
2
|
+
#private;
|
|
3
|
+
/**
|
|
4
|
+
* Add text to the kill ring.
|
|
5
|
+
*
|
|
6
|
+
* @param text - The killed text to add
|
|
7
|
+
* @param opts - Push options
|
|
8
|
+
* @param opts.prepend - If accumulating, prepend (backward deletion) or append (forward deletion)
|
|
9
|
+
* @param opts.accumulate - Merge with the most recent entry instead of creating a new one
|
|
10
|
+
*/
|
|
11
|
+
push(text: string, opts: {
|
|
12
|
+
prepend: boolean;
|
|
13
|
+
accumulate?: boolean;
|
|
14
|
+
}): void;
|
|
15
|
+
/** Get most recent entry without modifying the ring. */
|
|
16
|
+
peek(): string | undefined;
|
|
17
|
+
/** Move last entry to front (for yank-pop cycling). */
|
|
18
|
+
rotate(): void;
|
|
19
|
+
get length(): number;
|
|
20
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kitty graphics: Unicode placeholder placement (`U=1` + U+10EEEE), with
|
|
3
|
+
* runtime feature state and env overrides.
|
|
4
|
+
*
|
|
5
|
+
* Unicode placeholders let a transmitted image be displayed by writing ordinary
|
|
6
|
+
* text cells — the placeholder char U+10EEEE plus row/column combining
|
|
7
|
+
* diacritics — instead of a cursor-positioned `a=p` direct placement. The image
|
|
8
|
+
* then participates in the normal text grid, so it survives horizontal slicing,
|
|
9
|
+
* reflow and overlapping draws (each cell names its own row+column, so a sliced
|
|
10
|
+
* row still maps to the correct sub-region). See kitty
|
|
11
|
+
* `docs/graphics-protocol.rst` "Unicode placeholders for relative placements".
|
|
12
|
+
*
|
|
13
|
+
* This module is intentionally free of `./terminal-capabilities` imports so the
|
|
14
|
+
* dependency stays one-way (capabilities → kitty-graphics) and no import cycle
|
|
15
|
+
* forms. Protocol gating (`imageProtocol === Kitty`) lives in the caller.
|
|
16
|
+
*/
|
|
17
|
+
/** Kitty Unicode placeholder base character (U+10EEEE, Plane 16 PUA). */
|
|
18
|
+
export declare const KITTY_PLACEHOLDER = "\uDBFB\uDEEE";
|
|
19
|
+
/** Largest row/column index expressible with the diacritic table (one cell each). */
|
|
20
|
+
export declare const KITTY_PLACEHOLDER_MAX_CELLS: number;
|
|
21
|
+
export interface KittyGraphicsFeatures {
|
|
22
|
+
/** Display images via Unicode placeholders instead of direct `a=p` placement. */
|
|
23
|
+
unicodePlaceholders: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Whether the detected terminal renders Kitty Unicode placeholders (`U=1` +
|
|
27
|
+
* U+10EEEE with row/column diacritics).
|
|
28
|
+
*
|
|
29
|
+
* Only `kitty` (the protocol's origin) and `ghostty` ship a working
|
|
30
|
+
* implementation; WezTerm advertises Kitty graphics but treats placeholder
|
|
31
|
+
* cells as literal PUA glyphs (see wezterm/wezterm#986, "placeholder support"
|
|
32
|
+
* still unchecked), and the tmux/screen fallback can land on any outer
|
|
33
|
+
* terminal. Enabling placeholders on those paths emits a `columns × rows`
|
|
34
|
+
* grid of U+10EEEE per image per frame; the cells render as boxed fallback
|
|
35
|
+
* glyphs and re-emit on every repaint, which is exactly the
|
|
36
|
+
* "stuck/laggy scrolling + ASCII artifact" symptom reported in #1877.
|
|
37
|
+
*
|
|
38
|
+
* `PI_NO_KITTY_PLACEHOLDERS=1` forces off (e.g. for tmux passthrough to a
|
|
39
|
+
* non-supporting outer terminal); `PI_KITTY_PLACEHOLDERS=1` forces on (e.g.
|
|
40
|
+
* for a wezterm nightly that has merged placeholder support).
|
|
41
|
+
*/
|
|
42
|
+
export declare function detectKittyUnicodePlaceholdersSupport(terminalId: string, env?: NodeJS.ProcessEnv): boolean;
|
|
43
|
+
export declare function getKittyGraphics(): Readonly<KittyGraphicsFeatures>;
|
|
44
|
+
export declare function setKittyGraphics(partial: Partial<KittyGraphicsFeatures>): void;
|
|
45
|
+
/** Whether a `columns`×`rows` placeholder grid fits within the diacritic table. */
|
|
46
|
+
export declare function kittyPlaceholdersFit(columns: number, rows: number): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Virtual placement APC (`a=p,U=1`): tells the terminal that placeholder cells
|
|
49
|
+
* carrying image id `i` should display the transmitted image, scaled to fit the
|
|
50
|
+
* `c`×`r` cell box. Re-emitting with a stable `placementId` replaces in place.
|
|
51
|
+
*/
|
|
52
|
+
export declare function encodeKittyVirtualPlacement(opts: {
|
|
53
|
+
imageId: number;
|
|
54
|
+
placementId?: number;
|
|
55
|
+
columns: number;
|
|
56
|
+
rows: number;
|
|
57
|
+
}): string;
|
|
58
|
+
/**
|
|
59
|
+
* Build the placeholder cell grid as one string per row. The image id is carried
|
|
60
|
+
* in each row's foreground color and the placement id (if any) in its underline
|
|
61
|
+
* color; every cell names its explicit row+column diacritic (robust to slicing,
|
|
62
|
+
* unlike left-inheritance). Returns exactly `rows` strings.
|
|
63
|
+
*/
|
|
64
|
+
export declare function encodeKittyPlaceholderGrid(opts: {
|
|
65
|
+
imageId: number;
|
|
66
|
+
placementId?: number;
|
|
67
|
+
columns: number;
|
|
68
|
+
rows: number;
|
|
69
|
+
}): string[];
|
|
70
|
+
/**
|
|
71
|
+
* Full placeholder render: the virtual-placement APC prefixes line 0, and every
|
|
72
|
+
* line carries placeholder cells. Returns exactly `rows` lines (no cursor moves).
|
|
73
|
+
*/
|
|
74
|
+
export declare function renderKittyPlaceholderLines(opts: {
|
|
75
|
+
imageId: number;
|
|
76
|
+
placementId?: number;
|
|
77
|
+
columns: number;
|
|
78
|
+
rows: number;
|
|
79
|
+
}): string[];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render a display LaTeX math fragment to lines, stacking `\frac` vertically.
|
|
3
|
+
* Top-level source newlines become vertical rows (so a `lhs =` line stays above
|
|
4
|
+
* its block); each row stacks fractions via `parseExpr`. Inline math should use
|
|
5
|
+
* `latexToUnicode` instead — fractions there stay single-line.
|
|
6
|
+
*/
|
|
7
|
+
export declare function latexToBlock(src: string): string[];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a bare LaTeX math fragment (no surrounding `$`/`\(` delimiters) to its
|
|
3
|
+
* best-effort Unicode rendering. Unknown commands degrade to their bare name;
|
|
4
|
+
* `\\` becomes a newline. Always returns a string (never throws).
|
|
5
|
+
*/
|
|
6
|
+
export declare function latexToUnicode(src: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* True when `env` is a math environment safe to auto-render without `$`/`\[`
|
|
9
|
+
* delimiters. The trailing `*` of starred variants (`align*`, `equation*`) is
|
|
10
|
+
* ignored; text-mode environments (`tabular`, `itemize`, …) return false.
|
|
11
|
+
*/
|
|
12
|
+
export declare function isBareMathEnvironment(env: string): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Scan prose for math spans — `$$…$$`, `\[…\]` (display) and `$…$`, `\(…\)`
|
|
15
|
+
* (inline) — and replace each with its Unicode rendering, leaving everything
|
|
16
|
+
* else verbatim. Newlines inside a span collapse to spaces so the result stays
|
|
17
|
+
* single-line-safe.
|
|
18
|
+
*
|
|
19
|
+
* Inline `$…$` uses pandoc's anti-currency heuristics: the opener must not be
|
|
20
|
+
* followed by whitespace, the closer must not be preceded by whitespace nor
|
|
21
|
+
* followed by a digit, and `\$` is treated as a literal dollar — so "$5 and
|
|
22
|
+
* $10" is left untouched.
|
|
23
|
+
*/
|
|
24
|
+
export declare function renderMathInText(text: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Index of the `$` that closes an inline math span opened at `open` (the index
|
|
27
|
+
* of the opening `$`), or -1 when the run is not inline math. Applies pandoc's
|
|
28
|
+
* anti-currency heuristics: the opener must not be followed by whitespace, the
|
|
29
|
+
* closer must not be preceded by whitespace nor followed by a digit, `\$` is a
|
|
30
|
+
* literal dollar, and the span may not span a newline. Shared by
|
|
31
|
+
* `renderMathInText` and the markdown math tokenizer so the rule has one home.
|
|
32
|
+
*/
|
|
33
|
+
export declare function inlineMathSpanEnd(text: string, open: number): number;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface LoopWatchdogOptions {
|
|
2
|
+
/** How far ahead each probe tick is scheduled, in ms. Default 250. */
|
|
3
|
+
intervalMs?: number;
|
|
4
|
+
/** A tick later than this past its deadline counts as a block. Default 250. */
|
|
5
|
+
thresholdMs?: number;
|
|
6
|
+
/** Monotonic clock source; injectable for tests. Default `performance.now`. */
|
|
7
|
+
now?: () => number;
|
|
8
|
+
/** Timer source; injectable for tests. Default `setTimeout`. */
|
|
9
|
+
schedule?: (cb: () => void, ms: number) => LoopWatchdogTimer;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Timer handle the watchdog arms. `cancel`, when present, is invoked on stop()
|
|
13
|
+
* so a stopped watchdog leaves no armed timer to wake the loop even once.
|
|
14
|
+
*/
|
|
15
|
+
interface LoopWatchdogTimer {
|
|
16
|
+
unref?(): void;
|
|
17
|
+
cancel?(): void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Always-on event-loop lag probe. Each tick is scheduled `intervalMs` ahead of
|
|
21
|
+
* a recorded deadline; a tick that fires `thresholdMs` past its deadline means
|
|
22
|
+
* the loop was blocked that long. The overshoot is logged once on the rising
|
|
23
|
+
* edge (one block ⇒ one line, deduped via `#wasBlocked`), tagged with the phase
|
|
24
|
+
* active during the elapsed interval via {@link takeRecentLoopPhase} — which
|
|
25
|
+
* survives the synchronous push/pop the instrumented hot paths do before this
|
|
26
|
+
* delayed tick can run — so the stall names its cause instead of "unknown".
|
|
27
|
+
*
|
|
28
|
+
* The handle is `unref`'d so the probe never keeps the process alive, and stop()
|
|
29
|
+
* cancels the armed timer when the handle exposes `cancel` (the default
|
|
30
|
+
* `setTimeout` handle does, via `clearTimeout`). The `#generation` guard remains
|
|
31
|
+
* as a fallback for injected handles that cannot cancel.
|
|
32
|
+
*/
|
|
33
|
+
export declare class LoopWatchdog {
|
|
34
|
+
#private;
|
|
35
|
+
constructor(options?: LoopWatchdogOptions);
|
|
36
|
+
start(): void;
|
|
37
|
+
stop(): void;
|
|
38
|
+
}
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SGR mouse report parsing (`\x1b[<button;col;rowM` / `…m`).
|
|
3
|
+
*
|
|
4
|
+
* Mouse tracking is enabled only while a fullscreen overlay holds the
|
|
5
|
+
* alternate screen (see tui.ts MOUSE_TRACKING_ON), so consumers are
|
|
6
|
+
* fullscreen components hit-testing against their own rendered frame:
|
|
7
|
+
* the frame paints from screen row 0, hence `row`/`col` are exposed
|
|
8
|
+
* 0-based for direct indexing into rendered lines.
|
|
9
|
+
*/
|
|
10
|
+
/** A decoded SGR mouse report. */
|
|
11
|
+
export interface SgrMouseEvent {
|
|
12
|
+
/** Raw button code (bit 32 = motion, bit 64 = wheel, low bits = button). */
|
|
13
|
+
button: number;
|
|
14
|
+
/** 0-based column of the event. */
|
|
15
|
+
col: number;
|
|
16
|
+
/** 0-based row of the event. */
|
|
17
|
+
row: number;
|
|
18
|
+
/** True for a release report (`m` suffix). */
|
|
19
|
+
release: boolean;
|
|
20
|
+
/** Wheel direction: -1 up, 1 down, null when not a wheel event. */
|
|
21
|
+
wheel: -1 | 1 | null;
|
|
22
|
+
/** True when the pointer moved (hover or drag) rather than clicked. */
|
|
23
|
+
motion: boolean;
|
|
24
|
+
/** True for a left-button press (not motion, not release, not wheel). */
|
|
25
|
+
leftClick: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Decode an SGR mouse report, or return null when `data` is not one.
|
|
29
|
+
* Callers on hot keypress paths should pre-check `data.startsWith("\x1b[<")`
|
|
30
|
+
* before paying for the regex.
|
|
31
|
+
*/
|
|
32
|
+
export declare function parseSgrMouse(data: string): SgrMouseEvent | null;
|
|
33
|
+
/** Handler invoked with a decoded SGR event; returning `false` reports unhandled. */
|
|
34
|
+
export type SgrMouseHandler = (event: SgrMouseEvent) => boolean | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Decode an SGR mouse report and forward it to `handler`. Returns `false` when
|
|
37
|
+
* `data` is not an SGR mouse report (or fails to parse), so callers can fall
|
|
38
|
+
* through to other input handling. Centralizes the repeated
|
|
39
|
+
* `data.startsWith("\x1b[<")` + `parseSgrMouse()` pattern.
|
|
40
|
+
*/
|
|
41
|
+
export declare function routeSgrMouseInput(data: string, handler: SgrMouseHandler): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Structural view of a SelectList-like target for mouse routing. Declared here
|
|
44
|
+
* (rather than importing the component) to keep this core module free of any
|
|
45
|
+
* component-to-core import cycle.
|
|
46
|
+
*/
|
|
47
|
+
export interface SelectListMouseTarget {
|
|
48
|
+
handleWheel(delta: -1 | 1): void;
|
|
49
|
+
hitTest(line: number): number | undefined;
|
|
50
|
+
setHoverIndex(index: number | null): void;
|
|
51
|
+
clickItem(index: number): void;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Route a decoded mouse event against a SelectList-like target at the given
|
|
55
|
+
* 0-based frame-local `line`. Centralizes the repeated wheel/hit-test/hover/
|
|
56
|
+
* click pattern. Returns `true` when the event was consumed.
|
|
57
|
+
*/
|
|
58
|
+
export declare function routeSelectListMouse(target: SelectListMouseTarget, event: SgrMouseEvent, line: number): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Implemented by components that accept routed mouse events at frame-local
|
|
61
|
+
* coordinates. Hosts translate screen coordinates to the component's own
|
|
62
|
+
* rendered lines before forwarding.
|
|
63
|
+
*/
|
|
64
|
+
export interface MouseRoutable {
|
|
65
|
+
/** `line`/`col` are 0-based within the component's rendered output. */
|
|
66
|
+
routeMouse(event: SgrMouseEvent, line: number, col: number): void;
|
|
67
|
+
}
|