Merge branch 'master' into strict_demo

This commit is contained in:
Daniel Imms
2026-01-31 09:24:47 -08:00
committed by GitHub
10 changed files with 117 additions and 5 deletions
+25 -1
View File
@@ -42,7 +42,7 @@ import { SelectionService } from 'browser/services/SelectionService';
import { ICharSizeService, ICharacterJoinerService, ICoreBrowserService, IKeyboardService, ILinkProviderService, IMouseService, IRenderService, ISelectionService, IThemeService } from 'browser/services/Services';
import { ThemeService } from 'browser/services/ThemeService';
import { KeyboardService } from 'browser/services/KeyboardService';
import { channels, color } from 'common/Color';
import { channels, color, rgb } from 'common/Color';
import { CoreTerminal } from 'common/CoreTerminal';
import * as Browser from 'common/Platform';
import { ColorRequestType, CoreMouseAction, CoreMouseButton, CoreMouseEventType, IColorEvent, ITerminalOptions, KeyboardResultType, SpecialColorIndex } from 'common/Types';
@@ -252,6 +252,20 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
}
}
/**
* Reports the current color scheme (dark or light) based on the relative luminance
* of the background and foreground theme colors.
* Sends CSI ? 997 ; 1 n for dark mode or CSI ? 997 ; 2 n for light mode.
*/
private _reportColorScheme(): void {
if (!this._themeService) return;
const bgLuminance = rgb.relativeLuminance(this._themeService.colors.background.rgba >> 8);
const fgLuminance = rgb.relativeLuminance(this._themeService.colors.foreground.rgba >> 8);
// Dark mode = background is darker than foreground (lower luminance)
const colorSchemeMode = bgLuminance < fgLuminance ? 1 : 2;
this.coreService.triggerDataEvent(`${C0.ESC}[?997;${colorSchemeMode}n`);
}
protected _setup(): void {
super._setup();
@@ -495,6 +509,16 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
this._themeService = this._instantiationService.createInstance(ThemeService);
this._instantiationService.setService(IThemeService, this._themeService);
// CSI ? 996 n - color scheme query (https://contour-terminal.org/vt-extensions/color-palette-update-notifications/)
this._register(this._inputHandler.onRequestColorSchemeQuery(() => this._reportColorScheme()));
// Emit unsolicited color scheme notification on theme change when DECSET 2031 is enabled
this._register(this._themeService.onChangeColors(() => {
if (this.coreService.decPrivateModes.colorSchemeUpdates) {
this._reportColorScheme();
}
}));
this._characterJoinerService = this._instantiationService.createInstance(CharacterJoinerService);
this._instantiationService.setService(ICharacterJoinerService, this._characterJoinerService);
+20
View File
@@ -269,6 +269,26 @@ describe('InputHandler', () => {
inputHandler.resetModePrivate(Params.fromArray([2004]));
assert.equal(coreService.decPrivateModes.bracketedPasteMode, false);
});
it('should toggle colorSchemeUpdates (DECSET 2031)', () => {
const coreService = new MockCoreService();
const optionsService = new MockOptionsService();
const inputHandler = new TestInputHandler(new MockBufferService(80, 30), new MockCharsetService(), coreService, new MockLogService(), optionsService, new MockOscLinkService(), new MockCoreMouseService(), new MockUnicodeService());
// Set color scheme updates mode (default colorSchemeQuery=true)
inputHandler.setModePrivate(Params.fromArray([2031]));
assert.equal(coreService.decPrivateModes.colorSchemeUpdates, true);
// Reset color scheme updates mode
inputHandler.resetModePrivate(Params.fromArray([2031]));
assert.equal(coreService.decPrivateModes.colorSchemeUpdates, false);
});
it('should not toggle colorSchemeUpdates when colorSchemeQuery is disabled', () => {
const coreService = new MockCoreService();
const optionsService = new MockOptionsService();
optionsService.rawOptions.vtExtensions = { colorSchemeQuery: false };
const inputHandler = new TestInputHandler(new MockBufferService(80, 30), new MockCharsetService(), coreService, new MockLogService(), optionsService, new MockOscLinkService(), new MockCoreMouseService(), new MockUnicodeService());
// Attempt to set color scheme updates mode
inputHandler.setModePrivate(Params.fromArray([2031]));
assert.equal(coreService.decPrivateModes.colorSchemeUpdates, false);
});
});
describe('regression tests', function (): void {
function termContent(bufferService: IBufferService, trim: boolean): string[] {
+18
View File
@@ -160,6 +160,8 @@ export class InputHandler extends Disposable implements IInputHandler {
public readonly onTitleChange = this._onTitleChange.event;
private readonly _onColor = this._register(new Emitter<IColorEvent>());
public readonly onColor = this._onColor.event;
private readonly _onRequestColorSchemeQuery = this._register(new Emitter<void>());
public readonly onRequestColorSchemeQuery = this._onRequestColorSchemeQuery.event;
private _parseStack: IParseStack = {
paused: false,
@@ -2034,6 +2036,11 @@ export class InputHandler extends Disposable implements IInputHandler {
case 2026: // synchronized output (https://github.com/contour-terminal/vt-extensions/blob/master/synchronized-output.md)
this._coreService.decPrivateModes.synchronizedOutput = true;
break;
case 2031: // color scheme updates (https://contour-terminal.org/vt-extensions/color-palette-update-notifications/)
if (this._optionsService.rawOptions.vtExtensions?.colorSchemeQuery ?? true) {
this._coreService.decPrivateModes.colorSchemeUpdates = true;
}
break;
case 9001: // win32-input-mode (https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md)
if (this._optionsService.rawOptions.vtExtensions?.win32InputMode) {
this._coreService.decPrivateModes.win32InputMode = true;
@@ -2279,6 +2286,11 @@ export class InputHandler extends Disposable implements IInputHandler {
this._coreService.decPrivateModes.synchronizedOutput = false;
this._onRequestRefreshRows.fire(undefined);
break;
case 2031: // color scheme updates (https://contour-terminal.org/vt-extensions/color-palette-update-notifications/)
if (this._optionsService.rawOptions.vtExtensions?.colorSchemeQuery ?? true) {
this._coreService.decPrivateModes.colorSchemeUpdates = false;
}
break;
case 9001: // win32-input-mode
if (this._optionsService.rawOptions.vtExtensions?.win32InputMode) {
this._coreService.decPrivateModes.win32InputMode = false;
@@ -2782,6 +2794,12 @@ export class InputHandler extends Disposable implements IInputHandler {
// no dec locator/mouse
// this.handler(C0.ESC + '[?50n');
break;
case 996:
// color scheme query (https://contour-terminal.org/vt-extensions/color-palette-update-notifications/)
if (this._optionsService.rawOptions.vtExtensions?.colorSchemeQuery ?? true) {
this._onRequestColorSchemeQuery.fire();
}
break;
}
return true;
}
+1
View File
@@ -106,6 +106,7 @@ export class MockCoreService implements ICoreService {
applicationCursorKeys: false,
applicationKeypad: false,
bracketedPasteMode: false,
colorSchemeUpdates: false,
cursorBlink: undefined,
cursorStyle: undefined,
origin: false,
+1
View File
@@ -269,6 +269,7 @@ export interface IDecPrivateModes {
applicationCursorKeys: boolean;
applicationKeypad: boolean;
bracketedPasteMode: boolean;
colorSchemeUpdates: boolean;
cursorBlink: boolean | undefined;
cursorStyle: CursorStyle | undefined;
origin: boolean;
+1
View File
@@ -17,6 +17,7 @@ const DEFAULT_DEC_PRIVATE_MODES: IDecPrivateModes = Object.freeze({
applicationCursorKeys: false,
applicationKeypad: false,
bracketedPasteMode: false,
colorSchemeUpdates: false,
cursorBlink: undefined,
cursorStyle: undefined,
origin: false,
+1
View File
@@ -313,6 +313,7 @@ export interface IVtExtensions {
kittyKeyboard?: boolean;
kittySgrBoldFaintControl?: boolean;
win32InputMode?: boolean;
colorSchemeQuery?: boolean;
}
export const IOscLinkService = createDecorator<IOscLinkService>('OscLinkService');
+24 -2
View File
@@ -1234,8 +1234,30 @@ test.describe('InputHandler Integration Tests', () => {
test.skip('CSI > Ps n - Disable key modifier options, xterm', () => {
// TODO: Implement
});
test.describe.skip('CSI ? Ps n - DSR: Device Status Report (DEC-specific).', () => {
// TODO: Implement
test.describe('CSI ? Ps n - DECDSR: Device Status Report (DEC-specific)', () => {
test('Color Scheme Query - CSI ? 996 n (dark theme)', async () => {
// Default theme has dark background (#000000) and light foreground (#ffffff)
await ctx.proxy.write('\x1b[?996n');
deepStrictEqual(recordedData, ['\x1b[?997;1n']);
});
test('Color Scheme Query - CSI ? 996 n (light theme)', async () => {
recordedData.length = 0;
await ctx.page.evaluate(`window.term.options.theme = { background: '#ffffff', foreground: '#000000' }`);
await ctx.proxy.write('\x1b[?996n');
deepStrictEqual(recordedData, ['\x1b[?997;2n']);
// Restore default theme
await ctx.page.evaluate(`window.term.options.theme = { background: '#000000', foreground: '#ffffff' }`);
});
test('Color Scheme Query disabled via vtExtensions.colorSchemeQuery', async () => {
recordedData.length = 0;
await ctx.page.evaluate(`window.term.options.vtExtensions = { colorSchemeQuery: false }`);
await ctx.proxy.write('\x1b[?996n');
deepStrictEqual(recordedData, []);
// Re-enable
await ctx.page.evaluate(`window.term.options.vtExtensions = { colorSchemeQuery: true }`);
});
});
test.skip('CSI > Ps p - XTSMPOINTER: Set resource value pointerMode, xterm', () => {
// TODO: Implement
+13 -1
View File
@@ -233,7 +233,7 @@ declare module '@xterm/headless' {
windowOptions?: IWindowOptions;
/**
* Enable various VT extensions. All extensions are disabled by default.
* Enable various VT extensions.
*/
vtExtensions?: IVtExtensions;
}
@@ -356,6 +356,18 @@ declare module '@xterm/headless' {
* [0]: https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md
*/
win32InputMode?: boolean;
/**
* Whether [color scheme query and notification][0] (`CSI ? 996 n` and
* `DECSET 2031`) is enabled. When enabled, the terminal will respond to
* color scheme queries with `CSI ? 997 ; 1 n` (dark) or `CSI ? 997 ; 2 n`
* (light) based on the relative luminance of the background and foreground
* theme colors. Programs can enable unsolicited notifications via
* `CSI ? 2031 h`. The default is true.
*
* [0]: https://contour-terminal.org/vt-extensions/color-palette-update-notifications/
*/
colorSchemeQuery?: boolean;
}
/**
+13 -1
View File
@@ -291,7 +291,7 @@ declare module '@xterm/xterm' {
theme?: ITheme;
/**
* Enable various VT extensions. All extensions are disabled by default.
* Enable various VT extensions.
*/
vtExtensions?: IVtExtensions;
@@ -473,6 +473,18 @@ declare module '@xterm/xterm' {
* [0]: https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md
*/
win32InputMode?: boolean;
/**
* Whether [color scheme query and notification][0] (`CSI ? 996 n` and
* `DECSET 2031`) is enabled. When enabled, the terminal will respond to
* color scheme queries with `CSI ? 997 ; 1 n` (dark) or `CSI ? 997 ; 2 n`
* (light) based on the relative luminance of the background and foreground
* theme colors. Programs can enable unsolicited notifications via
* `CSI ? 2031 h`. The default is true.
*
* [0]: https://contour-terminal.org/vt-extensions/color-palette-update-notifications/
*/
colorSchemeQuery?: boolean;
}
/**