@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,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { RenderDebouncer } from 'browser/RenderDebouncer';
|
|
7
|
+
import { IRenderDebouncerWithCallback } from 'browser/Types';
|
|
8
|
+
import { IRenderDimensions, IRenderer } from 'browser/renderer/shared/Types';
|
|
9
|
+
import { ICharSizeService, ICoreBrowserService, IRenderService, IThemeService } from 'browser/services/Services';
|
|
10
|
+
import { EventEmitter } from 'common/EventEmitter';
|
|
11
|
+
import { Disposable, MutableDisposable } from 'common/Lifecycle';
|
|
12
|
+
import { DebouncedIdleTask } from 'common/TaskQueue';
|
|
13
|
+
import { IBufferService, IDecorationService, IInstantiationService, IOptionsService } from 'common/services/Services';
|
|
14
|
+
|
|
15
|
+
interface ISelectionState {
|
|
16
|
+
start: [number, number] | undefined;
|
|
17
|
+
end: [number, number] | undefined;
|
|
18
|
+
columnSelectMode: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class RenderService extends Disposable implements IRenderService {
|
|
22
|
+
public serviceBrand: undefined;
|
|
23
|
+
|
|
24
|
+
private _renderer: MutableDisposable<IRenderer> = this.register(new MutableDisposable());
|
|
25
|
+
private _renderDebouncer: IRenderDebouncerWithCallback;
|
|
26
|
+
private _pausedResizeTask = new DebouncedIdleTask();
|
|
27
|
+
|
|
28
|
+
private _isPaused: boolean = false;
|
|
29
|
+
private _needsFullRefresh: boolean = false;
|
|
30
|
+
private _isNextRenderRedrawOnly: boolean = true;
|
|
31
|
+
private _needsSelectionRefresh: boolean = false;
|
|
32
|
+
private _canvasWidth: number = 0;
|
|
33
|
+
private _canvasHeight: number = 0;
|
|
34
|
+
private _selectionState: ISelectionState = {
|
|
35
|
+
start: undefined,
|
|
36
|
+
end: undefined,
|
|
37
|
+
columnSelectMode: false
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
private readonly _onDimensionsChange = this.register(new EventEmitter<IRenderDimensions>());
|
|
41
|
+
public readonly onDimensionsChange = this._onDimensionsChange.event;
|
|
42
|
+
private readonly _onRenderedViewportChange = this.register(new EventEmitter<{ start: number, end: number }>());
|
|
43
|
+
public readonly onRenderedViewportChange = this._onRenderedViewportChange.event;
|
|
44
|
+
private readonly _onRender = this.register(new EventEmitter<{ start: number, end: number }>());
|
|
45
|
+
public readonly onRender = this._onRender.event;
|
|
46
|
+
private readonly _onRefreshRequest = this.register(new EventEmitter<{ start: number, end: number }>());
|
|
47
|
+
public readonly onRefreshRequest = this._onRefreshRequest.event;
|
|
48
|
+
|
|
49
|
+
public get dimensions(): IRenderDimensions { return this._renderer.value!.dimensions; }
|
|
50
|
+
|
|
51
|
+
constructor(
|
|
52
|
+
private _rowCount: number,
|
|
53
|
+
screenElement: HTMLElement,
|
|
54
|
+
@IOptionsService optionsService: IOptionsService,
|
|
55
|
+
@ICharSizeService private readonly _charSizeService: ICharSizeService,
|
|
56
|
+
@IDecorationService decorationService: IDecorationService,
|
|
57
|
+
@IBufferService bufferService: IBufferService,
|
|
58
|
+
@ICoreBrowserService coreBrowserService: ICoreBrowserService,
|
|
59
|
+
@IInstantiationService instantiationService: IInstantiationService,
|
|
60
|
+
@IThemeService themeService: IThemeService
|
|
61
|
+
) {
|
|
62
|
+
super();
|
|
63
|
+
|
|
64
|
+
this._renderDebouncer = new RenderDebouncer(coreBrowserService.window, (start, end) => this._renderRows(start, end));
|
|
65
|
+
this.register(this._renderDebouncer);
|
|
66
|
+
|
|
67
|
+
this.register(coreBrowserService.onDprChange(() => this.handleDevicePixelRatioChange()));
|
|
68
|
+
|
|
69
|
+
this.register(bufferService.onResize(() => this._fullRefresh()));
|
|
70
|
+
this.register(bufferService.buffers.onBufferActivate(() => this._renderer.value?.clear()));
|
|
71
|
+
this.register(optionsService.onOptionChange(() => this._handleOptionsChanged()));
|
|
72
|
+
this.register(this._charSizeService.onCharSizeChange(() => this.handleCharSizeChanged()));
|
|
73
|
+
|
|
74
|
+
// Do a full refresh whenever any decoration is added or removed. This may not actually result
|
|
75
|
+
// in changes but since decorations should be used sparingly or added/removed all in the same
|
|
76
|
+
// frame this should have minimal performance impact.
|
|
77
|
+
this.register(decorationService.onDecorationRegistered(() => this._fullRefresh()));
|
|
78
|
+
this.register(decorationService.onDecorationRemoved(() => this._fullRefresh()));
|
|
79
|
+
|
|
80
|
+
// Clear the renderer when the a change that could affect glyphs occurs
|
|
81
|
+
this.register(optionsService.onMultipleOptionChange([
|
|
82
|
+
'customGlyphs',
|
|
83
|
+
'drawBoldTextInBrightColors',
|
|
84
|
+
'letterSpacing',
|
|
85
|
+
'lineHeight',
|
|
86
|
+
'fontFamily',
|
|
87
|
+
'fontSize',
|
|
88
|
+
'fontWeight',
|
|
89
|
+
'fontWeightBold',
|
|
90
|
+
'minimumContrastRatio'
|
|
91
|
+
], () => {
|
|
92
|
+
this.clear();
|
|
93
|
+
this.handleResize(bufferService.cols, bufferService.rows);
|
|
94
|
+
this._fullRefresh();
|
|
95
|
+
}));
|
|
96
|
+
|
|
97
|
+
// Refresh the cursor line when the cursor changes
|
|
98
|
+
this.register(optionsService.onMultipleOptionChange([
|
|
99
|
+
'cursorBlink',
|
|
100
|
+
'cursorStyle'
|
|
101
|
+
], () => this.refreshRows(bufferService.buffer.y, bufferService.buffer.y, true)));
|
|
102
|
+
|
|
103
|
+
this.register(themeService.onChangeColors(() => this._fullRefresh()));
|
|
104
|
+
|
|
105
|
+
// Detect whether IntersectionObserver is detected and enable renderer pause
|
|
106
|
+
// and resume based on terminal visibility if so
|
|
107
|
+
if ('IntersectionObserver' in coreBrowserService.window) {
|
|
108
|
+
const observer = new coreBrowserService.window.IntersectionObserver(e => this._handleIntersectionChange(e[e.length - 1]), { threshold: 0 });
|
|
109
|
+
observer.observe(screenElement);
|
|
110
|
+
this.register({ dispose: () => observer.disconnect() });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private _handleIntersectionChange(entry: IntersectionObserverEntry): void {
|
|
115
|
+
this._isPaused = entry.isIntersecting === undefined ? (entry.intersectionRatio === 0) : !entry.isIntersecting;
|
|
116
|
+
|
|
117
|
+
// Terminal was hidden on open
|
|
118
|
+
if (!this._isPaused && !this._charSizeService.hasValidSize) {
|
|
119
|
+
this._charSizeService.measure();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!this._isPaused && this._needsFullRefresh) {
|
|
123
|
+
this._pausedResizeTask.flush();
|
|
124
|
+
this.refreshRows(0, this._rowCount - 1);
|
|
125
|
+
this._needsFullRefresh = false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public refreshRows(start: number, end: number, isRedrawOnly: boolean = false): void {
|
|
130
|
+
if (this._isPaused) {
|
|
131
|
+
this._needsFullRefresh = true;
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (!isRedrawOnly) {
|
|
135
|
+
this._isNextRenderRedrawOnly = false;
|
|
136
|
+
}
|
|
137
|
+
this._renderDebouncer.refresh(start, end, this._rowCount);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private _renderRows(start: number, end: number): void {
|
|
141
|
+
if (!this._renderer.value) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Since this is debounced, a resize event could have happened between the time a refresh was
|
|
146
|
+
// requested and when this triggers. Clamp the values of start and end to ensure they're valid
|
|
147
|
+
// given the current viewport state.
|
|
148
|
+
start = Math.min(start, this._rowCount - 1);
|
|
149
|
+
end = Math.min(end, this._rowCount - 1);
|
|
150
|
+
|
|
151
|
+
// Render
|
|
152
|
+
this._renderer.value.renderRows(start, end);
|
|
153
|
+
|
|
154
|
+
// Update selection if needed
|
|
155
|
+
if (this._needsSelectionRefresh) {
|
|
156
|
+
this._renderer.value.handleSelectionChanged(this._selectionState.start, this._selectionState.end, this._selectionState.columnSelectMode);
|
|
157
|
+
this._needsSelectionRefresh = false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Fire render event only if it was not a redraw
|
|
161
|
+
if (!this._isNextRenderRedrawOnly) {
|
|
162
|
+
this._onRenderedViewportChange.fire({ start, end });
|
|
163
|
+
}
|
|
164
|
+
this._onRender.fire({ start, end });
|
|
165
|
+
this._isNextRenderRedrawOnly = true;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
public resize(cols: number, rows: number): void {
|
|
169
|
+
this._rowCount = rows;
|
|
170
|
+
this._fireOnCanvasResize();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private _handleOptionsChanged(): void {
|
|
174
|
+
if (!this._renderer.value) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
this.refreshRows(0, this._rowCount - 1);
|
|
178
|
+
this._fireOnCanvasResize();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private _fireOnCanvasResize(): void {
|
|
182
|
+
if (!this._renderer.value) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
// Don't fire the event if the dimensions haven't changed
|
|
186
|
+
if (this._renderer.value.dimensions.css.canvas.width === this._canvasWidth && this._renderer.value.dimensions.css.canvas.height === this._canvasHeight) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
this._onDimensionsChange.fire(this._renderer.value.dimensions);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
public hasRenderer(): boolean {
|
|
193
|
+
return !!this._renderer.value;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
public setRenderer(renderer: IRenderer): void {
|
|
197
|
+
this._renderer.value = renderer;
|
|
198
|
+
// If the value was not set, the terminal is being disposed so ignore it
|
|
199
|
+
if (this._renderer.value) {
|
|
200
|
+
this._renderer.value.onRequestRedraw(e => this.refreshRows(e.start, e.end, true));
|
|
201
|
+
|
|
202
|
+
// Force a refresh
|
|
203
|
+
this._needsSelectionRefresh = true;
|
|
204
|
+
this._fullRefresh();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
public addRefreshCallback(callback: FrameRequestCallback): number {
|
|
209
|
+
return this._renderDebouncer.addRefreshCallback(callback);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
private _fullRefresh(): void {
|
|
213
|
+
if (this._isPaused) {
|
|
214
|
+
this._needsFullRefresh = true;
|
|
215
|
+
} else {
|
|
216
|
+
this.refreshRows(0, this._rowCount - 1);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
public clearTextureAtlas(): void {
|
|
221
|
+
if (!this._renderer.value) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
this._renderer.value.clearTextureAtlas?.();
|
|
225
|
+
this._fullRefresh();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
public handleDevicePixelRatioChange(): void {
|
|
229
|
+
// Force char size measurement as DomMeasureStrategy(getBoundingClientRect) is not stable
|
|
230
|
+
// when devicePixelRatio changes
|
|
231
|
+
this._charSizeService.measure();
|
|
232
|
+
|
|
233
|
+
if (!this._renderer.value) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
this._renderer.value.handleDevicePixelRatioChange();
|
|
237
|
+
this.refreshRows(0, this._rowCount - 1);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
public handleResize(cols: number, rows: number): void {
|
|
241
|
+
if (!this._renderer.value) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (this._isPaused) {
|
|
245
|
+
this._pausedResizeTask.set(() => this._renderer.value!.handleResize(cols, rows));
|
|
246
|
+
} else {
|
|
247
|
+
this._renderer.value.handleResize(cols, rows);
|
|
248
|
+
}
|
|
249
|
+
this._fullRefresh();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// TODO: Is this useful when we have onResize?
|
|
253
|
+
public handleCharSizeChanged(): void {
|
|
254
|
+
this._renderer.value?.handleCharSizeChanged();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
public handleBlur(): void {
|
|
258
|
+
this._renderer.value?.handleBlur();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
public handleFocus(): void {
|
|
262
|
+
this._renderer.value?.handleFocus();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
public handleSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void {
|
|
266
|
+
this._selectionState.start = start;
|
|
267
|
+
this._selectionState.end = end;
|
|
268
|
+
this._selectionState.columnSelectMode = columnSelectMode;
|
|
269
|
+
this._renderer.value?.handleSelectionChanged(start, end, columnSelectMode);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
public handleCursorMove(): void {
|
|
273
|
+
this._renderer.value?.handleCursorMove();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
public clear(): void {
|
|
277
|
+
this._renderer.value?.clear();
|
|
278
|
+
}
|
|
279
|
+
}
|