Skip to content

Commit 62656b8

Browse files
authored
Merge branch 'master' into patch-1
2 parents d12b825 + af4208d commit 62656b8

14 files changed

Lines changed: 111 additions & 71 deletions

File tree

addons/addon-webgl/src/WebglRenderer.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
354354
}
355355

356356
private _updateCursorBlink(): void {
357-
if (this._terminal.options.cursorBlink) {
357+
if (this._coreService.decPrivateModes.cursorBlink ?? this._terminal.options.cursorBlink) {
358358
this._cursorBlinkStateManager.value = new CursorBlinkStateManager(() => {
359359
this._requestRedrawCursor();
360360
}, this._coreBrowserService);
@@ -387,6 +387,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
387387
let j: number;
388388
start = clamp(start, terminal.rows - 1, 0);
389389
end = clamp(end, terminal.rows - 1, 0);
390+
const cursorStyle = this._coreService.decPrivateModes.cursorStyle ?? terminal.options.cursorStyle ?? 'block';
390391

391392
const cursorY = this._terminal.buffer.active.baseY + this._terminal.buffer.active.cursorY;
392393
const viewportRelativeCursorY = cursorY - terminal.buffer.ydisp;
@@ -450,18 +451,18 @@ export class WebglRenderer extends Disposable implements IRenderer {
450451
x: cursorX,
451452
y: viewportRelativeCursorY,
452453
width: cell.getWidth(),
453-
style: this._coreBrowserService.isFocused ?
454-
(terminal.options.cursorStyle || 'block') : terminal.options.cursorInactiveStyle,
454+
style: this._coreBrowserService.isFocused ? cursorStyle : terminal.options.cursorInactiveStyle,
455455
cursorWidth: terminal.options.cursorWidth,
456456
dpr: this._devicePixelRatio
457457
};
458458
lastCursorX = cursorX + cell.getWidth() - 1;
459459
}
460460
if (x >= cursorX && x <= lastCursorX &&
461461
((this._coreBrowserService.isFocused &&
462-
(terminal.options.cursorStyle || 'block') === 'block') ||
462+
cursorStyle === 'block') ||
463463
(this._coreBrowserService.isFocused === false &&
464-
terminal.options.cursorInactiveStyle === 'block'))) {
464+
terminal.options.cursorInactiveStyle === 'block'))
465+
) {
465466
this._cellColorResolver.result.fg =
466467
Attributes.CM_RGB | (this._themeService.colors.cursorAccent.rgba >> 8 & Attributes.RGB_MASK);
467468
this._cellColorResolver.result.bg =

demo/client.ts

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ if ('WebAssembly' in window) {
1616
ImageAddon = imageAddon.ImageAddon;
1717
}
1818

19-
import { Terminal, ITerminalOptions, type IDisposable } from '@xterm/xterm';
19+
import { Terminal, ITerminalOptions, type IDisposable, type ITheme } from '@xterm/xterm';
2020
import { AttachAddon } from '@xterm/addon-attach';
2121
import { ClipboardAddon } from '@xterm/addon-clipboard';
2222
import { FitAddon } from '@xterm/addon-fit';
@@ -131,7 +131,7 @@ const xtermjsTheme = {
131131
brightCyan: '#72F0FF',
132132
white: '#F8F8F8',
133133
brightWhite: '#FFFFFF'
134-
};
134+
} satisfies ITheme;
135135
function setPadding(): void {
136136
term.element.style.padding = parseInt(paddingElement.value, 10).toString() + 'px';
137137
addons.fit.instance.fit();
@@ -1266,9 +1266,9 @@ function addVtButtons(): void {
12661266

12671267
const element = document.createElement('button');
12681268
element.textContent = name;
1269-
writeCsi.split('');
1270-
const prefix = writeCsi.length === 2 ? writeCsi[0] : '';
1271-
const suffix = writeCsi[writeCsi.length - 1];
1269+
const writeCsiSplit = writeCsi.split('|');
1270+
const prefix = writeCsiSplit.length === 2 ? writeCsiSplit[0] : '';
1271+
const suffix = writeCsiSplit[writeCsiSplit.length - 1];
12721272
element.addEventListener(`click`, () => term.write(csi(`${prefix}${inputs.map(e => e.value).join(';')}${suffix}`)));
12731273

12741274
const desc = document.createElement('span');
@@ -1281,22 +1281,23 @@ function addVtButtons(): void {
12811281
}
12821282
const vtFragment = document.createDocumentFragment();
12831283
const buttonSpecs: { [key: string]: { label: string, description: string, paramCount?: number }} = {
1284-
A: { label: 'CUU ↑', description: 'Cursor Up Ps Times' },
1285-
B: { label: 'CUD ↓', description: 'Cursor Down Ps Times' },
1286-
C: { label: 'CUF →', description: 'Cursor Forward Ps Times' },
1287-
D: { label: 'CUB ←', description: 'Cursor Backward Ps Times' },
1288-
E: { label: 'CNL', description: 'Cursor Next Line Ps Times' },
1289-
F: { label: 'CPL', description: 'Cursor Preceding Line Ps Times' },
1290-
G: { label: 'CHA', description: 'Cursor Character Absolute' },
1291-
H: { label: 'CUP', description: 'Cursor Position [row;column]', paramCount: 2 },
1292-
I: { label: 'CHT', description: 'Cursor Forward Tabulation Ps tab stops' },
1293-
J: { label: 'ED', description: 'Erase in Display' },
1294-
'?J': { label: 'DECSED', description: 'Erase in Display' },
1295-
K: { label: 'EL', description: 'Erase in Line' },
1296-
'?K': { label: 'DECSEL', description: 'Erase in Line' },
1297-
L: { label: 'IL', description: 'Insert Ps Line(s)' },
1298-
M: { label: 'DL', description: 'Delete Ps Line(s)' },
1299-
P: { label: 'DCH', description: 'Delete Ps Character(s)' }
1284+
A: { label: 'CUU ↑', description: 'Cursor Up Ps Times' },
1285+
B: { label: 'CUD ↓', description: 'Cursor Down Ps Times' },
1286+
C: { label: 'CUF →', description: 'Cursor Forward Ps Times' },
1287+
D: { label: 'CUB ←', description: 'Cursor Backward Ps Times' },
1288+
E: { label: 'CNL', description: 'Cursor Next Line Ps Times' },
1289+
F: { label: 'CPL', description: 'Cursor Preceding Line Ps Times' },
1290+
G: { label: 'CHA', description: 'Cursor Character Absolute' },
1291+
H: { label: 'CUP', description: 'Cursor Position [row;column]', paramCount: 2 },
1292+
I: { label: 'CHT', description: 'Cursor Forward Tabulation Ps tab stops' },
1293+
J: { label: 'ED', description: 'Erase in Display' },
1294+
'?|J': { label: 'DECSED', description: 'Erase in Display' },
1295+
K: { label: 'EL', description: 'Erase in Line' },
1296+
'?|K': { label: 'DECSEL', description: 'Erase in Line' },
1297+
L: { label: 'IL', description: 'Insert Ps Line(s)' },
1298+
M: { label: 'DL', description: 'Delete Ps Line(s)' },
1299+
P: { label: 'DCH', description: 'Delete Ps Character(s)' },
1300+
' q': { label: 'DECSCUSR', description: 'Set Cursor Style', paramCount: 1 }
13001301
};
13011302
for (const s of Object.keys(buttonSpecs)) {
13021303
const spec = buttonSpecs[s];

src/browser/CoreBrowserTerminal.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
437437
this.screenElement.appendChild(this._helperContainer);
438438
fragment.appendChild(this.screenElement);
439439

440-
this.textarea = this._document.createElement('textarea');
440+
const textarea = this.textarea = this._document.createElement('textarea');
441441
this.textarea.classList.add('xterm-helper-textarea');
442442
this.textarea.setAttribute('aria-label', Strings.promptLabel.get());
443443
if (!Browser.isChromeOS) {
@@ -449,6 +449,8 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
449449
this.textarea.setAttribute('autocapitalize', 'off');
450450
this.textarea.setAttribute('spellcheck', 'false');
451451
this.textarea.tabIndex = 0;
452+
this._register(this.optionsService.onSpecificOptionChange('disableStdin', () => textarea.readOnly = this.optionsService.rawOptions.disableStdin));
453+
this.textarea.readOnly = this.optionsService.rawOptions.disableStdin;
452454

453455
// Register the core browser service before the generic textarea handlers are registered so it
454456
// handles them first. Otherwise the renderers may use the wrong focus state.

src/browser/renderer/dom/DomRenderer.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { ICharSizeService, ICoreBrowserService, IThemeService } from 'browser/se
1313
import { ILinkifier2, ILinkifierEvent, ITerminal, ReadonlyColorSet } from 'browser/Types';
1414
import { color } from 'common/Color';
1515
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
16-
import { IBufferService, IInstantiationService, IOptionsService } from 'common/services/Services';
16+
import { IBufferService, ICoreService, IInstantiationService, IOptionsService } from 'common/services/Services';
1717
import { Emitter } from 'vs/base/common/event';
1818

1919

@@ -59,6 +59,7 @@ export class DomRenderer extends Disposable implements IRenderer {
5959
@ICharSizeService private readonly _charSizeService: ICharSizeService,
6060
@IOptionsService private readonly _optionsService: IOptionsService,
6161
@IBufferService private readonly _bufferService: IBufferService,
62+
@ICoreService private readonly _coreService: ICoreService,
6263
@ICoreBrowserService private readonly _coreBrowserService: ICoreBrowserService,
6364
@IThemeService private readonly _themeService: IThemeService
6465
) {
@@ -161,6 +162,10 @@ export class DomRenderer extends Disposable implements IRenderer {
161162
// Base CSS
162163
let styles =
163164
`${this._terminalSelector} .${ROW_CONTAINER_CLASS} {` +
165+
// Disabling pointer events circumvents a browser behavior that prevents `click` events from
166+
// being delivered if the target element is replaced during the click. This happened due to
167+
// refresh() being called during the mousedown handler to start a selection.
168+
` pointer-events: none;` +
164169
` color: ${colors.foreground.css};` +
165170
` font-family: ${this._optionsService.rawOptions.fontFamily};` +
166171
` font-size: ${this._optionsService.rawOptions.fontSize}px;` +
@@ -437,8 +442,8 @@ export class DomRenderer extends Disposable implements IRenderer {
437442
const buffer = this._bufferService.buffer;
438443
const cursorAbsoluteY = buffer.ybase + buffer.y;
439444
const cursorX = Math.min(buffer.x, this._bufferService.cols - 1);
440-
const cursorBlink = this._optionsService.rawOptions.cursorBlink;
441-
const cursorStyle = this._optionsService.rawOptions.cursorStyle;
445+
const cursorBlink = this._coreService.decPrivateModes.cursorBlink ?? this._optionsService.rawOptions.cursorBlink;
446+
const cursorStyle = this._coreService.decPrivateModes.cursorStyle ?? this._optionsService.rawOptions.cursorStyle;
442447
const cursorInactiveStyle = this._optionsService.rawOptions.cursorInactiveStyle;
443448

444449
for (let y = start; y <= end; y++) {

src/browser/services/ThemeService.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ export class ThemeService extends Disposable implements IThemeService {
8282
const colors = this._colors;
8383
colors.foreground = parseColor(theme.foreground, DEFAULT_FOREGROUND);
8484
colors.background = parseColor(theme.background, DEFAULT_BACKGROUND);
85-
colors.cursor = parseColor(theme.cursor, DEFAULT_CURSOR);
86-
colors.cursorAccent = parseColor(theme.cursorAccent, DEFAULT_CURSOR_ACCENT);
85+
colors.cursor = color.blend(colors.background, parseColor(theme.cursor, DEFAULT_CURSOR));
86+
colors.cursorAccent = color.blend(colors.background, parseColor(theme.cursorAccent, DEFAULT_CURSOR_ACCENT));
8787
colors.selectionBackgroundTransparent = parseColor(theme.selectionBackground, DEFAULT_SELECTION);
8888
colors.selectionBackgroundOpaque = color.blend(colors.background, colors.selectionBackgroundTransparent);
8989
colors.selectionInactiveBackgroundTransparent = parseColor(theme.selectionInactiveBackground, colors.selectionBackgroundTransparent);

src/common/InputHandler.test.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -202,38 +202,38 @@ describe('InputHandler', () => {
202202
describe('setCursorStyle', () => {
203203
it('should call Terminal.setOption with correct params', () => {
204204
inputHandler.setCursorStyle(Params.fromArray([0]));
205-
assert.equal(optionsService.options['cursorStyle'], 'block');
206-
assert.equal(optionsService.options['cursorBlink'], true);
205+
assert.equal(coreService.decPrivateModes.cursorStyle, undefined);
206+
assert.equal(coreService.decPrivateModes.cursorBlink, undefined);
207207

208208
optionsService.options = clone(DEFAULT_OPTIONS);
209209
inputHandler.setCursorStyle(Params.fromArray([1]));
210-
assert.equal(optionsService.options['cursorStyle'], 'block');
211-
assert.equal(optionsService.options['cursorBlink'], true);
210+
assert.equal(coreService.decPrivateModes.cursorStyle, 'block');
211+
assert.equal(coreService.decPrivateModes.cursorBlink, true);
212212

213213
optionsService.options = clone(DEFAULT_OPTIONS);
214214
inputHandler.setCursorStyle(Params.fromArray([2]));
215-
assert.equal(optionsService.options['cursorStyle'], 'block');
216-
assert.equal(optionsService.options['cursorBlink'], false);
215+
assert.equal(coreService.decPrivateModes.cursorStyle, 'block');
216+
assert.equal(coreService.decPrivateModes.cursorBlink, false);
217217

218218
optionsService.options = clone(DEFAULT_OPTIONS);
219219
inputHandler.setCursorStyle(Params.fromArray([3]));
220-
assert.equal(optionsService.options['cursorStyle'], 'underline');
221-
assert.equal(optionsService.options['cursorBlink'], true);
220+
assert.equal(coreService.decPrivateModes.cursorStyle, 'underline');
221+
assert.equal(coreService.decPrivateModes.cursorBlink, true);
222222

223223
optionsService.options = clone(DEFAULT_OPTIONS);
224224
inputHandler.setCursorStyle(Params.fromArray([4]));
225-
assert.equal(optionsService.options['cursorStyle'], 'underline');
226-
assert.equal(optionsService.options['cursorBlink'], false);
225+
assert.equal(coreService.decPrivateModes.cursorStyle, 'underline');
226+
assert.equal(coreService.decPrivateModes.cursorBlink, false);
227227

228228
optionsService.options = clone(DEFAULT_OPTIONS);
229229
inputHandler.setCursorStyle(Params.fromArray([5]));
230-
assert.equal(optionsService.options['cursorStyle'], 'bar');
231-
assert.equal(optionsService.options['cursorBlink'], true);
230+
assert.equal(coreService.decPrivateModes.cursorStyle, 'bar');
231+
assert.equal(coreService.decPrivateModes.cursorBlink, true);
232232

233233
optionsService.options = clone(DEFAULT_OPTIONS);
234234
inputHandler.setCursorStyle(Params.fromArray([6]));
235-
assert.equal(optionsService.options['cursorStyle'], 'bar');
236-
assert.equal(optionsService.options['cursorBlink'], false);
235+
assert.equal(coreService.decPrivateModes.cursorStyle, 'bar');
236+
assert.equal(coreService.decPrivateModes.cursorBlink, false);
237237
});
238238
});
239239
describe('setMode', () => {

src/common/InputHandler.ts

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2714,7 +2714,7 @@ export class InputHandler extends Disposable implements IInputHandler {
27142714

27152715
/**
27162716
* CSI Ps SP q Set cursor style (DECSCUSR, VT520).
2717-
* Ps = 0 -> blinking block.
2717+
* Ps = 0 -> reset to option.
27182718
* Ps = 1 -> blinking block (default).
27192719
* Ps = 2 -> steady block.
27202720
* Ps = 3 -> blinking underline.
@@ -2724,31 +2724,37 @@ export class InputHandler extends Disposable implements IInputHandler {
27242724
*
27252725
* @vt: #Y CSI DECSCUSR "Set Cursor Style" "CSI Ps SP q" "Set cursor style."
27262726
* Supported cursor styles:
2727-
* - empty, 0 or 1: steady block
2728-
* - 2: blink block
2729-
* - 3: steady underline
2730-
* - 4: blink underline
2731-
* - 5: steady bar
2732-
* - 6: blink bar
2727+
* - 0: reset to option
2728+
* - empty, 1: blinking block
2729+
* - 2: steady block
2730+
* - 3: blinking underline
2731+
* - 4: steady underline
2732+
* - 5: blinking bar
2733+
* - 6: steady bar
27332734
*/
27342735
public setCursorStyle(params: IParams): boolean {
2735-
const param = params.params[0] || 1;
2736-
switch (param) {
2737-
case 1:
2738-
case 2:
2739-
this._optionsService.options.cursorStyle = 'block';
2740-
break;
2741-
case 3:
2742-
case 4:
2743-
this._optionsService.options.cursorStyle = 'underline';
2744-
break;
2745-
case 5:
2746-
case 6:
2747-
this._optionsService.options.cursorStyle = 'bar';
2748-
break;
2736+
const param = params.length === 0 ? 1 : params.params[0];
2737+
if (param === 0) {
2738+
this._coreService.decPrivateModes.cursorStyle = undefined;
2739+
this._coreService.decPrivateModes.cursorBlink = undefined;
2740+
} else {
2741+
switch (param) {
2742+
case 1:
2743+
case 2:
2744+
this._coreService.decPrivateModes.cursorStyle = 'block';
2745+
break;
2746+
case 3:
2747+
case 4:
2748+
this._coreService.decPrivateModes.cursorStyle = 'underline';
2749+
break;
2750+
case 5:
2751+
case 6:
2752+
this._coreService.decPrivateModes.cursorStyle = 'bar';
2753+
break;
2754+
}
2755+
const isBlinking = param % 2 === 1;
2756+
this._coreService.decPrivateModes.cursorBlink = isBlinking;
27492757
}
2750-
const isBlinking = param % 2 === 1;
2751-
this._optionsService.options.cursorBlink = isBlinking;
27522758
return true;
27532759
}
27542760

src/common/TestUtils.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ export class MockCoreService implements ICoreService {
8989
applicationCursorKeys: false,
9090
applicationKeypad: false,
9191
bracketedPasteMode: false,
92+
cursorBlink: undefined,
93+
cursorStyle: undefined,
9294
origin: false,
9395
reverseWraparound: false,
9496
sendFocus: false,

src/common/Types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,8 @@ export interface IDecPrivateModes {
268268
applicationCursorKeys: boolean;
269269
applicationKeypad: boolean;
270270
bracketedPasteMode: boolean;
271+
cursorBlink: boolean | undefined;
272+
cursorStyle: CursorStyle | undefined;
271273
origin: boolean;
272274
reverseWraparound: boolean;
273275
sendFocus: boolean;

src/common/services/CoreService.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ const DEFAULT_DEC_PRIVATE_MODES: IDecPrivateModes = Object.freeze({
1717
applicationCursorKeys: false,
1818
applicationKeypad: false,
1919
bracketedPasteMode: false,
20+
cursorBlink: undefined,
21+
cursorStyle: undefined,
2022
origin: false,
2123
reverseWraparound: false,
2224
sendFocus: false,

0 commit comments

Comments
 (0)