@xterm/xterm 5.4.0-beta.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/LICENSE +21 -0
- package/README.md +235 -0
- package/css/xterm.css +209 -0
- package/lib/xterm.js +2 -0
- package/lib/xterm.js.map +1 -0
- package/package.json +101 -0
- package/src/browser/AccessibilityManager.ts +278 -0
- package/src/browser/Clipboard.ts +93 -0
- package/src/browser/ColorContrastCache.ts +34 -0
- package/src/browser/Lifecycle.ts +33 -0
- package/src/browser/Linkifier2.ts +416 -0
- package/src/browser/LocalizableStrings.ts +12 -0
- package/src/browser/OscLinkProvider.ts +128 -0
- package/src/browser/RenderDebouncer.ts +83 -0
- package/src/browser/Terminal.ts +1317 -0
- package/src/browser/TimeBasedDebouncer.ts +86 -0
- package/src/browser/Types.d.ts +181 -0
- package/src/browser/Viewport.ts +401 -0
- package/src/browser/decorations/BufferDecorationRenderer.ts +134 -0
- package/src/browser/decorations/ColorZoneStore.ts +117 -0
- package/src/browser/decorations/OverviewRulerRenderer.ts +218 -0
- package/src/browser/input/CompositionHelper.ts +246 -0
- package/src/browser/input/Mouse.ts +54 -0
- package/src/browser/input/MoveToCell.ts +249 -0
- package/src/browser/public/Terminal.ts +260 -0
- package/src/browser/renderer/dom/DomRenderer.ts +509 -0
- package/src/browser/renderer/dom/DomRendererRowFactory.ts +526 -0
- package/src/browser/renderer/dom/WidthCache.ts +160 -0
- package/src/browser/renderer/shared/CellColorResolver.ts +137 -0
- package/src/browser/renderer/shared/CharAtlasCache.ts +96 -0
- package/src/browser/renderer/shared/CharAtlasUtils.ts +75 -0
- package/src/browser/renderer/shared/Constants.ts +14 -0
- package/src/browser/renderer/shared/CursorBlinkStateManager.ts +146 -0
- package/src/browser/renderer/shared/CustomGlyphs.ts +687 -0
- package/src/browser/renderer/shared/DevicePixelObserver.ts +41 -0
- package/src/browser/renderer/shared/README.md +1 -0
- package/src/browser/renderer/shared/RendererUtils.ts +58 -0
- package/src/browser/renderer/shared/SelectionRenderModel.ts +91 -0
- package/src/browser/renderer/shared/TextureAtlas.ts +1082 -0
- package/src/browser/renderer/shared/Types.d.ts +173 -0
- package/src/browser/selection/SelectionModel.ts +144 -0
- package/src/browser/selection/Types.d.ts +15 -0
- package/src/browser/services/CharSizeService.ts +102 -0
- package/src/browser/services/CharacterJoinerService.ts +339 -0
- package/src/browser/services/CoreBrowserService.ts +137 -0
- package/src/browser/services/MouseService.ts +46 -0
- package/src/browser/services/RenderService.ts +279 -0
- package/src/browser/services/SelectionService.ts +1031 -0
- package/src/browser/services/Services.ts +147 -0
- package/src/browser/services/ThemeService.ts +237 -0
- package/src/common/CircularList.ts +241 -0
- package/src/common/Clone.ts +23 -0
- package/src/common/Color.ts +357 -0
- package/src/common/CoreTerminal.ts +284 -0
- package/src/common/EventEmitter.ts +78 -0
- package/src/common/InputHandler.ts +3461 -0
- package/src/common/Lifecycle.ts +108 -0
- package/src/common/MultiKeyMap.ts +42 -0
- package/src/common/Platform.ts +44 -0
- package/src/common/SortedList.ts +118 -0
- package/src/common/TaskQueue.ts +166 -0
- package/src/common/TypedArrayUtils.ts +17 -0
- package/src/common/Types.d.ts +553 -0
- package/src/common/WindowsMode.ts +27 -0
- package/src/common/buffer/AttributeData.ts +196 -0
- package/src/common/buffer/Buffer.ts +654 -0
- package/src/common/buffer/BufferLine.ts +524 -0
- package/src/common/buffer/BufferRange.ts +13 -0
- package/src/common/buffer/BufferReflow.ts +223 -0
- package/src/common/buffer/BufferSet.ts +134 -0
- package/src/common/buffer/CellData.ts +94 -0
- package/src/common/buffer/Constants.ts +149 -0
- package/src/common/buffer/Marker.ts +43 -0
- package/src/common/buffer/Types.d.ts +52 -0
- package/src/common/data/Charsets.ts +256 -0
- package/src/common/data/EscapeSequences.ts +153 -0
- package/src/common/input/Keyboard.ts +398 -0
- package/src/common/input/TextDecoder.ts +346 -0
- package/src/common/input/UnicodeV6.ts +145 -0
- package/src/common/input/WriteBuffer.ts +246 -0
- package/src/common/input/XParseColor.ts +80 -0
- package/src/common/parser/Constants.ts +58 -0
- package/src/common/parser/DcsParser.ts +192 -0
- package/src/common/parser/EscapeSequenceParser.ts +792 -0
- package/src/common/parser/OscParser.ts +238 -0
- package/src/common/parser/Params.ts +229 -0
- package/src/common/parser/Types.d.ts +275 -0
- package/src/common/public/AddonManager.ts +53 -0
- package/src/common/public/BufferApiView.ts +35 -0
- package/src/common/public/BufferLineApiView.ts +29 -0
- package/src/common/public/BufferNamespaceApi.ts +36 -0
- package/src/common/public/ParserApi.ts +37 -0
- package/src/common/public/UnicodeApi.ts +27 -0
- package/src/common/services/BufferService.ts +151 -0
- package/src/common/services/CharsetService.ts +34 -0
- package/src/common/services/CoreMouseService.ts +318 -0
- package/src/common/services/CoreService.ts +87 -0
- package/src/common/services/DecorationService.ts +140 -0
- package/src/common/services/InstantiationService.ts +85 -0
- package/src/common/services/LogService.ts +124 -0
- package/src/common/services/OptionsService.ts +202 -0
- package/src/common/services/OscLinkService.ts +115 -0
- package/src/common/services/ServiceRegistry.ts +49 -0
- package/src/common/services/Services.ts +373 -0
- package/src/common/services/UnicodeService.ts +111 -0
- package/src/headless/Terminal.ts +136 -0
- package/src/headless/public/Terminal.ts +195 -0
- package/typings/xterm.d.ts +1857 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
import { IBufferService, ICoreService, ICoreMouseService } from 'common/services/Services';
|
|
6
|
+
import { EventEmitter } from 'common/EventEmitter';
|
|
7
|
+
import { ICoreMouseProtocol, ICoreMouseEvent, CoreMouseEncoding, CoreMouseEventType, CoreMouseButton, CoreMouseAction } from 'common/Types';
|
|
8
|
+
import { Disposable } from 'common/Lifecycle';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Supported default protocols.
|
|
12
|
+
*/
|
|
13
|
+
const DEFAULT_PROTOCOLS: { [key: string]: ICoreMouseProtocol } = {
|
|
14
|
+
/**
|
|
15
|
+
* NONE
|
|
16
|
+
* Events: none
|
|
17
|
+
* Modifiers: none
|
|
18
|
+
*/
|
|
19
|
+
NONE: {
|
|
20
|
+
events: CoreMouseEventType.NONE,
|
|
21
|
+
restrict: () => false
|
|
22
|
+
},
|
|
23
|
+
/**
|
|
24
|
+
* X10
|
|
25
|
+
* Events: mousedown
|
|
26
|
+
* Modifiers: none
|
|
27
|
+
*/
|
|
28
|
+
X10: {
|
|
29
|
+
events: CoreMouseEventType.DOWN,
|
|
30
|
+
restrict: (e: ICoreMouseEvent) => {
|
|
31
|
+
// no wheel, no move, no up
|
|
32
|
+
if (e.button === CoreMouseButton.WHEEL || e.action !== CoreMouseAction.DOWN) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
// no modifiers
|
|
36
|
+
e.ctrl = false;
|
|
37
|
+
e.alt = false;
|
|
38
|
+
e.shift = false;
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
/**
|
|
43
|
+
* VT200
|
|
44
|
+
* Events: mousedown / mouseup / wheel
|
|
45
|
+
* Modifiers: all
|
|
46
|
+
*/
|
|
47
|
+
VT200: {
|
|
48
|
+
events: CoreMouseEventType.DOWN | CoreMouseEventType.UP | CoreMouseEventType.WHEEL,
|
|
49
|
+
restrict: (e: ICoreMouseEvent) => {
|
|
50
|
+
// no move
|
|
51
|
+
if (e.action === CoreMouseAction.MOVE) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
/**
|
|
58
|
+
* DRAG
|
|
59
|
+
* Events: mousedown / mouseup / wheel / mousedrag
|
|
60
|
+
* Modifiers: all
|
|
61
|
+
*/
|
|
62
|
+
DRAG: {
|
|
63
|
+
events: CoreMouseEventType.DOWN | CoreMouseEventType.UP | CoreMouseEventType.WHEEL | CoreMouseEventType.DRAG,
|
|
64
|
+
restrict: (e: ICoreMouseEvent) => {
|
|
65
|
+
// no move without button
|
|
66
|
+
if (e.action === CoreMouseAction.MOVE && e.button === CoreMouseButton.NONE) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
/**
|
|
73
|
+
* ANY
|
|
74
|
+
* Events: all mouse related events
|
|
75
|
+
* Modifiers: all
|
|
76
|
+
*/
|
|
77
|
+
ANY: {
|
|
78
|
+
events:
|
|
79
|
+
CoreMouseEventType.DOWN | CoreMouseEventType.UP | CoreMouseEventType.WHEEL
|
|
80
|
+
| CoreMouseEventType.DRAG | CoreMouseEventType.MOVE,
|
|
81
|
+
restrict: (e: ICoreMouseEvent) => true
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const enum Modifiers {
|
|
86
|
+
SHIFT = 4,
|
|
87
|
+
ALT = 8,
|
|
88
|
+
CTRL = 16
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// helper for default encoders to generate the event code.
|
|
92
|
+
function eventCode(e: ICoreMouseEvent, isSGR: boolean): number {
|
|
93
|
+
let code = (e.ctrl ? Modifiers.CTRL : 0) | (e.shift ? Modifiers.SHIFT : 0) | (e.alt ? Modifiers.ALT : 0);
|
|
94
|
+
if (e.button === CoreMouseButton.WHEEL) {
|
|
95
|
+
code |= 64;
|
|
96
|
+
code |= e.action;
|
|
97
|
+
} else {
|
|
98
|
+
code |= e.button & 3;
|
|
99
|
+
if (e.button & 4) {
|
|
100
|
+
code |= 64;
|
|
101
|
+
}
|
|
102
|
+
if (e.button & 8) {
|
|
103
|
+
code |= 128;
|
|
104
|
+
}
|
|
105
|
+
if (e.action === CoreMouseAction.MOVE) {
|
|
106
|
+
code |= CoreMouseAction.MOVE;
|
|
107
|
+
} else if (e.action === CoreMouseAction.UP && !isSGR) {
|
|
108
|
+
// special case - only SGR can report button on release
|
|
109
|
+
// all others have to go with NONE
|
|
110
|
+
code |= CoreMouseButton.NONE;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return code;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const S = String.fromCharCode;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Supported default encodings.
|
|
120
|
+
*/
|
|
121
|
+
const DEFAULT_ENCODINGS: { [key: string]: CoreMouseEncoding } = {
|
|
122
|
+
/**
|
|
123
|
+
* DEFAULT - CSI M Pb Px Py
|
|
124
|
+
* Single byte encoding for coords and event code.
|
|
125
|
+
* Can encode values up to 223 (1-based).
|
|
126
|
+
*/
|
|
127
|
+
DEFAULT: (e: ICoreMouseEvent) => {
|
|
128
|
+
const params = [eventCode(e, false) + 32, e.col + 32, e.row + 32];
|
|
129
|
+
// supress mouse report if we exceed addressible range
|
|
130
|
+
// Note this is handled differently by emulators
|
|
131
|
+
// - xterm: sends 0;0 coords instead
|
|
132
|
+
// - vte, konsole: no report
|
|
133
|
+
if (params[0] > 255 || params[1] > 255 || params[2] > 255) {
|
|
134
|
+
return '';
|
|
135
|
+
}
|
|
136
|
+
return `\x1b[M${S(params[0])}${S(params[1])}${S(params[2])}`;
|
|
137
|
+
},
|
|
138
|
+
/**
|
|
139
|
+
* SGR - CSI < Pb ; Px ; Py M|m
|
|
140
|
+
* No encoding limitation.
|
|
141
|
+
* Can report button on release and works with a well formed sequence.
|
|
142
|
+
*/
|
|
143
|
+
SGR: (e: ICoreMouseEvent) => {
|
|
144
|
+
const final = (e.action === CoreMouseAction.UP && e.button !== CoreMouseButton.WHEEL) ? 'm' : 'M';
|
|
145
|
+
return `\x1b[<${eventCode(e, true)};${e.col};${e.row}${final}`;
|
|
146
|
+
},
|
|
147
|
+
SGR_PIXELS: (e: ICoreMouseEvent) => {
|
|
148
|
+
const final = (e.action === CoreMouseAction.UP && e.button !== CoreMouseButton.WHEEL) ? 'm' : 'M';
|
|
149
|
+
return `\x1b[<${eventCode(e, true)};${e.x};${e.y}${final}`;
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* CoreMouseService
|
|
155
|
+
*
|
|
156
|
+
* Provides mouse tracking reports with different protocols and encodings.
|
|
157
|
+
* - protocols: NONE (default), X10, VT200, DRAG, ANY
|
|
158
|
+
* - encodings: DEFAULT, SGR (UTF8, URXVT removed in #2507)
|
|
159
|
+
*
|
|
160
|
+
* Custom protocols/encodings can be added by `addProtocol` / `addEncoding`.
|
|
161
|
+
* To activate a protocol/encoding, set `activeProtocol` / `activeEncoding`.
|
|
162
|
+
* Switching a protocol will send a notification event `onProtocolChange`
|
|
163
|
+
* with a list of needed events to track.
|
|
164
|
+
*
|
|
165
|
+
* The service handles the mouse tracking state and decides whether to send
|
|
166
|
+
* a tracking report to the backend based on protocol and encoding limitations.
|
|
167
|
+
* To send a mouse event call `triggerMouseEvent`.
|
|
168
|
+
*/
|
|
169
|
+
export class CoreMouseService extends Disposable implements ICoreMouseService {
|
|
170
|
+
private _protocols: { [name: string]: ICoreMouseProtocol } = {};
|
|
171
|
+
private _encodings: { [name: string]: CoreMouseEncoding } = {};
|
|
172
|
+
private _activeProtocol: string = '';
|
|
173
|
+
private _activeEncoding: string = '';
|
|
174
|
+
private _lastEvent: ICoreMouseEvent | null = null;
|
|
175
|
+
|
|
176
|
+
private readonly _onProtocolChange = this.register(new EventEmitter<CoreMouseEventType>());
|
|
177
|
+
public readonly onProtocolChange = this._onProtocolChange.event;
|
|
178
|
+
|
|
179
|
+
constructor(
|
|
180
|
+
@IBufferService private readonly _bufferService: IBufferService,
|
|
181
|
+
@ICoreService private readonly _coreService: ICoreService
|
|
182
|
+
) {
|
|
183
|
+
super();
|
|
184
|
+
// register default protocols and encodings
|
|
185
|
+
for (const name of Object.keys(DEFAULT_PROTOCOLS)) this.addProtocol(name, DEFAULT_PROTOCOLS[name]);
|
|
186
|
+
for (const name of Object.keys(DEFAULT_ENCODINGS)) this.addEncoding(name, DEFAULT_ENCODINGS[name]);
|
|
187
|
+
// call reset to set defaults
|
|
188
|
+
this.reset();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
public addProtocol(name: string, protocol: ICoreMouseProtocol): void {
|
|
192
|
+
this._protocols[name] = protocol;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
public addEncoding(name: string, encoding: CoreMouseEncoding): void {
|
|
196
|
+
this._encodings[name] = encoding;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
public get activeProtocol(): string {
|
|
200
|
+
return this._activeProtocol;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
public get areMouseEventsActive(): boolean {
|
|
204
|
+
return this._protocols[this._activeProtocol].events !== 0;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
public set activeProtocol(name: string) {
|
|
208
|
+
if (!this._protocols[name]) {
|
|
209
|
+
throw new Error(`unknown protocol "${name}"`);
|
|
210
|
+
}
|
|
211
|
+
this._activeProtocol = name;
|
|
212
|
+
this._onProtocolChange.fire(this._protocols[name].events);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
public get activeEncoding(): string {
|
|
216
|
+
return this._activeEncoding;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public set activeEncoding(name: string) {
|
|
220
|
+
if (!this._encodings[name]) {
|
|
221
|
+
throw new Error(`unknown encoding "${name}"`);
|
|
222
|
+
}
|
|
223
|
+
this._activeEncoding = name;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
public reset(): void {
|
|
227
|
+
this.activeProtocol = 'NONE';
|
|
228
|
+
this.activeEncoding = 'DEFAULT';
|
|
229
|
+
this._lastEvent = null;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Triggers a mouse event to be sent.
|
|
234
|
+
*
|
|
235
|
+
* Returns true if the event passed all protocol restrictions and a report
|
|
236
|
+
* was sent, otherwise false. The return value may be used to decide whether
|
|
237
|
+
* the default event action in the bowser component should be omitted.
|
|
238
|
+
*
|
|
239
|
+
* Note: The method will change values of the given event object
|
|
240
|
+
* to fullfill protocol and encoding restrictions.
|
|
241
|
+
*/
|
|
242
|
+
public triggerMouseEvent(e: ICoreMouseEvent): boolean {
|
|
243
|
+
// range check for col/row
|
|
244
|
+
if (e.col < 0 || e.col >= this._bufferService.cols
|
|
245
|
+
|| e.row < 0 || e.row >= this._bufferService.rows) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// filter nonsense combinations of button + action
|
|
250
|
+
if (e.button === CoreMouseButton.WHEEL && e.action === CoreMouseAction.MOVE) {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
if (e.button === CoreMouseButton.NONE && e.action !== CoreMouseAction.MOVE) {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
if (e.button !== CoreMouseButton.WHEEL && (e.action === CoreMouseAction.LEFT || e.action === CoreMouseAction.RIGHT)) {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// report 1-based coords
|
|
261
|
+
e.col++;
|
|
262
|
+
e.row++;
|
|
263
|
+
|
|
264
|
+
// debounce move events at grid or pixel level
|
|
265
|
+
if (e.action === CoreMouseAction.MOVE
|
|
266
|
+
&& this._lastEvent
|
|
267
|
+
&& this._equalEvents(this._lastEvent, e, this._activeEncoding === 'SGR_PIXELS')
|
|
268
|
+
) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// apply protocol restrictions
|
|
273
|
+
if (!this._protocols[this._activeProtocol].restrict(e)) {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// encode report and send
|
|
278
|
+
const report = this._encodings[this._activeEncoding](e);
|
|
279
|
+
if (report) {
|
|
280
|
+
// always send DEFAULT as binary data
|
|
281
|
+
if (this._activeEncoding === 'DEFAULT') {
|
|
282
|
+
this._coreService.triggerBinaryEvent(report);
|
|
283
|
+
} else {
|
|
284
|
+
this._coreService.triggerDataEvent(report, true);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
this._lastEvent = e;
|
|
289
|
+
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
public explainEvents(events: CoreMouseEventType): { [event: string]: boolean } {
|
|
294
|
+
return {
|
|
295
|
+
down: !!(events & CoreMouseEventType.DOWN),
|
|
296
|
+
up: !!(events & CoreMouseEventType.UP),
|
|
297
|
+
drag: !!(events & CoreMouseEventType.DRAG),
|
|
298
|
+
move: !!(events & CoreMouseEventType.MOVE),
|
|
299
|
+
wheel: !!(events & CoreMouseEventType.WHEEL)
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
private _equalEvents(e1: ICoreMouseEvent, e2: ICoreMouseEvent, pixels: boolean): boolean {
|
|
304
|
+
if (pixels) {
|
|
305
|
+
if (e1.x !== e2.x) return false;
|
|
306
|
+
if (e1.y !== e2.y) return false;
|
|
307
|
+
} else {
|
|
308
|
+
if (e1.col !== e2.col) return false;
|
|
309
|
+
if (e1.row !== e2.row) return false;
|
|
310
|
+
}
|
|
311
|
+
if (e1.button !== e2.button) return false;
|
|
312
|
+
if (e1.action !== e2.action) return false;
|
|
313
|
+
if (e1.ctrl !== e2.ctrl) return false;
|
|
314
|
+
if (e1.alt !== e2.alt) return false;
|
|
315
|
+
if (e1.shift !== e2.shift) return false;
|
|
316
|
+
return true;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { clone } from 'common/Clone';
|
|
7
|
+
import { EventEmitter } from 'common/EventEmitter';
|
|
8
|
+
import { Disposable } from 'common/Lifecycle';
|
|
9
|
+
import { IDecPrivateModes, IModes } from 'common/Types';
|
|
10
|
+
import { IBufferService, ICoreService, ILogService, IOptionsService } from 'common/services/Services';
|
|
11
|
+
|
|
12
|
+
const DEFAULT_MODES: IModes = Object.freeze({
|
|
13
|
+
insertMode: false
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const DEFAULT_DEC_PRIVATE_MODES: IDecPrivateModes = Object.freeze({
|
|
17
|
+
applicationCursorKeys: false,
|
|
18
|
+
applicationKeypad: false,
|
|
19
|
+
bracketedPasteMode: false,
|
|
20
|
+
origin: false,
|
|
21
|
+
reverseWraparound: false,
|
|
22
|
+
sendFocus: false,
|
|
23
|
+
wraparound: true // defaults: xterm - true, vt100 - false
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export class CoreService extends Disposable implements ICoreService {
|
|
27
|
+
public serviceBrand: any;
|
|
28
|
+
|
|
29
|
+
public isCursorInitialized: boolean = false;
|
|
30
|
+
public isCursorHidden: boolean = false;
|
|
31
|
+
public modes: IModes;
|
|
32
|
+
public decPrivateModes: IDecPrivateModes;
|
|
33
|
+
|
|
34
|
+
private readonly _onData = this.register(new EventEmitter<string>());
|
|
35
|
+
public readonly onData = this._onData.event;
|
|
36
|
+
private readonly _onUserInput = this.register(new EventEmitter<void>());
|
|
37
|
+
public readonly onUserInput = this._onUserInput.event;
|
|
38
|
+
private readonly _onBinary = this.register(new EventEmitter<string>());
|
|
39
|
+
public readonly onBinary = this._onBinary.event;
|
|
40
|
+
private readonly _onRequestScrollToBottom = this.register(new EventEmitter<void>());
|
|
41
|
+
public readonly onRequestScrollToBottom = this._onRequestScrollToBottom.event;
|
|
42
|
+
|
|
43
|
+
constructor(
|
|
44
|
+
@IBufferService private readonly _bufferService: IBufferService,
|
|
45
|
+
@ILogService private readonly _logService: ILogService,
|
|
46
|
+
@IOptionsService private readonly _optionsService: IOptionsService
|
|
47
|
+
) {
|
|
48
|
+
super();
|
|
49
|
+
this.modes = clone(DEFAULT_MODES);
|
|
50
|
+
this.decPrivateModes = clone(DEFAULT_DEC_PRIVATE_MODES);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public reset(): void {
|
|
54
|
+
this.modes = clone(DEFAULT_MODES);
|
|
55
|
+
this.decPrivateModes = clone(DEFAULT_DEC_PRIVATE_MODES);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public triggerDataEvent(data: string, wasUserInput: boolean = false): void {
|
|
59
|
+
// Prevents all events to pty process if stdin is disabled
|
|
60
|
+
if (this._optionsService.rawOptions.disableStdin) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Input is being sent to the terminal, the terminal should focus the prompt.
|
|
65
|
+
const buffer = this._bufferService.buffer;
|
|
66
|
+
if (wasUserInput && this._optionsService.rawOptions.scrollOnUserInput && buffer.ybase !== buffer.ydisp) {
|
|
67
|
+
this._onRequestScrollToBottom.fire();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Fire onUserInput so listeners can react as well (eg. clear selection)
|
|
71
|
+
if (wasUserInput) {
|
|
72
|
+
this._onUserInput.fire();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Fire onData API
|
|
76
|
+
this._logService.debug(`sending data "${data}"`, () => data.split('').map(e => e.charCodeAt(0)));
|
|
77
|
+
this._onData.fire(data);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public triggerBinaryEvent(data: string): void {
|
|
81
|
+
if (this._optionsService.rawOptions.disableStdin) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
this._logService.debug(`sending binary "${data}"`, () => data.split('').map(e => e.charCodeAt(0)));
|
|
85
|
+
this._onBinary.fire(data);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2022 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { css } from 'common/Color';
|
|
7
|
+
import { EventEmitter } from 'common/EventEmitter';
|
|
8
|
+
import { Disposable, toDisposable } from 'common/Lifecycle';
|
|
9
|
+
import { IDecorationService, IInternalDecoration } from 'common/services/Services';
|
|
10
|
+
import { SortedList } from 'common/SortedList';
|
|
11
|
+
import { IColor } from 'common/Types';
|
|
12
|
+
import { IDecoration, IDecorationOptions, IMarker } from '@xterm/xterm';
|
|
13
|
+
|
|
14
|
+
// Work variables to avoid garbage collection
|
|
15
|
+
let $xmin = 0;
|
|
16
|
+
let $xmax = 0;
|
|
17
|
+
|
|
18
|
+
export class DecorationService extends Disposable implements IDecorationService {
|
|
19
|
+
public serviceBrand: any;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A list of all decorations, sorted by the marker's line value. This relies on the fact that
|
|
23
|
+
* while marker line values do change, they should all change by the same amount so this should
|
|
24
|
+
* never become out of order.
|
|
25
|
+
*/
|
|
26
|
+
private readonly _decorations: SortedList<IInternalDecoration> = new SortedList(e => e?.marker.line);
|
|
27
|
+
|
|
28
|
+
private readonly _onDecorationRegistered = this.register(new EventEmitter<IInternalDecoration>());
|
|
29
|
+
public readonly onDecorationRegistered = this._onDecorationRegistered.event;
|
|
30
|
+
private readonly _onDecorationRemoved = this.register(new EventEmitter<IInternalDecoration>());
|
|
31
|
+
public readonly onDecorationRemoved = this._onDecorationRemoved.event;
|
|
32
|
+
|
|
33
|
+
public get decorations(): IterableIterator<IInternalDecoration> { return this._decorations.values(); }
|
|
34
|
+
|
|
35
|
+
constructor() {
|
|
36
|
+
super();
|
|
37
|
+
|
|
38
|
+
this.register(toDisposable(() => this.reset()));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public registerDecoration(options: IDecorationOptions): IDecoration | undefined {
|
|
42
|
+
if (options.marker.isDisposed) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
const decoration = new Decoration(options);
|
|
46
|
+
if (decoration) {
|
|
47
|
+
const markerDispose = decoration.marker.onDispose(() => decoration.dispose());
|
|
48
|
+
decoration.onDispose(() => {
|
|
49
|
+
if (decoration) {
|
|
50
|
+
if (this._decorations.delete(decoration)) {
|
|
51
|
+
this._onDecorationRemoved.fire(decoration);
|
|
52
|
+
}
|
|
53
|
+
markerDispose.dispose();
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
this._decorations.insert(decoration);
|
|
57
|
+
this._onDecorationRegistered.fire(decoration);
|
|
58
|
+
}
|
|
59
|
+
return decoration;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public reset(): void {
|
|
63
|
+
for (const d of this._decorations.values()) {
|
|
64
|
+
d.dispose();
|
|
65
|
+
}
|
|
66
|
+
this._decorations.clear();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public *getDecorationsAtCell(x: number, line: number, layer?: 'bottom' | 'top'): IterableIterator<IInternalDecoration> {
|
|
70
|
+
let xmin = 0;
|
|
71
|
+
let xmax = 0;
|
|
72
|
+
for (const d of this._decorations.getKeyIterator(line)) {
|
|
73
|
+
xmin = d.options.x ?? 0;
|
|
74
|
+
xmax = xmin + (d.options.width ?? 1);
|
|
75
|
+
if (x >= xmin && x < xmax && (!layer || (d.options.layer ?? 'bottom') === layer)) {
|
|
76
|
+
yield d;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public forEachDecorationAtCell(x: number, line: number, layer: 'bottom' | 'top' | undefined, callback: (decoration: IInternalDecoration) => void): void {
|
|
82
|
+
this._decorations.forEachByKey(line, d => {
|
|
83
|
+
$xmin = d.options.x ?? 0;
|
|
84
|
+
$xmax = $xmin + (d.options.width ?? 1);
|
|
85
|
+
if (x >= $xmin && x < $xmax && (!layer || (d.options.layer ?? 'bottom') === layer)) {
|
|
86
|
+
callback(d);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
class Decoration extends Disposable implements IInternalDecoration {
|
|
93
|
+
public readonly marker: IMarker;
|
|
94
|
+
public element: HTMLElement | undefined;
|
|
95
|
+
public get isDisposed(): boolean { return this._isDisposed; }
|
|
96
|
+
|
|
97
|
+
public readonly onRenderEmitter = this.register(new EventEmitter<HTMLElement>());
|
|
98
|
+
public readonly onRender = this.onRenderEmitter.event;
|
|
99
|
+
private readonly _onDispose = this.register(new EventEmitter<void>());
|
|
100
|
+
public readonly onDispose = this._onDispose.event;
|
|
101
|
+
|
|
102
|
+
private _cachedBg: IColor | undefined | null = null;
|
|
103
|
+
public get backgroundColorRGB(): IColor | undefined {
|
|
104
|
+
if (this._cachedBg === null) {
|
|
105
|
+
if (this.options.backgroundColor) {
|
|
106
|
+
this._cachedBg = css.toColor(this.options.backgroundColor);
|
|
107
|
+
} else {
|
|
108
|
+
this._cachedBg = undefined;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return this._cachedBg;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private _cachedFg: IColor | undefined | null = null;
|
|
115
|
+
public get foregroundColorRGB(): IColor | undefined {
|
|
116
|
+
if (this._cachedFg === null) {
|
|
117
|
+
if (this.options.foregroundColor) {
|
|
118
|
+
this._cachedFg = css.toColor(this.options.foregroundColor);
|
|
119
|
+
} else {
|
|
120
|
+
this._cachedFg = undefined;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return this._cachedFg;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
constructor(
|
|
127
|
+
public readonly options: IDecorationOptions
|
|
128
|
+
) {
|
|
129
|
+
super();
|
|
130
|
+
this.marker = options.marker;
|
|
131
|
+
if (this.options.overviewRulerOptions && !this.options.overviewRulerOptions.position) {
|
|
132
|
+
this.options.overviewRulerOptions.position = 'full';
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public override dispose(): void {
|
|
137
|
+
this._onDispose.fire();
|
|
138
|
+
super.dispose();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*
|
|
5
|
+
* This was heavily inspired from microsoft/vscode's dependency injection system (MIT).
|
|
6
|
+
*/
|
|
7
|
+
/*---------------------------------------------------------------------------------------------
|
|
8
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
9
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
10
|
+
*--------------------------------------------------------------------------------------------*/
|
|
11
|
+
|
|
12
|
+
import { IInstantiationService, IServiceIdentifier } from 'common/services/Services';
|
|
13
|
+
import { getServiceDependencies } from 'common/services/ServiceRegistry';
|
|
14
|
+
|
|
15
|
+
export class ServiceCollection {
|
|
16
|
+
|
|
17
|
+
private _entries = new Map<IServiceIdentifier<any>, any>();
|
|
18
|
+
|
|
19
|
+
constructor(...entries: [IServiceIdentifier<any>, any][]) {
|
|
20
|
+
for (const [id, service] of entries) {
|
|
21
|
+
this.set(id, service);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public set<T>(id: IServiceIdentifier<T>, instance: T): T {
|
|
26
|
+
const result = this._entries.get(id);
|
|
27
|
+
this._entries.set(id, instance);
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public forEach(callback: (id: IServiceIdentifier<any>, instance: any) => any): void {
|
|
32
|
+
for (const [key, value] of this._entries.entries()) {
|
|
33
|
+
callback(key, value);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public has(id: IServiceIdentifier<any>): boolean {
|
|
38
|
+
return this._entries.has(id);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public get<T>(id: IServiceIdentifier<T>): T | undefined {
|
|
42
|
+
return this._entries.get(id);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class InstantiationService implements IInstantiationService {
|
|
47
|
+
public serviceBrand: undefined;
|
|
48
|
+
|
|
49
|
+
private readonly _services: ServiceCollection = new ServiceCollection();
|
|
50
|
+
|
|
51
|
+
constructor() {
|
|
52
|
+
this._services.set(IInstantiationService, this);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public setService<T>(id: IServiceIdentifier<T>, instance: T): void {
|
|
56
|
+
this._services.set(id, instance);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public getService<T>(id: IServiceIdentifier<T>): T | undefined {
|
|
60
|
+
return this._services.get(id);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public createInstance<T>(ctor: any, ...args: any[]): T {
|
|
64
|
+
const serviceDependencies = getServiceDependencies(ctor).sort((a, b) => a.index - b.index);
|
|
65
|
+
|
|
66
|
+
const serviceArgs: any[] = [];
|
|
67
|
+
for (const dependency of serviceDependencies) {
|
|
68
|
+
const service = this._services.get(dependency.id);
|
|
69
|
+
if (!service) {
|
|
70
|
+
throw new Error(`[createInstance] ${ctor.name} depends on UNKNOWN service ${dependency.id}.`);
|
|
71
|
+
}
|
|
72
|
+
serviceArgs.push(service);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const firstServiceArgPos = serviceDependencies.length > 0 ? serviceDependencies[0].index : args.length;
|
|
76
|
+
|
|
77
|
+
// check for argument mismatches, adjust static args if needed
|
|
78
|
+
if (args.length !== firstServiceArgPos) {
|
|
79
|
+
throw new Error(`[createInstance] First service dependency of ${ctor.name} at position ${firstServiceArgPos + 1} conflicts with ${args.length} static arguments`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// now create the instance
|
|
83
|
+
return new ctor(...[...args, ...serviceArgs]);
|
|
84
|
+
}
|
|
85
|
+
}
|