From ca5a6813636ffdf3439158e08561ea842ba5c0b4 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sun, 28 Dec 2025 07:34:55 -0800 Subject: [PATCH] Add quirks setting to control DECSET/DECRST 12 Fixes #5314 --- src/common/InputHandler.ts | 12 ++++++++---- src/common/services/OptionsService.ts | 3 ++- src/common/services/Services.ts | 5 +++++ typings/xterm.d.ts | 21 +++++++++++++++++++++ 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/common/InputHandler.ts b/src/common/InputHandler.ts index e6231725..99ae6252 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -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; diff --git a/src/common/services/OptionsService.ts b/src/common/services/OptionsService.ts index b33a0856..54c3db23 100644 --- a/src/common/services/OptionsService.ts +++ b/src/common/services/OptionsService.ts @@ -53,7 +53,8 @@ export const DEFAULT_OPTIONS: Readonly> = { convertEol: false, termName: 'xterm', cancelEvents: false, - overviewRuler: {} + overviewRuler: {}, + quirks: {} }; const FONT_WEIGHT_OPTIONS: Extract[] = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900']; diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index 849abcd5..a73d99f3 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -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('OscLinkService'); export interface IOscLinkService { serviceBrand: undefined; diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 8e34a00e..a5d82601 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -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 @@ -406,6 +412,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. */