@cplieger/web-terminal-engine 5.3.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -61
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/connection.ts +1205 -1676
- package/src/index.ts +20 -100
- package/src/keyboard.ts +56 -133
- package/src/modes.ts +92 -166
- package/src/mouse.ts +380 -413
- package/src/render.ts +1894 -2355
- package/src/scroll.ts +225 -476
- package/src/store.ts +1 -1
- package/src/terminal.ts +135 -0
- package/src/toolbar.ts +29 -43
package/src/modes.ts
CHANGED
|
@@ -1,31 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
// mirrors the modes of whichever session the live socket serves: the
|
|
3
|
-
// connection module is the single writer (it applies every inbound modes
|
|
4
|
-
// frame via applySnapshot AND, in a tabbed shell, synchronously restores the
|
|
5
|
-
// target session's cached snapshot inside setSession — power-on defaults for
|
|
6
|
-
// a session never seen). Readers therefore never observe another session's
|
|
7
|
-
// modes after setSession returns; the only staleness left is the inherent
|
|
8
|
-
// one-frame lag against the session's own server state. Used by:
|
|
9
|
-
// - keyboard.ts arrow-key encoder: emits SS3 (ESC O letter) when
|
|
10
|
-
// applicationCursor is true, CSI (ESC [ letter) otherwise.
|
|
11
|
-
// - paste handling: wraps in \e[200~..\e[201~ only when
|
|
12
|
-
// bracketedPaste is on; otherwise sends raw text.
|
|
13
|
-
// - mouse.ts: encodes mouse events only when mouseMode > 0.
|
|
14
|
-
//
|
|
15
|
-
// Defaults: bracketedPaste starts true because most modern shells
|
|
16
|
-
// (bash 4.4+, zsh, fish) enable it immediately on startup via
|
|
17
|
-
// CSI ?2004h. Starting false would cause the first paste before the
|
|
18
|
-
// server's modes frame arrives to be sent un-bracketed, which shells
|
|
19
|
-
// interpret as typed input (potentially executing pasted commands
|
|
20
|
-
// character-by-character). applicationCursor starts false (normal
|
|
21
|
-
// mode) because that's the VT100 power-on default.
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* One session's complete DEC-mode mirror, as a typed value (P3). The
|
|
25
|
-
* connection module caches one per session and applies it via applySnapshot;
|
|
26
|
-
* the named-field shape (vs setModes' nine positional parameters) makes
|
|
27
|
-
* field-order drift impossible for production writers.
|
|
28
|
-
*/
|
|
1
|
+
/** One session's complete DEC-mode mirror, as a typed value. */
|
|
29
2
|
export interface ModeSnapshot {
|
|
30
3
|
bracketedPaste: boolean;
|
|
31
4
|
applicationCursor: boolean;
|
|
@@ -39,11 +12,12 @@ export interface ModeSnapshot {
|
|
|
39
12
|
}
|
|
40
13
|
|
|
41
14
|
/**
|
|
42
|
-
* The VT power-on mode state
|
|
43
|
-
*
|
|
44
|
-
*
|
|
15
|
+
* The VT power-on mode state, frozen: copy it (`{ ...POWER_ON_MODES }`) before
|
|
16
|
+
* changing a field. `bracketedPaste` starts true because modern shells enable
|
|
17
|
+
* DEC 2004 at startup, and a paste delivered un-bracketed before the server's
|
|
18
|
+
* first modes frame would be executed as typed input.
|
|
45
19
|
*/
|
|
46
|
-
export const POWER_ON_MODES: Readonly<ModeSnapshot> = {
|
|
20
|
+
export const POWER_ON_MODES: Readonly<ModeSnapshot> = Object.freeze({
|
|
47
21
|
bracketedPaste: true,
|
|
48
22
|
applicationCursor: false,
|
|
49
23
|
mouseSGR: false,
|
|
@@ -53,144 +27,96 @@ export const POWER_ON_MODES: Readonly<ModeSnapshot> = {
|
|
|
53
27
|
reverseVideo: false,
|
|
54
28
|
mousePixels: false,
|
|
55
29
|
keyboardFlags: 0,
|
|
56
|
-
};
|
|
30
|
+
});
|
|
57
31
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
*/
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
applicationCursor = appCursor;
|
|
88
|
-
if (mSGR !== undefined) {
|
|
89
|
-
mouseSGR = mSGR;
|
|
90
|
-
}
|
|
91
|
-
if (focus !== undefined) {
|
|
92
|
-
focusReporting = focus;
|
|
93
|
-
}
|
|
94
|
-
if (mMode !== undefined) {
|
|
95
|
-
mouseMode = mMode;
|
|
96
|
-
}
|
|
97
|
-
if (appKeypad !== undefined) {
|
|
98
|
-
applicationKeypad = appKeypad;
|
|
99
|
-
}
|
|
100
|
-
if (revVideo !== undefined) {
|
|
101
|
-
reverseVideo = revVideo;
|
|
102
|
-
}
|
|
103
|
-
if (mPixels !== undefined) {
|
|
104
|
-
mousePixels = mPixels;
|
|
105
|
-
}
|
|
106
|
-
if (kbdFlags !== undefined) {
|
|
107
|
-
keyboardFlags = kbdFlags;
|
|
108
|
-
}
|
|
32
|
+
/** The DEC private-mode state of one terminal instance. */
|
|
33
|
+
export interface ModeState {
|
|
34
|
+
/** True when the server has DEC 2004 (bracketed paste) enabled. */
|
|
35
|
+
isBracketedPaste(): boolean;
|
|
36
|
+
/** True when the server has DECCKM (application cursor keys) enabled. */
|
|
37
|
+
isApplicationCursor(): boolean;
|
|
38
|
+
/** Active mouse tracking mode (xterm DECSET): 0 = off, 1000 = normal, 1002 = button-event, 1003 = any-event. */
|
|
39
|
+
getMouseMode(): number;
|
|
40
|
+
/** True when the server has DEC 1006 (SGR mouse encoding) enabled. */
|
|
41
|
+
isMouseSGR(): boolean;
|
|
42
|
+
/** True when the server has DEC 1016 (SGR-pixels mouse) enabled: reports carry pixel coordinates. */
|
|
43
|
+
isMousePixels(): boolean;
|
|
44
|
+
/** True when the server has DEC 1004 (focus event reporting) enabled. */
|
|
45
|
+
isFocusReporting(): boolean;
|
|
46
|
+
/** True when the server has DECKPAM (application keypad) enabled. */
|
|
47
|
+
isApplicationKeypad(): boolean;
|
|
48
|
+
/** True when the server has DEC 5 (reverse video / DECSCNM) enabled. */
|
|
49
|
+
isReverseVideo(): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Kitty keyboard progressive-enhancement flags in effect (bit0 disambiguate,
|
|
52
|
+
* bit1 report-event-types, bit2 report-alternate-keys); 0 means legacy encoding.
|
|
53
|
+
*/
|
|
54
|
+
getKeyboardFlags(): number;
|
|
55
|
+
/** Replaces every mode bit with the snapshot's; no field is left at its previous value. */
|
|
56
|
+
applySnapshot(s: Readonly<ModeSnapshot>): void;
|
|
57
|
+
/** The current mode state as a snapshot value (a copy; safe to retain). */
|
|
58
|
+
snapshot(): ModeSnapshot;
|
|
59
|
+
/** Resets every field to `POWER_ON_MODES` and makes `applySnapshot` a no-op. */
|
|
60
|
+
dispose(): void;
|
|
109
61
|
}
|
|
110
62
|
|
|
111
|
-
/**
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
63
|
+
/** Creates independent mode state initialized from a copy of `initial` (default `POWER_ON_MODES`). */
|
|
64
|
+
export function createModeState(initial: Readonly<ModeSnapshot> = POWER_ON_MODES): ModeState {
|
|
65
|
+
let bracketedPaste = initial.bracketedPaste;
|
|
66
|
+
let applicationCursor = initial.applicationCursor;
|
|
67
|
+
let mouseSGR = initial.mouseSGR;
|
|
68
|
+
let focusReporting = initial.focusReporting;
|
|
69
|
+
let mouseMode = initial.mouseMode;
|
|
70
|
+
let applicationKeypad = initial.applicationKeypad;
|
|
71
|
+
let reverseVideo = initial.reverseVideo;
|
|
72
|
+
let mousePixels = initial.mousePixels;
|
|
73
|
+
let keyboardFlags = initial.keyboardFlags;
|
|
74
|
+
let disposed = false;
|
|
75
|
+
|
|
76
|
+
function assign(s: Readonly<ModeSnapshot>): void {
|
|
77
|
+
bracketedPaste = s.bracketedPaste;
|
|
78
|
+
applicationCursor = s.applicationCursor;
|
|
79
|
+
mouseSGR = s.mouseSGR;
|
|
80
|
+
focusReporting = s.focusReporting;
|
|
81
|
+
mouseMode = s.mouseMode;
|
|
82
|
+
applicationKeypad = s.applicationKeypad;
|
|
83
|
+
reverseVideo = s.reverseVideo;
|
|
84
|
+
mousePixels = s.mousePixels;
|
|
85
|
+
keyboardFlags = s.keyboardFlags;
|
|
86
|
+
}
|
|
128
87
|
|
|
129
|
-
/** The current mode state as a snapshot value (a copy; safe to retain). */
|
|
130
|
-
export function snapshot(): ModeSnapshot {
|
|
131
88
|
return {
|
|
132
|
-
bracketedPaste,
|
|
133
|
-
applicationCursor,
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
keyboardFlags,
|
|
89
|
+
isBracketedPaste: () => bracketedPaste,
|
|
90
|
+
isApplicationCursor: () => applicationCursor,
|
|
91
|
+
getMouseMode: () => mouseMode,
|
|
92
|
+
isMouseSGR: () => mouseSGR,
|
|
93
|
+
isMousePixels: () => mousePixels,
|
|
94
|
+
isFocusReporting: () => focusReporting,
|
|
95
|
+
isApplicationKeypad: () => applicationKeypad,
|
|
96
|
+
isReverseVideo: () => reverseVideo,
|
|
97
|
+
getKeyboardFlags: () => keyboardFlags,
|
|
98
|
+
applySnapshot(s: Readonly<ModeSnapshot>): void {
|
|
99
|
+
if (disposed) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
assign(s);
|
|
103
|
+
},
|
|
104
|
+
snapshot(): ModeSnapshot {
|
|
105
|
+
return {
|
|
106
|
+
bracketedPaste,
|
|
107
|
+
applicationCursor,
|
|
108
|
+
mouseSGR,
|
|
109
|
+
focusReporting,
|
|
110
|
+
mouseMode,
|
|
111
|
+
applicationKeypad,
|
|
112
|
+
reverseVideo,
|
|
113
|
+
mousePixels,
|
|
114
|
+
keyboardFlags,
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
dispose(): void {
|
|
118
|
+
disposed = true;
|
|
119
|
+
assign(POWER_ON_MODES);
|
|
120
|
+
},
|
|
141
121
|
};
|
|
142
122
|
}
|
|
143
|
-
|
|
144
|
-
/** True when the server has DEC 2004 (bracketed paste) enabled. */
|
|
145
|
-
export function isBracketedPaste(): boolean {
|
|
146
|
-
return bracketedPaste;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/** True when the server has DECCKM (application cursor keys) enabled. */
|
|
150
|
-
export function isApplicationCursor(): boolean {
|
|
151
|
-
return applicationCursor;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Active mouse tracking mode (xterm DECSET): 0 = off, 1000 = normal,
|
|
156
|
-
* 1002 = button-event, 1003 = any-event.
|
|
157
|
-
*/
|
|
158
|
-
export function getMouseMode(): number {
|
|
159
|
-
return mouseMode;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/** True when the server has DEC 1006 (SGR mouse encoding) enabled. */
|
|
163
|
-
export function isMouseSGR(): boolean {
|
|
164
|
-
return mouseSGR;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/** True when the server has DEC 1016 (SGR-pixels mouse) enabled: mouse reports
|
|
168
|
-
* carry pixel coordinates instead of cell coordinates. */
|
|
169
|
-
export function isMousePixels(): boolean {
|
|
170
|
-
return mousePixels;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/** True when the server has DEC 1004 (focus event reporting) enabled. */
|
|
174
|
-
export function isFocusReporting(): boolean {
|
|
175
|
-
return focusReporting;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/** True when the server has DECKPAM (application keypad) enabled. */
|
|
179
|
-
export function isApplicationKeypad(): boolean {
|
|
180
|
-
return applicationKeypad;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/** True when the server has DEC 5 (reverse video / DECSCNM) enabled. */
|
|
184
|
-
export function isReverseVideo(): boolean {
|
|
185
|
-
return reverseVideo;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Kitty keyboard progressive-enhancement flags currently in effect (bit0
|
|
190
|
-
* disambiguate, bit1 report-event-types, bit2 report-alternate-keys). 0 means
|
|
191
|
-
* the protocol is disabled and keys use legacy encoding. Read by keyboard.ts to
|
|
192
|
-
* choose between legacy and kitty CSI-u encoding.
|
|
193
|
-
*/
|
|
194
|
-
export function getKeyboardFlags(): number {
|
|
195
|
-
return keyboardFlags;
|
|
196
|
-
}
|