@opentui/core 0.0.0-20251106-788e97e4 → 0.0.0-20251112-a24ada2d
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/3d.js +140 -140
- package/3d.js.map +2 -2
- package/Renderable.d.ts +1 -3
- package/console.d.ts +2 -2
- package/{index-pb1pm3hk.js → index-kj9k00yt.js} +669 -441
- package/index-kj9k00yt.js.map +58 -0
- package/index.js +174 -95
- package/index.js.map +6 -6
- package/lib/KeyHandler.d.ts +4 -9
- package/lib/keymapping.d.ts +1 -0
- package/lib/stdin-buffer.d.ts +8 -6
- package/lib/terminal-capability-detection.d.ts +30 -0
- package/package.json +8 -8
- package/renderables/Code.d.ts +4 -7
- package/renderables/ScrollBox.d.ts +3 -1
- package/renderables/Textarea.d.ts +2 -1
- package/renderables/__tests__/renderable-test-utils.d.ts +7 -0
- package/renderer.d.ts +9 -0
- package/testing/mock-keys.d.ts +5 -1
- package/testing/test-renderer.d.ts +2 -0
- package/testing.js +162 -27
- package/testing.js.map +4 -4
- package/text-buffer.d.ts +2 -0
- package/zig-structs.d.ts +8 -0
- package/zig.d.ts +2 -0
- package/index-pb1pm3hk.js.map +0 -57
package/lib/KeyHandler.d.ts
CHANGED
|
@@ -36,16 +36,11 @@ export type KeyHandlerEventMap = {
|
|
|
36
36
|
paste: [PasteEvent];
|
|
37
37
|
};
|
|
38
38
|
export declare class KeyHandler extends EventEmitter<KeyHandlerEventMap> {
|
|
39
|
-
protected stdin: NodeJS.ReadStream;
|
|
40
39
|
protected useKittyKeyboard: boolean;
|
|
41
|
-
protected pasteMode: boolean;
|
|
42
|
-
protected pasteBuffer: string[];
|
|
43
40
|
private suspended;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
private processSequence;
|
|
48
|
-
destroy(): void;
|
|
41
|
+
constructor(useKittyKeyboard?: boolean);
|
|
42
|
+
processInput(data: string): boolean;
|
|
43
|
+
processPaste(data: string): void;
|
|
49
44
|
suspend(): void;
|
|
50
45
|
resume(): void;
|
|
51
46
|
}
|
|
@@ -55,7 +50,7 @@ export declare class KeyHandler extends EventEmitter<KeyHandlerEventMap> {
|
|
|
55
50
|
*/
|
|
56
51
|
export declare class InternalKeyHandler extends KeyHandler {
|
|
57
52
|
private renderableHandlers;
|
|
58
|
-
constructor(
|
|
53
|
+
constructor(useKittyKeyboard?: boolean);
|
|
59
54
|
emit<K extends keyof KeyHandlerEventMap>(event: K, ...args: KeyHandlerEventMap[K]): boolean;
|
|
60
55
|
private emitWithPriority;
|
|
61
56
|
onInternal<K extends keyof KeyHandlerEventMap>(event: K, handler: (...args: KeyHandlerEventMap[K]) => void): void;
|
package/lib/keymapping.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export interface KeyBinding<Action extends string = string> {
|
|
|
3
3
|
ctrl?: boolean;
|
|
4
4
|
shift?: boolean;
|
|
5
5
|
meta?: boolean;
|
|
6
|
+
super?: boolean;
|
|
6
7
|
action: Action;
|
|
7
8
|
}
|
|
8
9
|
export declare function mergeKeyBindings<Action extends string>(defaults: KeyBinding<Action>[], custom: KeyBinding<Action>[]): KeyBinding<Action>[];
|
package/lib/stdin-buffer.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* StdinBuffer
|
|
2
|
+
* StdinBuffer buffers input and emits complete sequences.
|
|
3
3
|
*
|
|
4
4
|
* This is necessary because stdin data events can arrive in partial chunks,
|
|
5
5
|
* especially for escape sequences like mouse events. Without buffering,
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* - Event 3: `;20;5m`
|
|
12
12
|
*
|
|
13
13
|
* The buffer accumulates these until a complete sequence is detected.
|
|
14
|
+
* Call the `process()` method to feed input data.
|
|
14
15
|
*/
|
|
15
16
|
import { EventEmitter } from "events";
|
|
16
17
|
export type StdinBufferOptions = {
|
|
@@ -22,19 +23,20 @@ export type StdinBufferOptions = {
|
|
|
22
23
|
};
|
|
23
24
|
export type StdinBufferEventMap = {
|
|
24
25
|
data: [string];
|
|
26
|
+
paste: [string];
|
|
25
27
|
};
|
|
26
28
|
/**
|
|
27
|
-
*
|
|
29
|
+
* Buffers stdin input and emits complete sequences via the 'data' event.
|
|
28
30
|
* Handles partial escape sequences that arrive across multiple chunks.
|
|
29
31
|
*/
|
|
30
32
|
export declare class StdinBuffer extends EventEmitter<StdinBufferEventMap> {
|
|
31
33
|
private buffer;
|
|
32
34
|
private timeout;
|
|
33
35
|
private readonly timeoutMs;
|
|
34
|
-
private
|
|
35
|
-
private
|
|
36
|
-
constructor(
|
|
37
|
-
|
|
36
|
+
private pasteMode;
|
|
37
|
+
private pasteBuffer;
|
|
38
|
+
constructor(options?: StdinBufferOptions);
|
|
39
|
+
process(data: string | Buffer): void;
|
|
38
40
|
flush(): string[];
|
|
39
41
|
clear(): void;
|
|
40
42
|
getBuffer(): string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal capability response detection utilities.
|
|
3
|
+
*
|
|
4
|
+
* Detects various terminal capability response sequences:
|
|
5
|
+
* - DECRPM (DEC Request Mode): ESC[?...;N$y where N is 0,1,2,3,4
|
|
6
|
+
* - CPR (Cursor Position Report): ESC[row;colR (used for width detection)
|
|
7
|
+
* - XTVersion: ESC P >| ... ESC \
|
|
8
|
+
* - Kitty Graphics: ESC _ G ... ESC \
|
|
9
|
+
* - Kitty Keyboard Query: ESC[?Nu where N is 0,1,2,etc
|
|
10
|
+
* - DA1 (Device Attributes): ESC[?...c
|
|
11
|
+
* - Pixel Resolution: ESC[4;height;widtht
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Check if a sequence is a terminal capability response.
|
|
15
|
+
* Returns true if the sequence matches any known capability response pattern.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isCapabilityResponse(sequence: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Check if a sequence is a pixel resolution response.
|
|
20
|
+
* Format: ESC[4;height;widtht
|
|
21
|
+
*/
|
|
22
|
+
export declare function isPixelResolutionResponse(sequence: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Parse pixel resolution from response sequence.
|
|
25
|
+
* Returns { width, height } or null if not a valid resolution response.
|
|
26
|
+
*/
|
|
27
|
+
export declare function parsePixelResolution(sequence: string): {
|
|
28
|
+
width: number;
|
|
29
|
+
height: number;
|
|
30
|
+
} | null;
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"types": "index.d.ts",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"version": "0.0.0-
|
|
7
|
+
"version": "0.0.0-20251112-a24ada2d",
|
|
8
8
|
"description": "OpenTUI is a TypeScript library for building terminal user interfaces (TUIs)",
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"repository": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"bun-ffi-structs": "
|
|
38
|
+
"bun-ffi-structs": "0.1.2",
|
|
39
39
|
"jimp": "1.6.0",
|
|
40
40
|
"yoga-layout": "3.2.1"
|
|
41
41
|
},
|
|
@@ -55,11 +55,11 @@
|
|
|
55
55
|
"bun-webgpu": "0.1.3",
|
|
56
56
|
"planck": "^1.4.2",
|
|
57
57
|
"three": "0.177.0",
|
|
58
|
-
"@opentui/core-darwin-x64": "0.0.0-
|
|
59
|
-
"@opentui/core-darwin-arm64": "0.0.0-
|
|
60
|
-
"@opentui/core-linux-x64": "0.0.0-
|
|
61
|
-
"@opentui/core-linux-arm64": "0.0.0-
|
|
62
|
-
"@opentui/core-win32-x64": "0.0.0-
|
|
63
|
-
"@opentui/core-win32-arm64": "0.0.0-
|
|
58
|
+
"@opentui/core-darwin-x64": "0.0.0-20251112-a24ada2d",
|
|
59
|
+
"@opentui/core-darwin-arm64": "0.0.0-20251112-a24ada2d",
|
|
60
|
+
"@opentui/core-linux-x64": "0.0.0-20251112-a24ada2d",
|
|
61
|
+
"@opentui/core-linux-arm64": "0.0.0-20251112-a24ada2d",
|
|
62
|
+
"@opentui/core-win32-x64": "0.0.0-20251112-a24ada2d",
|
|
63
|
+
"@opentui/core-win32-arm64": "0.0.0-20251112-a24ada2d"
|
|
64
64
|
}
|
|
65
65
|
}
|
package/renderables/Code.d.ts
CHANGED
|
@@ -18,9 +18,8 @@ export declare class CodeRenderable extends TextBufferRenderable {
|
|
|
18
18
|
private _syntaxStyle;
|
|
19
19
|
private _isHighlighting;
|
|
20
20
|
private _treeSitterClient;
|
|
21
|
-
private
|
|
22
|
-
private
|
|
23
|
-
private _currentHighlightId;
|
|
21
|
+
private _highlightsDirty;
|
|
22
|
+
private _highlightSnapshotId;
|
|
24
23
|
private _conceal;
|
|
25
24
|
private _drawUnstyledText;
|
|
26
25
|
private _shouldRenderTextBuffer;
|
|
@@ -48,10 +47,8 @@ export declare class CodeRenderable extends TextBufferRenderable {
|
|
|
48
47
|
set streaming(value: boolean);
|
|
49
48
|
get treeSitterClient(): TreeSitterClient;
|
|
50
49
|
set treeSitterClient(value: TreeSitterClient);
|
|
51
|
-
private
|
|
52
|
-
private
|
|
53
|
-
private fallback;
|
|
54
|
-
private createFallbackStyledText;
|
|
50
|
+
private ensureVisibleTextBeforeHighlight;
|
|
51
|
+
private startHighlight;
|
|
55
52
|
getLineHighlights(lineIdx: number): import("..").Highlight[];
|
|
56
53
|
protected renderSelf(buffer: OptimizedBuffer): void;
|
|
57
54
|
}
|
|
@@ -12,7 +12,7 @@ declare class ContentRenderable extends BoxRenderable {
|
|
|
12
12
|
constructor(ctx: RenderContext, viewport: BoxRenderable, viewportCulling: boolean, options: RenderableOptions<BoxRenderable>);
|
|
13
13
|
get viewportCulling(): boolean;
|
|
14
14
|
set viewportCulling(value: boolean);
|
|
15
|
-
protected
|
|
15
|
+
protected _getVisibleChildren(): number[];
|
|
16
16
|
}
|
|
17
17
|
export interface ScrollBoxOptions extends BoxOptions<ScrollBoxRenderable> {
|
|
18
18
|
rootOptions?: BoxOptions;
|
|
@@ -57,6 +57,7 @@ export declare class ScrollBoxRenderable extends BoxRenderable {
|
|
|
57
57
|
private _stickyScrollRight;
|
|
58
58
|
private _stickyStart?;
|
|
59
59
|
private _hasManualScroll;
|
|
60
|
+
private _isApplyingStickyScroll;
|
|
60
61
|
private scrollAccel;
|
|
61
62
|
get stickyScroll(): boolean;
|
|
62
63
|
set stickyScroll(value: boolean);
|
|
@@ -80,6 +81,7 @@ export declare class ScrollBoxRenderable extends BoxRenderable {
|
|
|
80
81
|
x: number;
|
|
81
82
|
y: number;
|
|
82
83
|
}): void;
|
|
84
|
+
private isAtStickyPosition;
|
|
83
85
|
add(obj: Renderable | VNode<any, any[]>, index?: number): number;
|
|
84
86
|
insertBefore(obj: Renderable | VNode<any, any[]> | unknown, anchor?: Renderable | unknown): number;
|
|
85
87
|
remove(id: string): void;
|
|
@@ -5,7 +5,7 @@ import { RGBA, type ColorInput } from "../lib/RGBA";
|
|
|
5
5
|
import { type KeyBinding as BaseKeyBinding } from "../lib/keymapping";
|
|
6
6
|
import { type StyledText } from "../lib/styled-text";
|
|
7
7
|
import type { ExtmarksController } from "../lib/extmarks";
|
|
8
|
-
export type TextareaAction = "move-left" | "move-right" | "move-up" | "move-down" | "select-left" | "select-right" | "select-up" | "select-down" | "line-home" | "line-end" | "select-line-home" | "select-line-end" | "buffer-home" | "buffer-end" | "delete-line" | "delete-to-line-end" | "backspace" | "delete" | "newline" | "undo" | "redo" | "word-forward" | "word-backward" | "select-word-forward" | "select-word-backward" | "delete-word-forward" | "delete-word-backward" | "submit";
|
|
8
|
+
export type TextareaAction = "move-left" | "move-right" | "move-up" | "move-down" | "select-left" | "select-right" | "select-up" | "select-down" | "line-home" | "line-end" | "select-line-home" | "select-line-end" | "buffer-home" | "buffer-end" | "delete-line" | "delete-to-line-end" | "delete-to-line-start" | "backspace" | "delete" | "newline" | "undo" | "redo" | "word-forward" | "word-backward" | "select-word-forward" | "select-word-backward" | "delete-word-forward" | "delete-word-backward" | "submit";
|
|
9
9
|
export type KeyBinding = BaseKeyBinding<TextareaAction>;
|
|
10
10
|
export interface SubmitEvent {
|
|
11
11
|
}
|
|
@@ -65,6 +65,7 @@ export declare class TextareaRenderable extends EditBufferRenderable {
|
|
|
65
65
|
gotoBufferHome(): boolean;
|
|
66
66
|
gotoBufferEnd(): boolean;
|
|
67
67
|
deleteToLineEnd(): boolean;
|
|
68
|
+
deleteToLineStart(): boolean;
|
|
68
69
|
undo(): boolean;
|
|
69
70
|
redo(): boolean;
|
|
70
71
|
moveWordForward(options?: {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { TextareaRenderable } from "../Textarea";
|
|
2
|
+
import { type TestRenderer } from "../../testing/test-renderer";
|
|
3
|
+
import { type TextareaOptions } from "../Textarea";
|
|
4
|
+
export declare function createTextareaRenderable(renderer: TestRenderer, renderOnce: () => Promise<void>, options: TextareaOptions): Promise<{
|
|
5
|
+
textarea: TextareaRenderable;
|
|
6
|
+
root: any;
|
|
7
|
+
}>;
|
package/renderer.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ export interface CliRendererConfig {
|
|
|
30
30
|
useKittyKeyboard?: boolean;
|
|
31
31
|
backgroundColor?: ColorInput;
|
|
32
32
|
openConsoleOnError?: boolean;
|
|
33
|
+
prependInputHandlers?: ((sequence: string) => boolean)[];
|
|
33
34
|
}
|
|
34
35
|
export type PixelResolution = {
|
|
35
36
|
width: number;
|
|
@@ -126,6 +127,7 @@ export declare class CliRenderer extends EventEmitter implements RenderContext {
|
|
|
126
127
|
private _console;
|
|
127
128
|
private _resolution;
|
|
128
129
|
private _keyHandler;
|
|
130
|
+
private _stdinBuffer;
|
|
129
131
|
private animationRequest;
|
|
130
132
|
private resizeTimeoutId;
|
|
131
133
|
private resizeDebounceDelay;
|
|
@@ -157,6 +159,8 @@ export declare class CliRenderer extends EventEmitter implements RenderContext {
|
|
|
157
159
|
private _paletteDetector;
|
|
158
160
|
private _cachedPalette;
|
|
159
161
|
private _paletteDetectionPromise;
|
|
162
|
+
private inputHandlers;
|
|
163
|
+
private prependedInputHandlers;
|
|
160
164
|
private handleError;
|
|
161
165
|
private dumpOutputCache;
|
|
162
166
|
private exitHandler;
|
|
@@ -202,6 +206,11 @@ export declare class CliRenderer extends EventEmitter implements RenderContext {
|
|
|
202
206
|
set useThread(useThread: boolean);
|
|
203
207
|
setupTerminal(): Promise<void>;
|
|
204
208
|
private stdinListener;
|
|
209
|
+
addInputHandler(handler: (sequence: string) => boolean): void;
|
|
210
|
+
prependInputHandler(handler: (sequence: string) => boolean): void;
|
|
211
|
+
removeInputHandler(handler: (sequence: string) => boolean): void;
|
|
212
|
+
private capabilityHandler;
|
|
213
|
+
private focusHandler;
|
|
205
214
|
private setupInput;
|
|
206
215
|
private handleMouseData;
|
|
207
216
|
private takeMemorySnapshot;
|
package/testing/mock-keys.d.ts
CHANGED
|
@@ -26,7 +26,11 @@ export declare const KeyCodes: {
|
|
|
26
26
|
readonly F12: "\u001B[24~";
|
|
27
27
|
};
|
|
28
28
|
export type KeyInput = string | keyof typeof KeyCodes;
|
|
29
|
-
export
|
|
29
|
+
export interface MockKeysOptions {
|
|
30
|
+
kittyKeyboard?: boolean;
|
|
31
|
+
otherModifiersMode?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export declare function createMockKeys(renderer: CliRenderer, options?: MockKeysOptions): {
|
|
30
34
|
pressKeys: (keys: KeyInput[], delayMs?: number) => Promise<void>;
|
|
31
35
|
pressKey: (key: KeyInput, modifiers?: {
|
|
32
36
|
shift?: boolean;
|
|
@@ -4,6 +4,8 @@ import { createMockMouse } from "./mock-mouse";
|
|
|
4
4
|
export interface TestRendererOptions extends CliRendererConfig {
|
|
5
5
|
width?: number;
|
|
6
6
|
height?: number;
|
|
7
|
+
kittyKeyboard?: boolean;
|
|
8
|
+
otherModifiersMode?: boolean;
|
|
7
9
|
}
|
|
8
10
|
export interface TestRenderer extends CliRenderer {
|
|
9
11
|
}
|
package/testing.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
CliRenderer,
|
|
5
5
|
TreeSitterClient,
|
|
6
6
|
resolveRenderLib
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-kj9k00yt.js";
|
|
8
8
|
|
|
9
9
|
// src/testing/mock-keys.ts
|
|
10
10
|
var KeyCodes = {
|
|
@@ -34,22 +34,88 @@ var KeyCodes = {
|
|
|
34
34
|
F11: "\x1B[23~",
|
|
35
35
|
F12: "\x1B[24~"
|
|
36
36
|
};
|
|
37
|
-
|
|
37
|
+
var kittyKeyCodeMap = {
|
|
38
|
+
escape: 27,
|
|
39
|
+
tab: 9,
|
|
40
|
+
return: 13,
|
|
41
|
+
backspace: 127,
|
|
42
|
+
insert: 57348,
|
|
43
|
+
delete: 57349,
|
|
44
|
+
left: 57350,
|
|
45
|
+
right: 57351,
|
|
46
|
+
up: 57352,
|
|
47
|
+
down: 57353,
|
|
48
|
+
pageup: 57354,
|
|
49
|
+
pagedown: 57355,
|
|
50
|
+
home: 57356,
|
|
51
|
+
end: 57357,
|
|
52
|
+
f1: 57364,
|
|
53
|
+
f2: 57365,
|
|
54
|
+
f3: 57366,
|
|
55
|
+
f4: 57367,
|
|
56
|
+
f5: 57368,
|
|
57
|
+
f6: 57369,
|
|
58
|
+
f7: 57370,
|
|
59
|
+
f8: 57371,
|
|
60
|
+
f9: 57372,
|
|
61
|
+
f10: 57373,
|
|
62
|
+
f11: 57374,
|
|
63
|
+
f12: 57375
|
|
64
|
+
};
|
|
65
|
+
function encodeKittySequence(codepoint, modifiers) {
|
|
66
|
+
let modMask = 0;
|
|
67
|
+
if (modifiers?.shift)
|
|
68
|
+
modMask |= 1;
|
|
69
|
+
if (modifiers?.meta)
|
|
70
|
+
modMask |= 2;
|
|
71
|
+
if (modifiers?.ctrl)
|
|
72
|
+
modMask |= 4;
|
|
73
|
+
if (modMask === 0) {
|
|
74
|
+
return `\x1B[${codepoint}u`;
|
|
75
|
+
} else {
|
|
76
|
+
return `\x1B[${codepoint};${modMask + 1}u`;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function encodeModifyOtherKeysSequence(charCode, modifiers) {
|
|
80
|
+
let modMask = 0;
|
|
81
|
+
if (modifiers?.shift)
|
|
82
|
+
modMask |= 1;
|
|
83
|
+
if (modifiers?.meta)
|
|
84
|
+
modMask |= 2;
|
|
85
|
+
if (modifiers?.ctrl)
|
|
86
|
+
modMask |= 4;
|
|
87
|
+
if (modMask === 0) {
|
|
88
|
+
return String.fromCharCode(charCode);
|
|
89
|
+
}
|
|
90
|
+
return `\x1B[27;${modMask + 1};${charCode}~`;
|
|
91
|
+
}
|
|
92
|
+
function resolveKeyInput(key) {
|
|
93
|
+
let keyValue;
|
|
94
|
+
let keyName;
|
|
95
|
+
if (typeof key === "string") {
|
|
96
|
+
if (key in KeyCodes) {
|
|
97
|
+
keyValue = KeyCodes[key];
|
|
98
|
+
keyName = key.toLowerCase();
|
|
99
|
+
} else {
|
|
100
|
+
keyValue = key;
|
|
101
|
+
keyName = undefined;
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
keyValue = KeyCodes[key];
|
|
105
|
+
if (!keyValue) {
|
|
106
|
+
throw new Error(`Unknown key: ${key}`);
|
|
107
|
+
}
|
|
108
|
+
keyName = String(key).toLowerCase();
|
|
109
|
+
}
|
|
110
|
+
return { keyValue, keyName };
|
|
111
|
+
}
|
|
112
|
+
function createMockKeys(renderer, options) {
|
|
113
|
+
const useKittyKeyboard = options?.kittyKeyboard ?? false;
|
|
114
|
+
const useOtherModifiersMode = options?.otherModifiersMode ?? false;
|
|
115
|
+
const effectiveOtherModifiersMode = useOtherModifiersMode && !useKittyKeyboard;
|
|
38
116
|
const pressKeys = async (keys, delayMs = 0) => {
|
|
39
117
|
for (const key of keys) {
|
|
40
|
-
|
|
41
|
-
if (typeof key === "string") {
|
|
42
|
-
if (key in KeyCodes) {
|
|
43
|
-
keyCode = KeyCodes[key];
|
|
44
|
-
} else {
|
|
45
|
-
keyCode = key;
|
|
46
|
-
}
|
|
47
|
-
} else {
|
|
48
|
-
keyCode = KeyCodes[key];
|
|
49
|
-
if (!keyCode) {
|
|
50
|
-
throw new Error(`Unknown key: ${key}`);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
118
|
+
const { keyValue: keyCode } = resolveKeyInput(key);
|
|
53
119
|
renderer.stdin.emit("data", Buffer.from(keyCode));
|
|
54
120
|
if (delayMs > 0) {
|
|
55
121
|
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
@@ -57,19 +123,66 @@ function createMockKeys(renderer) {
|
|
|
57
123
|
}
|
|
58
124
|
};
|
|
59
125
|
const pressKey = (key, modifiers) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
126
|
+
if (useKittyKeyboard) {
|
|
127
|
+
let { keyValue, keyName } = resolveKeyInput(key);
|
|
128
|
+
const valueToKeyNameMap = {
|
|
129
|
+
"\b": "backspace",
|
|
130
|
+
"\r": "return",
|
|
131
|
+
"\n": "return",
|
|
132
|
+
"\t": "tab",
|
|
133
|
+
"\x1B": "escape",
|
|
134
|
+
"\x1B[A": "up",
|
|
135
|
+
"\x1B[B": "down",
|
|
136
|
+
"\x1B[C": "right",
|
|
137
|
+
"\x1B[D": "left",
|
|
138
|
+
"\x1B[H": "home",
|
|
139
|
+
"\x1B[F": "end",
|
|
140
|
+
"\x1B[3~": "delete"
|
|
141
|
+
};
|
|
142
|
+
if (keyValue && valueToKeyNameMap[keyValue]) {
|
|
143
|
+
keyName = valueToKeyNameMap[keyValue];
|
|
66
144
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
145
|
+
if (keyName && keyName.startsWith("arrow_")) {
|
|
146
|
+
keyName = keyName.substring(6);
|
|
147
|
+
}
|
|
148
|
+
if (keyName && kittyKeyCodeMap[keyName]) {
|
|
149
|
+
const kittyCode = kittyKeyCodeMap[keyName];
|
|
150
|
+
const sequence = encodeKittySequence(kittyCode, modifiers);
|
|
151
|
+
renderer.stdin.emit("data", Buffer.from(sequence));
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (keyValue && keyValue.length === 1 && !keyValue.startsWith("\x1B")) {
|
|
155
|
+
const codepoint = keyValue.codePointAt(0);
|
|
156
|
+
if (codepoint) {
|
|
157
|
+
const sequence = encodeKittySequence(codepoint, modifiers);
|
|
158
|
+
renderer.stdin.emit("data", Buffer.from(sequence));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
71
161
|
}
|
|
72
162
|
}
|
|
163
|
+
if (effectiveOtherModifiersMode && modifiers) {
|
|
164
|
+
let { keyValue, keyName } = resolveKeyInput(key);
|
|
165
|
+
const valueToCharCodeMap = {
|
|
166
|
+
"\b": 127,
|
|
167
|
+
"\r": 13,
|
|
168
|
+
"\n": 13,
|
|
169
|
+
"\t": 9,
|
|
170
|
+
"\x1B": 27,
|
|
171
|
+
" ": 32
|
|
172
|
+
};
|
|
173
|
+
let charCode;
|
|
174
|
+
if (keyValue && valueToCharCodeMap[keyValue] !== undefined) {
|
|
175
|
+
charCode = valueToCharCodeMap[keyValue];
|
|
176
|
+
} else if (keyValue && keyValue.length === 1 && !keyValue.startsWith("\x1B")) {
|
|
177
|
+
charCode = keyValue.charCodeAt(0);
|
|
178
|
+
}
|
|
179
|
+
if (charCode !== undefined) {
|
|
180
|
+
const sequence = encodeModifyOtherKeysSequence(charCode, modifiers);
|
|
181
|
+
renderer.stdin.emit("data", Buffer.from(sequence));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
let keyCode = resolveKeyInput(key).keyValue;
|
|
73
186
|
if (modifiers) {
|
|
74
187
|
if (keyCode.startsWith("\x1B[") && keyCode.length > 2) {
|
|
75
188
|
const modifier = 1 + (modifiers.shift ? 1 : 0) + (modifiers.meta ? 2 : 0) + (modifiers.ctrl ? 4 : 0);
|
|
@@ -84,6 +197,24 @@ function createMockKeys(renderer) {
|
|
|
84
197
|
keyCode = String.fromCharCode(char.charCodeAt(0) - 96);
|
|
85
198
|
} else if (char >= "A" && char <= "Z") {
|
|
86
199
|
keyCode = String.fromCharCode(char.charCodeAt(0) - 64);
|
|
200
|
+
} else {
|
|
201
|
+
const specialCtrlMap = {
|
|
202
|
+
"[": "\x1B",
|
|
203
|
+
"\\": "\x1C",
|
|
204
|
+
"]": "\x1D",
|
|
205
|
+
"^": "\x1E",
|
|
206
|
+
_: "\x1F",
|
|
207
|
+
"?": "\x7F",
|
|
208
|
+
"/": "\x1F",
|
|
209
|
+
"-": "\x1F",
|
|
210
|
+
".": "\x1E",
|
|
211
|
+
",": "\x1C",
|
|
212
|
+
"@": "\x00",
|
|
213
|
+
" ": "\x00"
|
|
214
|
+
};
|
|
215
|
+
if (char in specialCtrlMap) {
|
|
216
|
+
keyCode = specialCtrlMap[char];
|
|
217
|
+
}
|
|
87
218
|
}
|
|
88
219
|
if (modifiers.meta) {
|
|
89
220
|
keyCode = `\x1B${keyCode}`;
|
|
@@ -305,7 +436,10 @@ async function createTestRenderer(options) {
|
|
|
305
436
|
useConsole: false
|
|
306
437
|
});
|
|
307
438
|
renderer.disableStdoutInterception();
|
|
308
|
-
const mockInput = createMockKeys(renderer
|
|
439
|
+
const mockInput = createMockKeys(renderer, {
|
|
440
|
+
kittyKeyboard: options.kittyKeyboard,
|
|
441
|
+
otherModifiersMode: options.otherModifiersMode
|
|
442
|
+
});
|
|
309
443
|
const mockMouse = createMockMouse(renderer);
|
|
310
444
|
const renderOnce = async () => {
|
|
311
445
|
await renderer.loop();
|
|
@@ -344,6 +478,7 @@ async function setupTestRenderer(config) {
|
|
|
344
478
|
}
|
|
345
479
|
ziglib.setUseThread(rendererPtr, config.useThread);
|
|
346
480
|
const renderer = new CliRenderer(ziglib, rendererPtr, stdin, stdout, width, height, config);
|
|
481
|
+
process.off("SIGWINCH", renderer["sigwinchHandler"]);
|
|
347
482
|
return renderer;
|
|
348
483
|
}
|
|
349
484
|
// src/testing/mock-tree-sitter-client.ts
|
|
@@ -401,5 +536,5 @@ export {
|
|
|
401
536
|
KeyCodes
|
|
402
537
|
};
|
|
403
538
|
|
|
404
|
-
//# debugId=
|
|
539
|
+
//# debugId=87F3E86F73786CEC64756E2164756E21
|
|
405
540
|
//# sourceMappingURL=testing.js.map
|