@xterm/xterm 6.1.0-beta.9 → 6.1.0-beta.90
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 +27 -28
- package/css/xterm.css +5 -11
- package/lib/xterm.js +1 -1
- package/lib/xterm.js.map +1 -1
- package/lib/xterm.mjs +17 -17
- package/lib/xterm.mjs.map +4 -4
- package/package.json +26 -19
- package/src/browser/AccessibilityManager.ts +4 -1
- package/src/browser/CoreBrowserTerminal.ts +37 -6
- package/src/browser/OscLinkProvider.ts +1 -1
- package/src/browser/Types.ts +4 -1
- package/src/browser/Viewport.ts +16 -1
- package/src/browser/input/CompositionHelper.ts +10 -1
- package/src/browser/public/Terminal.ts +6 -5
- package/src/browser/renderer/dom/DomRenderer.ts +74 -3
- package/src/browser/renderer/dom/WidthCache.ts +54 -52
- package/src/browser/renderer/shared/Constants.ts +7 -0
- package/src/browser/renderer/shared/Types.ts +5 -0
- package/src/browser/services/MouseService.ts +2 -1
- package/src/browser/services/RenderService.ts +9 -5
- package/src/browser/services/Services.ts +1 -1
- package/src/common/Color.ts +8 -0
- package/src/common/CoreTerminal.ts +2 -1
- package/src/common/InputHandler.ts +52 -9
- package/src/common/Platform.ts +4 -1
- package/src/common/Types.ts +1 -1
- package/src/common/Version.ts +9 -0
- package/src/common/buffer/Buffer.ts +4 -0
- package/src/common/buffer/Types.ts +4 -0
- package/src/common/data/Charsets.ts +1 -1
- package/src/common/input/Keyboard.ts +7 -6
- package/src/common/services/CharsetService.ts +4 -0
- package/src/common/services/DecorationService.ts +17 -3
- package/src/common/services/OptionsService.ts +2 -2
- package/src/common/services/Services.ts +6 -1
- package/typings/xterm.d.ts +165 -34
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @license MIT
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
|
6
7
|
import { IDisposable } from 'common/Types';
|
|
7
8
|
import { FontWeight } from 'common/services/Services';
|
|
8
9
|
|
|
@@ -24,6 +25,10 @@ const enum FontVariant {
|
|
|
24
25
|
BOLD_ITALIC = 3
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
export interface IWidthCacheFontVariantCanvas {
|
|
29
|
+
setFont(fontFamily: string, fontSize: number, fontWeight: FontWeight, italic: boolean): void;
|
|
30
|
+
measure(c: string): number;
|
|
31
|
+
}
|
|
27
32
|
|
|
28
33
|
export class WidthCache implements IDisposable {
|
|
29
34
|
// flat cache for regular variant up to CacheSettings.FLAT_SIZE
|
|
@@ -42,50 +47,24 @@ export class WidthCache implements IDisposable {
|
|
|
42
47
|
private _fontSize = 0;
|
|
43
48
|
private _weight: FontWeight = 'normal';
|
|
44
49
|
private _weightBold: FontWeight = 'bold';
|
|
45
|
-
private
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
this.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const regular = _document.createElement('span');
|
|
58
|
-
regular.classList.add('xterm-char-measure-element');
|
|
59
|
-
|
|
60
|
-
const bold = _document.createElement('span');
|
|
61
|
-
bold.classList.add('xterm-char-measure-element');
|
|
62
|
-
bold.style.fontWeight = 'bold';
|
|
63
|
-
|
|
64
|
-
const italic = _document.createElement('span');
|
|
65
|
-
italic.classList.add('xterm-char-measure-element');
|
|
66
|
-
italic.style.fontStyle = 'italic';
|
|
67
|
-
|
|
68
|
-
const boldItalic = _document.createElement('span');
|
|
69
|
-
boldItalic.classList.add('xterm-char-measure-element');
|
|
70
|
-
boldItalic.style.fontWeight = 'bold';
|
|
71
|
-
boldItalic.style.fontStyle = 'italic';
|
|
72
|
-
|
|
73
|
-
// NOTE: must be in order of FontVariant
|
|
74
|
-
this._measureElements = [regular, bold, italic, boldItalic];
|
|
75
|
-
this._container.appendChild(regular);
|
|
76
|
-
this._container.appendChild(bold);
|
|
77
|
-
this._container.appendChild(italic);
|
|
78
|
-
this._container.appendChild(boldItalic);
|
|
79
|
-
|
|
80
|
-
_helperContainer.appendChild(this._container);
|
|
50
|
+
private _canvasElements: IWidthCacheFontVariantCanvas[] = [];
|
|
51
|
+
|
|
52
|
+
constructor(
|
|
53
|
+
canvasFactory: () => IWidthCacheFontVariantCanvas = () => new WidthCacheFontVariantCanvas()
|
|
54
|
+
) {
|
|
55
|
+
this._canvasElements = [
|
|
56
|
+
canvasFactory(),
|
|
57
|
+
canvasFactory(),
|
|
58
|
+
canvasFactory(),
|
|
59
|
+
canvasFactory()
|
|
60
|
+
];
|
|
81
61
|
|
|
82
62
|
this.clear();
|
|
83
63
|
}
|
|
84
64
|
|
|
85
65
|
public dispose(): void {
|
|
86
|
-
this.
|
|
87
|
-
this.
|
|
88
|
-
this._holey = undefined; // free cache memory via GC
|
|
66
|
+
this._canvasElements.length = 0;
|
|
67
|
+
this._holey = undefined; // free cache memory via GC
|
|
89
68
|
}
|
|
90
69
|
|
|
91
70
|
/**
|
|
@@ -104,10 +83,11 @@ export class WidthCache implements IDisposable {
|
|
|
104
83
|
*/
|
|
105
84
|
public setFont(font: string, fontSize: number, weight: FontWeight, weightBold: FontWeight): void {
|
|
106
85
|
// skip if nothing changed
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
86
|
+
if (
|
|
87
|
+
font === this._font &&
|
|
88
|
+
fontSize === this._fontSize &&
|
|
89
|
+
weight === this._weight &&
|
|
90
|
+
weightBold === this._weightBold
|
|
111
91
|
) {
|
|
112
92
|
return;
|
|
113
93
|
}
|
|
@@ -117,12 +97,10 @@ export class WidthCache implements IDisposable {
|
|
|
117
97
|
this._weight = weight;
|
|
118
98
|
this._weightBold = weightBold;
|
|
119
99
|
|
|
120
|
-
this.
|
|
121
|
-
this.
|
|
122
|
-
this.
|
|
123
|
-
this.
|
|
124
|
-
this._measureElements[FontVariant.ITALIC].style.fontWeight = `${weight}`;
|
|
125
|
-
this._measureElements[FontVariant.BOLD_ITALIC].style.fontWeight = `${weightBold}`;
|
|
100
|
+
this._canvasElements[FontVariant.REGULAR].setFont(font, fontSize, weight, false);
|
|
101
|
+
this._canvasElements[FontVariant.BOLD].setFont(font, fontSize, weightBold, false);
|
|
102
|
+
this._canvasElements[FontVariant.ITALIC].setFont(font, fontSize, weight, true);
|
|
103
|
+
this._canvasElements[FontVariant.BOLD_ITALIC].setFont(font, fontSize, weightBold, true);
|
|
126
104
|
|
|
127
105
|
this.clear();
|
|
128
106
|
}
|
|
@@ -160,8 +138,32 @@ export class WidthCache implements IDisposable {
|
|
|
160
138
|
}
|
|
161
139
|
|
|
162
140
|
protected _measure(c: string, variant: FontVariant): number {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
141
|
+
return this._canvasElements[variant].measure(c);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
class WidthCacheFontVariantCanvas implements IWidthCacheFontVariantCanvas {
|
|
146
|
+
private _canvas: OffscreenCanvas | HTMLCanvasElement;
|
|
147
|
+
private _ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D;
|
|
148
|
+
|
|
149
|
+
constructor() {
|
|
150
|
+
if (typeof OffscreenCanvas !== 'undefined') {
|
|
151
|
+
this._canvas = new OffscreenCanvas(1, 1);
|
|
152
|
+
this._ctx = throwIfFalsy(this._canvas.getContext('2d'));
|
|
153
|
+
} else {
|
|
154
|
+
this._canvas = document.createElement('canvas');
|
|
155
|
+
this._canvas.width = 1;
|
|
156
|
+
this._canvas.height = 1;
|
|
157
|
+
this._ctx = throwIfFalsy(this._canvas.getContext('2d'));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
public setFont(fontFamily: string, fontSize: number, fontWeight: FontWeight, italic: boolean): void {
|
|
162
|
+
const fontStyle = italic ? 'italic' : '';
|
|
163
|
+
this._ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`.trim();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public measure(c: string): number {
|
|
167
|
+
return this._ctx.measureText(c).width;
|
|
166
168
|
}
|
|
167
169
|
}
|
|
@@ -39,6 +39,11 @@ export interface IRenderDimensions {
|
|
|
39
39
|
export interface IRequestRedrawEvent {
|
|
40
40
|
start: number;
|
|
41
41
|
end: number;
|
|
42
|
+
/**
|
|
43
|
+
* Whether the redraw should happen synchronously. This is used to avoid
|
|
44
|
+
* flicker when the canvas is resized.
|
|
45
|
+
*/
|
|
46
|
+
sync?: boolean;
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
/**
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @license MIT
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { getWindow } from 'vs/base/browser/dom';
|
|
6
7
|
import { ICharSizeService, IRenderService, IMouseService } from './Services';
|
|
7
8
|
import { getCoords, getCoordsRelativeToElement } from 'browser/input/Mouse';
|
|
8
9
|
|
|
@@ -30,7 +31,7 @@ export class MouseService implements IMouseService {
|
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
public getMouseReportCoords(event: MouseEvent, element: HTMLElement): { col: number, row: number, x: number, y: number } | undefined {
|
|
33
|
-
const coords = getCoordsRelativeToElement(
|
|
34
|
+
const coords = getCoordsRelativeToElement(getWindow(element), event, element);
|
|
34
35
|
if (!this._charSizeService.hasValidSize) {
|
|
35
36
|
return undefined;
|
|
36
37
|
}
|
|
@@ -92,7 +92,6 @@ export class RenderService extends Disposable implements IRenderService {
|
|
|
92
92
|
|
|
93
93
|
// Clear the renderer when the a change that could affect glyphs occurs
|
|
94
94
|
this._register(this._optionsService.onMultipleOptionChange([
|
|
95
|
-
'customGlyphs',
|
|
96
95
|
'drawBoldTextInBrightColors',
|
|
97
96
|
'letterSpacing',
|
|
98
97
|
'lineHeight',
|
|
@@ -112,7 +111,7 @@ export class RenderService extends Disposable implements IRenderService {
|
|
|
112
111
|
this._register(this._optionsService.onMultipleOptionChange([
|
|
113
112
|
'cursorBlink',
|
|
114
113
|
'cursorStyle'
|
|
115
|
-
], () => this.refreshRows(bufferService.buffer.y, bufferService.buffer.y, true)));
|
|
114
|
+
], () => this.refreshRows(bufferService.buffer.y, bufferService.buffer.y, undefined, true)));
|
|
116
115
|
|
|
117
116
|
this._register(themeService.onChangeColors(() => this._fullRefresh()));
|
|
118
117
|
|
|
@@ -145,7 +144,7 @@ export class RenderService extends Disposable implements IRenderService {
|
|
|
145
144
|
}
|
|
146
145
|
}
|
|
147
146
|
|
|
148
|
-
public refreshRows(start: number, end: number, isRedrawOnly: boolean = false): void {
|
|
147
|
+
public refreshRows(start: number, end: number, sync: boolean = false, isRedrawOnly: boolean = false): void {
|
|
149
148
|
if (this._isPaused) {
|
|
150
149
|
this._needsFullRefresh = true;
|
|
151
150
|
return;
|
|
@@ -165,7 +164,12 @@ export class RenderService extends Disposable implements IRenderService {
|
|
|
165
164
|
if (!isRedrawOnly) {
|
|
166
165
|
this._isNextRenderRedrawOnly = false;
|
|
167
166
|
}
|
|
168
|
-
|
|
167
|
+
|
|
168
|
+
if (sync) {
|
|
169
|
+
this._renderRows(start, end);
|
|
170
|
+
} else {
|
|
171
|
+
this._renderDebouncer.refresh(start, end, this._rowCount);
|
|
172
|
+
}
|
|
169
173
|
}
|
|
170
174
|
|
|
171
175
|
private _renderRows(start: number, end: number): void {
|
|
@@ -235,7 +239,7 @@ export class RenderService extends Disposable implements IRenderService {
|
|
|
235
239
|
this._renderer.value = renderer;
|
|
236
240
|
// If the value was not set, the terminal is being disposed so ignore it
|
|
237
241
|
if (this._renderer.value) {
|
|
238
|
-
this._renderer.value.onRequestRedraw(e => this.refreshRows(e.start, e.end, true));
|
|
242
|
+
this._renderer.value.onRequestRedraw(e => this.refreshRows(e.start, e.end, e.sync, true));
|
|
239
243
|
|
|
240
244
|
// Force a refresh
|
|
241
245
|
this._needsSelectionRefresh = true;
|
|
@@ -77,7 +77,7 @@ export interface IRenderService extends IDisposable {
|
|
|
77
77
|
|
|
78
78
|
addRefreshCallback(callback: FrameRequestCallback): number;
|
|
79
79
|
|
|
80
|
-
refreshRows(start: number, end: number): void;
|
|
80
|
+
refreshRows(start: number, end: number, sync?: boolean): void;
|
|
81
81
|
clearTextureAtlas(): void;
|
|
82
82
|
resize(cols: number, rows: number): void;
|
|
83
83
|
hasRenderer(): boolean;
|
package/src/common/Color.ts
CHANGED
|
@@ -184,6 +184,14 @@ export namespace css {
|
|
|
184
184
|
return channels.toColor($r, $g, $b, $a);
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
// Handle the "transparent" keyword
|
|
188
|
+
if (css === 'transparent') {
|
|
189
|
+
return {
|
|
190
|
+
css: 'transparent',
|
|
191
|
+
rgba: 0x00000000
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
187
195
|
// Validate the context is available for canvas-based color parsing
|
|
188
196
|
if (!$ctx || !$litmusColor) {
|
|
189
197
|
throw new Error('css.toColor: Unsupported css format');
|
|
@@ -65,6 +65,8 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
|
|
|
65
65
|
public readonly onData = this._onData.event;
|
|
66
66
|
protected _onLineFeed = this._register(new Emitter<void>());
|
|
67
67
|
public readonly onLineFeed = this._onLineFeed.event;
|
|
68
|
+
protected readonly _onRender = this._register(new Emitter<{ start: number, end: number }>());
|
|
69
|
+
public readonly onRender = this._onRender.event;
|
|
68
70
|
private readonly _onResize = this._register(new Emitter<{ cols: number, rows: number }>());
|
|
69
71
|
public readonly onResize = this._onResize.event;
|
|
70
72
|
protected readonly _onWriteParsed = this._register(new Emitter<void>());
|
|
@@ -124,7 +126,6 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
|
|
|
124
126
|
// Register input handler and handle/forward events
|
|
125
127
|
this._inputHandler = this._register(new InputHandler(this._bufferService, this._charsetService, this.coreService, this._logService, this.optionsService, this._oscLinkService, this.coreMouseService, this.unicodeService));
|
|
126
128
|
this._register(Event.forward(this._inputHandler.onLineFeed, this._onLineFeed));
|
|
127
|
-
this._register(this._inputHandler);
|
|
128
129
|
|
|
129
130
|
// Setup listeners
|
|
130
131
|
this._register(Event.forward(this._bufferService.onResize, this._onResize));
|
|
@@ -22,6 +22,7 @@ import { DcsHandler } from 'common/parser/DcsParser';
|
|
|
22
22
|
import { IBuffer } from 'common/buffer/Types';
|
|
23
23
|
import { parseColor } from 'common/input/XParseColor';
|
|
24
24
|
import { Emitter } from 'vs/base/common/event';
|
|
25
|
+
import { XTERM_VERSION } from 'common/Version';
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* Map collect to glevel. Used in `selectCharset`.
|
|
@@ -239,6 +240,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|
|
239
240
|
this._parser.registerCsiHandler({ final: 'T' }, params => this.scrollDown(params));
|
|
240
241
|
this._parser.registerCsiHandler({ final: 'X' }, params => this.eraseChars(params));
|
|
241
242
|
this._parser.registerCsiHandler({ final: 'Z' }, params => this.cursorBackwardTab(params));
|
|
243
|
+
this._parser.registerCsiHandler({ final: '^' }, params => this.scrollDown(params));
|
|
242
244
|
this._parser.registerCsiHandler({ final: '`' }, params => this.charPosAbsolute(params));
|
|
243
245
|
this._parser.registerCsiHandler({ final: 'a' }, params => this.hPositionRelative(params));
|
|
244
246
|
this._parser.registerCsiHandler({ final: 'b' }, params => this.repeatPrecedingCharacter(params));
|
|
@@ -256,6 +258,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|
|
256
258
|
this._parser.registerCsiHandler({ final: 'n' }, params => this.deviceStatus(params));
|
|
257
259
|
this._parser.registerCsiHandler({ prefix: '?', final: 'n' }, params => this.deviceStatusPrivate(params));
|
|
258
260
|
this._parser.registerCsiHandler({ intermediates: '!', final: 'p' }, params => this.softReset(params));
|
|
261
|
+
this._parser.registerCsiHandler({ prefix: '>', final: 'q' }, params => this.sendXtVersion(params));
|
|
259
262
|
this._parser.registerCsiHandler({ intermediates: ' ', final: 'q' }, params => this.setCursorStyle(params));
|
|
260
263
|
this._parser.registerCsiHandler({ final: 'r' }, params => this.setScrollRegion(params));
|
|
261
264
|
this._parser.registerCsiHandler({ final: 's' }, params => this.saveCursor(params));
|
|
@@ -531,6 +534,12 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|
|
531
534
|
for (let pos = start; pos < end; ++pos) {
|
|
532
535
|
code = data[pos];
|
|
533
536
|
|
|
537
|
+
// Soft hyphen's (U+00AD) behavior is ambiguous and differs across terminals. We opt to treat
|
|
538
|
+
// it as a zero-width hint to text layout engines and simply ignore it.
|
|
539
|
+
if (code === 0xAD) {
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
|
|
534
543
|
// get charset replacement character
|
|
535
544
|
// charset is only defined for ASCII, therefore we only
|
|
536
545
|
// search for an replacement char if code < 127
|
|
@@ -1145,7 +1154,10 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|
|
1145
1154
|
* @param respectProtect Whether to respect the protection attribute (DECSCA).
|
|
1146
1155
|
*/
|
|
1147
1156
|
private _eraseInBufferLine(y: number, start: number, end: number, clearWrap: boolean = false, respectProtect: boolean = false): void {
|
|
1148
|
-
const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)
|
|
1157
|
+
const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y);
|
|
1158
|
+
if (!line) {
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1149
1161
|
line.replaceCells(
|
|
1150
1162
|
start,
|
|
1151
1163
|
end,
|
|
@@ -1215,7 +1227,10 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|
|
1215
1227
|
this._eraseInBufferLine(j, 0, this._activeBuffer.x + 1, true, respectProtect);
|
|
1216
1228
|
if (this._activeBuffer.x + 1 >= this._bufferService.cols) {
|
|
1217
1229
|
// Deleted entire previous line. This next line can no longer be wrapped.
|
|
1218
|
-
this._activeBuffer.lines.get(j + 1)
|
|
1230
|
+
const nextLine = this._activeBuffer.lines.get(j + 1);
|
|
1231
|
+
if (nextLine) {
|
|
1232
|
+
nextLine.isWrapped = false;
|
|
1233
|
+
}
|
|
1219
1234
|
}
|
|
1220
1235
|
while (j--) {
|
|
1221
1236
|
this._resetBufferLine(j, respectProtect);
|
|
@@ -1721,6 +1736,22 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|
|
1721
1736
|
return true;
|
|
1722
1737
|
}
|
|
1723
1738
|
|
|
1739
|
+
/**
|
|
1740
|
+
* CSI > Ps q
|
|
1741
|
+
* Ps = 0 => Report xterm name and version (XTVERSION).
|
|
1742
|
+
*
|
|
1743
|
+
* The response is a DCS sequence identifying the version: DCS > | text ST
|
|
1744
|
+
*
|
|
1745
|
+
* @vt: #Y CSI XTVERSION "Report Xterm Version" "CSI > q" "Report the terminal name and version."
|
|
1746
|
+
*/
|
|
1747
|
+
public sendXtVersion(params: IParams): boolean {
|
|
1748
|
+
if (params.params[0] > 0) {
|
|
1749
|
+
return true;
|
|
1750
|
+
}
|
|
1751
|
+
this._coreService.triggerDataEvent(`${C0.ESC}P>|xterm.js(${XTERM_VERSION})${C0.ESC}\\`);
|
|
1752
|
+
return true;
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1724
1755
|
/**
|
|
1725
1756
|
* Evaluate if the current terminal is the given argument.
|
|
1726
1757
|
* @param term The terminal name to evaluate
|
|
@@ -1853,7 +1884,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|
|
1853
1884
|
* | 7 | Auto-wrap Mode (DECAWM). | #Y |
|
|
1854
1885
|
* | 8 | Auto-repeat Keys (DECARM). Always on. | #N |
|
|
1855
1886
|
* | 9 | X10 xterm mouse protocol. | #Y |
|
|
1856
|
-
* | 12 | Start Blinking Cursor. | #
|
|
1887
|
+
* | 12 | Start Blinking Cursor. | #P[Requires the allowSetCursorBlink quirk option enabled.] |
|
|
1857
1888
|
* | 25 | Show Cursor (DECTCEM). | #Y |
|
|
1858
1889
|
* | 45 | Reverse wrap-around. | #Y |
|
|
1859
1890
|
* | 47 | Use Alternate Screen Buffer. | #Y |
|
|
@@ -1906,7 +1937,9 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|
|
1906
1937
|
this._coreService.decPrivateModes.wraparound = true;
|
|
1907
1938
|
break;
|
|
1908
1939
|
case 12:
|
|
1909
|
-
this._optionsService.
|
|
1940
|
+
if (this._optionsService.rawOptions.quirks?.allowSetCursorBlink) {
|
|
1941
|
+
this._optionsService.options.cursorBlink = true;
|
|
1942
|
+
}
|
|
1910
1943
|
break;
|
|
1911
1944
|
case 45:
|
|
1912
1945
|
this._coreService.decPrivateModes.reverseWraparound = true;
|
|
@@ -2101,7 +2134,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|
|
2101
2134
|
* | 7 | No Wraparound Mode (DECAWM). | #Y |
|
|
2102
2135
|
* | 8 | No Auto-repeat Keys (DECARM). | #N |
|
|
2103
2136
|
* | 9 | Don't send Mouse X & Y on button press. | #Y |
|
|
2104
|
-
* | 12 | Stop Blinking Cursor. | #
|
|
2137
|
+
* | 12 | Stop Blinking Cursor. | #P[Requires the allowSetCursorBlink quirk option enabled.] |
|
|
2105
2138
|
* | 25 | Hide Cursor (DECTCEM). | #Y |
|
|
2106
2139
|
* | 45 | No reverse wrap-around. | #Y |
|
|
2107
2140
|
* | 47 | Use Normal Screen Buffer. | #Y |
|
|
@@ -2147,7 +2180,9 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|
|
2147
2180
|
this._coreService.decPrivateModes.wraparound = false;
|
|
2148
2181
|
break;
|
|
2149
2182
|
case 12:
|
|
2150
|
-
this._optionsService.
|
|
2183
|
+
if (this._optionsService.rawOptions.quirks?.allowSetCursorBlink) {
|
|
2184
|
+
this._optionsService.options.cursorBlink = false;
|
|
2185
|
+
}
|
|
2151
2186
|
break;
|
|
2152
2187
|
case 45:
|
|
2153
2188
|
this._coreService.decPrivateModes.reverseWraparound = false;
|
|
@@ -2901,6 +2936,10 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|
|
2901
2936
|
this._activeBuffer.savedCurAttrData.fg = this._curAttrData.fg;
|
|
2902
2937
|
this._activeBuffer.savedCurAttrData.bg = this._curAttrData.bg;
|
|
2903
2938
|
this._activeBuffer.savedCharset = this._charsetService.charset;
|
|
2939
|
+
this._activeBuffer.savedCharsets = this._charsetService.charsets.slice();
|
|
2940
|
+
this._activeBuffer.savedGlevel = this._charsetService.glevel;
|
|
2941
|
+
this._activeBuffer.savedOriginMode = this._coreService.decPrivateModes.origin;
|
|
2942
|
+
this._activeBuffer.savedWraparoundMode = this._coreService.decPrivateModes.wraparound;
|
|
2904
2943
|
return true;
|
|
2905
2944
|
}
|
|
2906
2945
|
|
|
@@ -2918,10 +2957,12 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|
|
2918
2957
|
this._activeBuffer.y = Math.max(this._activeBuffer.savedY - this._activeBuffer.ybase, 0);
|
|
2919
2958
|
this._curAttrData.fg = this._activeBuffer.savedCurAttrData.fg;
|
|
2920
2959
|
this._curAttrData.bg = this._activeBuffer.savedCurAttrData.bg;
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
this._charsetService.charset = this._activeBuffer.savedCharset;
|
|
2960
|
+
for (let i = 0; i < this._activeBuffer.savedCharsets.length; i++) {
|
|
2961
|
+
this._charsetService.setgCharset(i, this._activeBuffer.savedCharsets[i]);
|
|
2924
2962
|
}
|
|
2963
|
+
this._charsetService.setgLevel(this._activeBuffer.savedGlevel);
|
|
2964
|
+
this._coreService.decPrivateModes.origin = this._activeBuffer.savedOriginMode;
|
|
2965
|
+
this._coreService.decPrivateModes.wraparound = this._activeBuffer.savedWraparoundMode;
|
|
2925
2966
|
this._restrictCursor();
|
|
2926
2967
|
return true;
|
|
2927
2968
|
}
|
|
@@ -3320,6 +3361,8 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|
|
3320
3361
|
* ESC c
|
|
3321
3362
|
* DEC mnemonic: RIS (https://vt100.net/docs/vt510-rm/RIS.html)
|
|
3322
3363
|
* Reset to initial state.
|
|
3364
|
+
*
|
|
3365
|
+
* @vt: #Y ESC RIS "Full Reset" "ESC c" "Reset to initial state."
|
|
3323
3366
|
*/
|
|
3324
3367
|
public fullReset(): boolean {
|
|
3325
3368
|
this._parser.reset();
|
package/src/common/Platform.ts
CHANGED
|
@@ -14,7 +14,10 @@ interface INavigator {
|
|
|
14
14
|
declare const navigator: INavigator;
|
|
15
15
|
declare const process: unknown;
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
// navigator.userAgent is also checked here because bundling with the process module can cause
|
|
18
|
+
// issues otherwise. Note that navigator exists in Node.js 21+ but the userAgent is
|
|
19
|
+
// "Node.js/<version>".
|
|
20
|
+
export const isNode = (typeof process !== 'undefined' && 'title' in (process as any) && (typeof navigator === 'undefined' || navigator.userAgent.startsWith('Node.js/'))) ? true : false;
|
|
18
21
|
const userAgent = (isNode) ? 'node' : navigator.userAgent;
|
|
19
22
|
const platform = (isNode) ? 'node' : navigator.platform;
|
|
20
23
|
|
package/src/common/Types.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { IDeleteEvent, IInsertEvent } from 'common/CircularList';
|
|
7
|
-
import {
|
|
7
|
+
import { UnderlineStyle } from 'common/buffer/Constants';
|
|
8
8
|
import { IBufferSet } from 'common/buffer/Types';
|
|
9
9
|
import { IParams } from 'common/parser/Types';
|
|
10
10
|
import { ICoreMouseService, ICoreService, IOptionsService, IUnicodeService } from 'common/services/Services';
|
|
@@ -38,6 +38,10 @@ export class Buffer implements IBuffer {
|
|
|
38
38
|
public savedX: number = 0;
|
|
39
39
|
public savedCurAttrData = DEFAULT_ATTR_DATA.clone();
|
|
40
40
|
public savedCharset: ICharset | undefined = DEFAULT_CHARSET;
|
|
41
|
+
public savedCharsets: (ICharset | undefined)[] = [];
|
|
42
|
+
public savedGlevel: number = 0;
|
|
43
|
+
public savedOriginMode: boolean = false;
|
|
44
|
+
public savedWraparoundMode: boolean = true;
|
|
41
45
|
public markers: Marker[] = [];
|
|
42
46
|
private _nullCell: ICellData = CellData.fromCharData([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
|
|
43
47
|
private _whitespaceCell: ICellData = CellData.fromCharData([0, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_WIDTH, WHITESPACE_CELL_CODE]);
|
|
@@ -22,6 +22,10 @@ export interface IBuffer {
|
|
|
22
22
|
savedY: number;
|
|
23
23
|
savedX: number;
|
|
24
24
|
savedCharset: ICharset | undefined;
|
|
25
|
+
savedCharsets: (ICharset | undefined)[];
|
|
26
|
+
savedGlevel: number;
|
|
27
|
+
savedOriginMode: boolean;
|
|
28
|
+
savedWraparoundMode: boolean;
|
|
25
29
|
savedCurAttrData: IAttributeData;
|
|
26
30
|
isCursorInViewport: boolean;
|
|
27
31
|
markers: IMarker[];
|
|
@@ -315,6 +315,8 @@ export function evaluateKeyboardEvent(
|
|
|
315
315
|
result.key = String.fromCharCode(ev.keyCode - 51 + 27);
|
|
316
316
|
} else if (ev.keyCode === 56) {
|
|
317
317
|
result.key = C0.DEL;
|
|
318
|
+
} else if (ev.key === '/') {
|
|
319
|
+
result.key = C0.US; // https://github.com/xtermjs/xterm.js/issues/5457
|
|
318
320
|
} else if (ev.keyCode === 219) {
|
|
319
321
|
result.key = C0.ESC;
|
|
320
322
|
} else if (ev.keyCode === 220) {
|
|
@@ -358,12 +360,11 @@ export function evaluateKeyboardEvent(
|
|
|
358
360
|
// Include only keys that that result in a _single_ character; don't include num lock,
|
|
359
361
|
// volume up, etc.
|
|
360
362
|
result.key = ev.key;
|
|
361
|
-
} else if (ev.key && ev.ctrlKey) {
|
|
362
|
-
|
|
363
|
-
result.key = C0.US;
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
result.key = C0.NUL;
|
|
363
|
+
} else if (ev.key && ev.ctrlKey && ev.shiftKey) {
|
|
364
|
+
switch (ev.code) {
|
|
365
|
+
case 'Minus': result.key = C0.US; break; // ^_ (Ctrl+Shift+-_
|
|
366
|
+
case 'Digit2': result.key = C0.NUL; break; // ^@ (Ctrl+Shift+2)
|
|
367
|
+
case 'Digit6': result.key = C0.RS; break; // ^^ (Ctrl+Shift+6)
|
|
367
368
|
}
|
|
368
369
|
}
|
|
369
370
|
break;
|
|
@@ -14,6 +14,10 @@ export class CharsetService implements ICharsetService {
|
|
|
14
14
|
|
|
15
15
|
private _charsets: (ICharset | undefined)[] = [];
|
|
16
16
|
|
|
17
|
+
public get charsets(): (ICharset | undefined)[] {
|
|
18
|
+
return this._charsets;
|
|
19
|
+
}
|
|
20
|
+
|
|
17
21
|
public reset(): void {
|
|
18
22
|
this.charset = undefined;
|
|
19
23
|
this._charsets = [];
|
|
@@ -14,6 +14,8 @@ import { Emitter } from 'vs/base/common/event';
|
|
|
14
14
|
// Work variables to avoid garbage collection
|
|
15
15
|
let $xmin = 0;
|
|
16
16
|
let $xmax = 0;
|
|
17
|
+
let $ymin = 0;
|
|
18
|
+
let $ymax = 0;
|
|
17
19
|
|
|
18
20
|
export class DecorationService extends Disposable implements IDecorationService {
|
|
19
21
|
public serviceBrand: any;
|
|
@@ -70,7 +72,14 @@ export class DecorationService extends Disposable implements IDecorationService
|
|
|
70
72
|
public *getDecorationsAtCell(x: number, line: number, layer?: 'bottom' | 'top'): IterableIterator<IInternalDecoration> {
|
|
71
73
|
let xmin = 0;
|
|
72
74
|
let xmax = 0;
|
|
73
|
-
|
|
75
|
+
let ymin = 0;
|
|
76
|
+
let ymax = 0;
|
|
77
|
+
for (const d of this._decorations.values()) {
|
|
78
|
+
ymin = d.marker.line;
|
|
79
|
+
ymax = ymin + (d.options.height ?? 1);
|
|
80
|
+
if (line < ymin || line >= ymax) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
74
83
|
xmin = d.options.x ?? 0;
|
|
75
84
|
xmax = xmin + (d.options.width ?? 1);
|
|
76
85
|
if (x >= xmin && x < xmax && (!layer || (d.options.layer ?? 'bottom') === layer)) {
|
|
@@ -80,13 +89,18 @@ export class DecorationService extends Disposable implements IDecorationService
|
|
|
80
89
|
}
|
|
81
90
|
|
|
82
91
|
public forEachDecorationAtCell(x: number, line: number, layer: 'bottom' | 'top' | undefined, callback: (decoration: IInternalDecoration) => void): void {
|
|
83
|
-
this._decorations.
|
|
92
|
+
for (const d of this._decorations.values()) {
|
|
93
|
+
$ymin = d.marker.line;
|
|
94
|
+
$ymax = $ymin + (d.options.height ?? 1);
|
|
95
|
+
if (line < $ymin || line >= $ymax) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
84
98
|
$xmin = d.options.x ?? 0;
|
|
85
99
|
$xmax = $xmin + (d.options.width ?? 1);
|
|
86
100
|
if (x >= $xmin && x < $xmax && (!layer || (d.options.layer ?? 'bottom') === layer)) {
|
|
87
101
|
callback(d);
|
|
88
102
|
}
|
|
89
|
-
}
|
|
103
|
+
}
|
|
90
104
|
}
|
|
91
105
|
}
|
|
92
106
|
|
|
@@ -16,7 +16,6 @@ export const DEFAULT_OPTIONS: Readonly<Required<ITerminalOptions>> = {
|
|
|
16
16
|
cursorStyle: 'block',
|
|
17
17
|
cursorWidth: 1,
|
|
18
18
|
cursorInactiveStyle: 'outline',
|
|
19
|
-
customGlyphs: true,
|
|
20
19
|
drawBoldTextInBrightColors: true,
|
|
21
20
|
documentOverride: null,
|
|
22
21
|
fastScrollSensitivity: 5,
|
|
@@ -54,7 +53,8 @@ export const DEFAULT_OPTIONS: Readonly<Required<ITerminalOptions>> = {
|
|
|
54
53
|
convertEol: false,
|
|
55
54
|
termName: 'xterm',
|
|
56
55
|
cancelEvents: false,
|
|
57
|
-
overviewRuler: {}
|
|
56
|
+
overviewRuler: {},
|
|
57
|
+
quirks: {}
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
const FONT_WEIGHT_OPTIONS: Extract<FontWeight, string>[] = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'];
|
|
@@ -116,6 +116,7 @@ export interface ICharsetService {
|
|
|
116
116
|
|
|
117
117
|
charset: ICharset | undefined;
|
|
118
118
|
readonly glevel: number;
|
|
119
|
+
readonly charsets: (ICharset | undefined)[];
|
|
119
120
|
|
|
120
121
|
reset(): void;
|
|
121
122
|
|
|
@@ -230,7 +231,6 @@ export interface ITerminalOptions {
|
|
|
230
231
|
cursorStyle?: CursorStyle;
|
|
231
232
|
cursorWidth?: number;
|
|
232
233
|
cursorInactiveStyle?: CursorInactiveStyle;
|
|
233
|
-
customGlyphs?: boolean;
|
|
234
234
|
disableStdin?: boolean;
|
|
235
235
|
documentOverride?: any | null;
|
|
236
236
|
drawBoldTextInBrightColors?: boolean;
|
|
@@ -263,6 +263,7 @@ export interface ITerminalOptions {
|
|
|
263
263
|
windowOptions?: IWindowOptions;
|
|
264
264
|
wordSeparator?: string;
|
|
265
265
|
overviewRuler?: IOverviewRulerOptions;
|
|
266
|
+
quirks?: ITerminalQuirks;
|
|
266
267
|
scrollOnEraseInDisplay?: boolean;
|
|
267
268
|
|
|
268
269
|
[key: string]: any;
|
|
@@ -301,6 +302,10 @@ export interface ITheme {
|
|
|
301
302
|
extendedAnsi?: string[];
|
|
302
303
|
}
|
|
303
304
|
|
|
305
|
+
export interface ITerminalQuirks {
|
|
306
|
+
allowSetCursorBlink?: boolean;
|
|
307
|
+
}
|
|
308
|
+
|
|
304
309
|
export const IOscLinkService = createDecorator<IOscLinkService>('OscLinkService');
|
|
305
310
|
export interface IOscLinkService {
|
|
306
311
|
serviceBrand: undefined;
|