Merge pull request #5521 from Tyriar/5314

Add quirks setting to control DECSET/DECRST 12
This commit is contained in:
Daniel Imms
2025-12-28 08:07:47 -08:00
committed by GitHub
6 changed files with 55 additions and 6 deletions
@@ -72,6 +72,7 @@ export class OptionsWindow extends BaseWindow implements IControlWindow {
'linkHandler',
'logger',
'overviewRuler',
'quirks',
'theme',
'windowOptions',
'windowsPty',
+18 -1
View File
@@ -2341,7 +2341,7 @@ describe('InputHandler', () => {
});
it('DEC privates with set/reset semantic', async () => {
// initially reset
const reset = [1, 6, 9, 12, 45, 66, 1000, 1002, 1003, 1004, 1006, 1016, 47, 1047, 1049, 2004, 2026];
const reset = [1, 6, 9, 45, 66, 1000, 1002, 1003, 1004, 1006, 1016, 47, 1047, 1049, 2004, 2026];
for (const mode of reset) {
await inputHandler.parseP(`\x1b[?${mode}$p`);
assert.deepEqual(reportStack.pop(), `\x1b[?${mode};2$y`); // initial reset
@@ -2365,6 +2365,23 @@ describe('InputHandler', () => {
assert.deepEqual(reportStack.pop(), `\x1b[?${mode};1$y`); // again set
}
});
it('DEC privates quirks', async () => {
// Cursor blink
const mode = 12;
await inputHandler.parseP(`\x1b[?${mode}$p`);
assert.deepEqual(reportStack.pop(), `\x1b[?${mode};2$y`); // initial reset
await inputHandler.parseP(`\x1b[?${mode}h`);
await inputHandler.parseP(`\x1b[?${mode}$p`);
assert.deepEqual(reportStack.pop(), `\x1b[?${mode};2$y`); // still reset
optionsService.options.quirks.allowSetCursorBlink = true;
await inputHandler.parseP(`\x1b[?${mode}h`);
await inputHandler.parseP(`\x1b[?${mode}$p`);
assert.deepEqual(reportStack.pop(), `\x1b[?${mode};1$y`); // now active
await inputHandler.parseP(`\x1b[?${mode}l`);
await inputHandler.parseP(`\x1b[?${mode}$p`);
assert.deepEqual(reportStack.pop(), `\x1b[?${mode};2$y`); // now inactive
});
it('DEC privates perma modes', async () => {
// [mode number, state value]
const perma = [[3, 0], [8, 3], [67, 4], [1005, 4], [1015, 4], [1048, 1]];
+8 -4
View File
@@ -1877,7 +1877,7 @@ export class InputHandler extends Disposable implements IInputHandler {
* | 7 | Auto-wrap Mode (DECAWM). | #Y |
* | 8 | Auto-repeat Keys (DECARM). Always on. | #N |
* | 9 | X10 xterm mouse protocol. | #Y |
* | 12 | Start Blinking Cursor. | #Y |
* | 12 | Start Blinking Cursor. | #P[Requires the allowSetCursorBlink quirk option enabled.] |
* | 25 | Show Cursor (DECTCEM). | #Y |
* | 45 | Reverse wrap-around. | #Y |
* | 47 | Use Alternate Screen Buffer. | #Y |
@@ -1930,7 +1930,9 @@ export class InputHandler extends Disposable implements IInputHandler {
this._coreService.decPrivateModes.wraparound = true;
break;
case 12:
this._optionsService.options.cursorBlink = true;
if (this._optionsService.rawOptions.quirks?.allowSetCursorBlink) {
this._optionsService.options.cursorBlink = true;
}
break;
case 45:
this._coreService.decPrivateModes.reverseWraparound = true;
@@ -2125,7 +2127,7 @@ export class InputHandler extends Disposable implements IInputHandler {
* | 7 | No Wraparound Mode (DECAWM). | #Y |
* | 8 | No Auto-repeat Keys (DECARM). | #N |
* | 9 | Don't send Mouse X & Y on button press. | #Y |
* | 12 | Stop Blinking Cursor. | #Y |
* | 12 | Stop Blinking Cursor. | #P[Requires the allowSetCursorBlink quirk option enabled.] |
* | 25 | Hide Cursor (DECTCEM). | #Y |
* | 45 | No reverse wrap-around. | #Y |
* | 47 | Use Normal Screen Buffer. | #Y |
@@ -2171,7 +2173,9 @@ export class InputHandler extends Disposable implements IInputHandler {
this._coreService.decPrivateModes.wraparound = false;
break;
case 12:
this._optionsService.options.cursorBlink = false;
if (this._optionsService.rawOptions.quirks?.allowSetCursorBlink) {
this._optionsService.options.cursorBlink = false;
}
break;
case 45:
this._coreService.decPrivateModes.reverseWraparound = false;
+2 -1
View File
@@ -53,7 +53,8 @@ export const DEFAULT_OPTIONS: Readonly<Required<ITerminalOptions>> = {
convertEol: false,
termName: 'xterm',
cancelEvents: false,
overviewRuler: {}
overviewRuler: {},
quirks: {}
};
const FONT_WEIGHT_OPTIONS: Extract<FontWeight, string>[] = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'];
+5
View File
@@ -262,6 +262,7 @@ export interface ITerminalOptions {
windowOptions?: IWindowOptions;
wordSeparator?: string;
overviewRuler?: IOverviewRulerOptions;
quirks?: ITerminalQuirks;
scrollOnEraseInDisplay?: boolean;
[key: string]: any;
@@ -300,6 +301,10 @@ export interface ITheme {
extendedAnsi?: string[];
}
export interface ITerminalQuirks {
allowSetCursorBlink?: boolean;
}
export const IOscLinkService = createDecorator<IOscLinkService>('OscLinkService');
export interface IOscLinkService {
serviceBrand: undefined;
+21
View File
@@ -197,6 +197,12 @@ declare module '@xterm/xterm' {
*/
minimumContrastRatio?: number;
/**
* Control various quirks features that are either non-standard or standard
* in but generally rejected in modern terminals.
*/
quirks?: ITerminalQuirks;
/**
* Whether to reflow the line containing the cursor when the terminal is
* resized. Defaults to false, because shells usually handle this
@@ -407,6 +413,21 @@ declare module '@xterm/xterm' {
extendedAnsi?: string[];
}
/**
* Control various quirks features that are either non-standard or standard
* in but generally rejected in modern terminals.
*/
export interface ITerminalQuirks {
/**
* Enables support for DECSET 12 and DECRST 12 which controls cursor blink.
* Programs such as `vim` may use this to set the cursor blink state but may
* not change it back when exiting. Generally the terminal emulator should
* be in control of whether the cursor blinks or not and the application in
* modern terminals. Note that DECRQM works regardless of this option.
*/
allowSetCursorBlink?: boolean;
}
/**
* Pty information for Windows.
*/