2023-09-02 07:19:32 -07:00
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { test } from '@playwright/test' ;
2023-09-02 08:18:02 -07:00
import { deepStrictEqual , ok } from 'assert' ;
import { ITestContext , createTestContext , openTerminal , pollFor } from './TestUtils' ;
2023-09-02 07:19:32 -07:00
let ctx : ITestContext ;
test . beforeAll ( async ({ browser }) => {
ctx = await createTestContext ( browser );
await openTerminal ( ctx );
});
test . afterAll ( async () => await ctx . page . close ());
2023-09-02 09:11:15 -07:00
test . describe ( 'InputHandler Integration Tests' , () => {
2025-12-30 05:27:28 -08:00
let recordedData : string [];
let recordDataDisposable : { dispose : () => void };
test . beforeAll ( async () => {
recordedData = [];
recordDataDisposable = ctx . proxy . onData ( d => recordedData . push ( d ));
});
test . afterAll ( async () => {
recordDataDisposable . dispose ();
});
test . beforeEach ( async () => {
recordedData . length = 0 ;
2025-12-30 06:59:27 -08:00
await ctx . proxy . resize ( 80 , 24 );
2025-12-30 05:27:28 -08:00
});
2023-09-02 07:19:32 -07:00
test . describe ( 'CSI' , () => {
test . beforeEach ( async () => await ctx . proxy . reset ());
test ( 'CSI Ps @ - ICH: Insert Ps (Blank) Character(s) (default = 1)' , async () => {
2025-12-30 05:27:28 -08:00
// Default
await ctx . proxy . write ( 'foo\x1b[3D\x1b[@\n\r' );
// Explicit
await ctx . proxy . write ( 'bar\x1b[3D\x1b[4@' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 2 ), [ ' foo' , ' bar' ]);
});
2025-12-30 05:04:20 -08:00
test ( 'CSI Ps SP @ - SL: Shift left Ps columns(s) (default = 1), ECMA-48' , async () => {
// Default
await ctx . proxy . write ( 'abcdefg\x1b[ @' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'bcdefg' ]);
// Explicit
await ctx . proxy . reset ();
await ctx . proxy . write ( 'abcdefg\x1b[3 @' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'defg' ]);
2023-09-02 07:19:32 -07:00
});
test ( 'CSI Ps A - CUU: Cursor Up Ps Times (default = 1)' , async () => {
2025-12-30 05:27:28 -08:00
// Default
await ctx . proxy . write ( '\n\n\n\n\x1b[Aa' );
// Explicit
await ctx . proxy . write ( '\x1b[2Ab' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 4 ), [ '' , ' b' , '' , 'a' ]);
});
test ( 'CSI Ps B - CUD: Cursor Down Ps Times (default = 1)' , async () => {
2025-12-30 05:27:28 -08:00
// Default
await ctx . proxy . write ( '\x1b[Ba' );
// Explicit
await ctx . proxy . write ( '\x1b[2Bb' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 4 ), [ '' , 'a' , '' , ' b' ]);
});
test ( 'CSI Ps C - CUF: Cursor Forward Ps Times (default = 1)' , async () => {
2025-12-30 05:27:28 -08:00
// Default
await ctx . proxy . write ( '\x1b[Ca' );
// Explicit
await ctx . proxy . write ( '\x1b[2Cb' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ ' a b' ]);
});
test ( 'CSI Ps D - CUB: Cursor Backward Ps Times (default = 1)' , async () => {
2025-12-30 05:27:28 -08:00
// Default
await ctx . proxy . write ( 'foo\x1b[Da' );
// Explicit
await ctx . proxy . write ( '\x1b[2Db' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'fba' ]);
});
test ( 'CSI Ps E - CNL: Cursor Next Line Ps Times (default = 1)' , async () => {
2025-12-30 05:27:28 -08:00
// Default
await ctx . proxy . write ( '\x1b[Ea' );
// Explicit
await ctx . proxy . write ( '\x1b[2Eb' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 4 ), [ '' , 'a' , '' , 'b' ]);
});
test ( 'CSI Ps F - CPL: Cursor Preceding Line Ps Times (default = 1)' , async () => {
2025-12-30 05:27:28 -08:00
// Default
await ctx . proxy . write ( '\n\n\n\n\x1b[Fa' );
// Explicit
await ctx . proxy . write ( '\x1b[2Fb' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 5 ), [ '' , 'b' , '' , 'a' , '' ]);
});
test ( 'CSI Ps G - CHA: Cursor Character Absolute [column] (default = [row,1])' , async () => {
2025-12-30 05:27:28 -08:00
// Default
await ctx . proxy . write ( 'foo\x1b[Ga' );
// Explicit
await ctx . proxy . write ( '\x1b[10Gb' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'aoo b' ]);
});
test ( 'CSI Ps ; Ps H - CUP: Cursor Position [row;column] (default = [1,1])' , async () => {
2025-12-30 05:27:28 -08:00
// Default
await ctx . proxy . write ( 'foo\x1b[Ha' );
// Explicit
await ctx . proxy . write ( '\x1b[3;3Hb' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 3 ), [ 'aoo' , '' , ' b' ]);
});
test ( 'CSI Ps I - CHT: Cursor Forward Tabulation Ps tab stops (default = 1)' , async () => {
2025-12-30 05:27:28 -08:00
// Default
await ctx . proxy . write ( '\x1b[Ia' );
// Explicit
await ctx . proxy . write ( '\n\r\x1b[2Ib' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 2 ), [ ' a' , ' b' ]);
});
test ( 'CSI Ps J - ED: Erase in Display, VT100' , async () => {
2025-12-30 05:27:28 -08:00
const fixture = 'abc\n\rdef\n\rghi\x1b[2;2H' ;
// Default: Erase Below
await ctx . proxy . resize ( 5 , 5 );
await ctx . proxy . write ( fixture + '\x1b[J' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 3 ), [ 'abc' , 'd' , '' ]);
2025-12-30 05:27:28 -08:00
// 0: Erase Below
await ctx . proxy . reset ();
await ctx . proxy . write ( fixture + '\x1b[0J' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 3 ), [ 'abc' , 'd' , '' ]);
2025-12-30 05:27:28 -08:00
// 1: Erase Above
await ctx . proxy . reset ();
await ctx . proxy . write ( fixture + '\x1b[1J' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 3 ), [ '' , ' f' , 'ghi' ]);
2025-12-30 05:27:28 -08:00
// 2: Erase Saved Lines (scrollback)
await ctx . proxy . reset ();
await ctx . proxy . write ( '1\n2\n3\n4\n5' + fixture + '\x1b[3J' );
await pollFor ( ctx . page , () => ctx . proxy . buffer . active . length , 5 );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 5 ), [ ' 4' , ' 5' , 'abc' , 'def' , 'ghi' ]);
});
test ( 'CSI ? Ps J - DECSED: Erase in Display, VT220' , async () => {
2025-12-30 05:27:28 -08:00
const fixture = 'abc\n\rdef\n\rghi\x1b[2;2H' ;
// Default: Erase Below
await ctx . proxy . resize ( 5 , 5 );
await ctx . proxy . write ( fixture + '\x1b[?J' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 3 ), [ 'abc' , 'd' , '' ]);
2025-12-30 05:27:28 -08:00
// 0: Erase Below
await ctx . proxy . reset ();
await ctx . proxy . write ( fixture + '\x1b[?0J' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 3 ), [ 'abc' , 'd' , '' ]);
2025-12-30 05:27:28 -08:00
// 1: Erase Above
await ctx . proxy . reset ();
await ctx . proxy . write ( fixture + '\x1b[?1J' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 3 ), [ '' , ' f' , 'ghi' ]);
2025-12-30 05:27:28 -08:00
// 2: Erase Saved Lines (scrollback)
await ctx . proxy . reset ();
await ctx . proxy . write ( '1\n2\n3\n4\n5' + fixture + '\x1b[?3J' );
await pollFor ( ctx . page , () => ctx . proxy . buffer . active . length , 5 );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 5 ), [ ' 4' , ' 5' , 'abc' , 'def' , 'ghi' ]);
});
2025-12-30 06:48:28 -08:00
test ( 'CSI Ps K - EL: Erase in Line, VT100' , async () => {
const fixture = 'abcde\x1b[1;3H' ;
// Default: Erase to Right
await ctx . proxy . write ( fixture + '\x1b[K' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'ab' ]);
// 0: Erase to Right
await ctx . proxy . reset ();
await ctx . proxy . write ( fixture + '\x1b[0K' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'ab' ]);
// 1: Erase to Left
await ctx . proxy . reset ();
await ctx . proxy . write ( fixture + '\x1b[1K' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ ' de' ]);
// 2: Erase All
await ctx . proxy . reset ();
await ctx . proxy . write ( fixture + '\x1b[2K' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ '' ]);
2023-09-02 07:19:32 -07:00
});
2025-12-30 06:48:28 -08:00
test ( 'CSI ? Ps K - DECSEL: Erase in Line, VT220' , async () => {
const fixture = 'abcde\x1b[1;3H' ;
// Default: Erase to Right
await ctx . proxy . write ( fixture + '\x1b[?K' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'ab' ]);
// 0: Erase to Right
await ctx . proxy . reset ();
await ctx . proxy . write ( fixture + '\x1b[?0K' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'ab' ]);
// 1: Erase to Left
await ctx . proxy . reset ();
await ctx . proxy . write ( fixture + '\x1b[?1K' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ ' de' ]);
// 2: Erase All
await ctx . proxy . reset ();
await ctx . proxy . write ( fixture + '\x1b[?2K' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ '' ]);
2023-09-02 07:19:32 -07:00
});
test ( 'CSI Ps L - IL: Insert Ps Line(s) (default = 1)' , async () => {
2025-12-30 05:27:28 -08:00
// Default
await ctx . proxy . write ( 'foo\x1b[La' );
// Explicit
await ctx . proxy . write ( '\x1b[2Lb' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 4 ), [ 'b' , '' , 'a' , 'foo' ]);
});
test ( 'CSI Ps M - DL: Delete Ps Line(s) (default = 1)' , async () => {
2025-12-30 05:27:28 -08:00
// Default
await ctx . proxy . write ( 'a\nb\x1b[1F\x1b[M' );
// Explicit
await ctx . proxy . write ( '\x1b[1Ed\ne\nf\x1b[2F\x1b[2M' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 5 ), [ ' b' , ' f' , '' , '' , '' ]);
});
test ( 'CSI Ps P - DCH: Delete Ps Character(s) (default = 1)' , async () => {
2025-12-30 05:27:28 -08:00
// Default
await ctx . proxy . write ( 'abc\x1b[1;1H\x1b[P' );
// Explicit
await ctx . proxy . write ( '\n\rdef\x1b[2;1H\x1b[2P' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 2 ), [ 'bc' , 'f' ]);
});
test . skip ( 'CSI Pm # P - XTPUSHCOLORS: Push current dynamic- and ANSI-palette colors onto stack, xterm' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Pm # Q - XTPOPCOLORS: Pop stack to set dynamic- and ANSI-palette colors, xterm' , async () => {
// TODO: Implement
});
test . skip ( 'CSI # R - XTREPORTCOLORS: Report the current entry on the palette stack, and the number of palettes stored on the stack, using the same form as XTPOPCOLOR (default = 0), xterm' , async () => {
// TODO: Implement
});
2025-12-30 06:48:28 -08:00
test ( 'CSI Ps S - SU: Scroll up Ps lines (default = 1), VT420, ECMA-48' , async () => {
await ctx . proxy . write ( '1\r\n2\r\n3\r\n4\r\n5' );
await pollFor ( ctx . page , () => getLinesAsArray ( 5 ), [ '1' , '2' , '3' , '4' , '5' ]);
await ctx . proxy . write ( '\x1b[S' );
await pollFor ( ctx . page , () => getLinesAsArray ( 5 ), [ '2' , '3' , '4' , '5' , '' ]);
await ctx . proxy . reset ();
await ctx . proxy . write ( '1\r\n2\r\n3\r\n4\r\n5' );
await ctx . proxy . write ( '\x1b[2S' );
await pollFor ( ctx . page , () => getLinesAsArray ( 5 ), [ '3' , '4' , '5' , '' , '' ]);
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
// This is intentionally not implemented here are image support lives within an addon
// test.skip('CSI ? Pi ; Pa ; Pv S - XTSMGRAPHICS: Set or request graphics attribute, xterm', async () => {
// });
2025-12-30 06:48:28 -08:00
test ( 'CSI Ps T - SD: Scroll down Ps lines (default = 1), VT420' , async () => {
await ctx . proxy . write ( '1\r\n2\r\n3\r\n4\r\n5' );
await pollFor ( ctx . page , () => getLinesAsArray ( 5 ), [ '1' , '2' , '3' , '4' , '5' ]);
await ctx . proxy . write ( '\x1b[T' );
await pollFor ( ctx . page , () => getLinesAsArray ( 5 ), [ '' , '1' , '2' , '3' , '4' ]);
await ctx . proxy . reset ();
await ctx . proxy . write ( '1\r\n2\r\n3\r\n4\r\n5' );
await ctx . proxy . write ( '\x1b[2T' );
await pollFor ( ctx . page , () => getLinesAsArray ( 5 ), [ '' , '' , '1' , '2' , '3' ]);
2023-09-02 07:19:32 -07:00
});
test . skip ( 'CSI Ps ; Ps ; Ps ; Ps ; Ps T - XTHIMOUSE: Initiate highlight mouse tracking (XTHIMOUSE), xterm' , async () => {
// TODO: Implement
});
test . skip ( 'CSI > Pm T - XTRMTITLE: Reset title mode features to default value, xterm' , async () => {
// TODO: Implement
});
2025-12-30 06:59:27 -08:00
test ( 'CSI Ps X - ECH: Erase Ps Character(s) (default = 1)' , async () => {
2025-12-30 06:48:28 -08:00
await ctx . proxy . write ( 'abcdef\x1b[1;1H\x1b[X' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ ' bcdef' ]);
await ctx . proxy . reset ();
await ctx . proxy . write ( 'abcdef\x1b[1;1H\x1b[3X' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ ' def' ]);
2023-09-02 07:19:32 -07:00
});
2025-12-30 06:59:27 -08:00
test ( 'CSI Ps Z - CBT: Cursor Backward Tabulation Ps tab stops (default = 1)' , async () => {
2025-12-30 06:48:28 -08:00
await ctx . proxy . write ( '\x1b[17Ga\x1b[17G\x1b[Zb' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ ' b a' ]);
2023-09-02 07:19:32 -07:00
});
2025-12-30 06:59:27 -08:00
test ( 'CSI Ps ^ - SD: Scroll down Ps lines (default = 1) (SD), ECMA-48' , async () => {
2025-12-30 06:48:28 -08:00
await ctx . proxy . write ( '1\r\n2\r\n3\r\n4\r\n5' );
await pollFor ( ctx . page , () => getLinesAsArray ( 5 ), [ '1' , '2' , '3' , '4' , '5' ]);
await ctx . proxy . write ( '\x1b[^' );
await pollFor ( ctx . page , () => getLinesAsArray ( 5 ), [ '' , '1' , '2' , '3' , '4' ]);
await ctx . proxy . reset ();
await ctx . proxy . write ( '1\r\n2\r\n3\r\n4\r\n5' );
await ctx . proxy . write ( '\x1b[2^' );
await pollFor ( ctx . page , () => getLinesAsArray ( 5 ), [ '' , '' , '1' , '2' , '3' ]);
2023-09-02 07:19:32 -07:00
});
2025-12-30 06:48:28 -08:00
test ( 'CSI Ps ` - HPA: Character Position Absolute [column] (default = [row,1])' , async () => {
// Default
await ctx . proxy . write ( 'foo\x1b[`a' );
// Explicit
await ctx . proxy . write ( '\x1b[10`b' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'aoo b' ]);
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'CSI Ps a - HPR: Character Position Relative (default = [row,col+1])' , async () => {
await ctx . proxy . write ( 'a\x1b[2aB' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'a B' ]);
2023-09-02 07:19:32 -07:00
});
test ( 'CSI Ps b - REP: Repeat preceding character, ECMA48' , async () => {
// default to 1
2025-12-30 05:27:28 -08:00
await ctx . proxy . resize ( 10 , 10 );
await ctx . proxy . write ( '#\x1b[b' );
await ctx . proxy . writeln ( '' );
await ctx . proxy . write ( '#\x1b[0b' );
await ctx . proxy . writeln ( '' );
await ctx . proxy . write ( '#\x1b[1b' );
await ctx . proxy . writeln ( '' );
await ctx . proxy . write ( '#\x1b[5b' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 4 ), [ '##' , '##' , '##' , '######' ]);
await pollFor ( ctx . page , () => getCursor (), { col : 6 , row : 3 });
2023-09-06 22:11:46 -07:00
// repeat on fullwidth chars
2025-12-30 05:27:28 -08:00
await ctx . proxy . reset ();
await ctx . proxy . write ( 'ï¿¥\x1b[8b' );
2023-09-07 09:49:37 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ '¥¥¥¥¥' ]);
2023-09-06 22:11:46 -07:00
// change from xterm: repeat grapheme cluster
2025-12-30 05:27:28 -08:00
await ctx . proxy . reset ();
await ctx . proxy . write ( 'e\u0301\x1b[2b' );
2023-09-06 22:11:46 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'e\u0301e\u0301e\u0301' ]);
2023-09-02 07:19:32 -07:00
// should wrap correctly
2025-12-30 05:27:28 -08:00
await ctx . proxy . reset ();
await ctx . proxy . write ( '#\x1b[15b' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 2 ), [ '##########' , '######' ]);
2025-12-30 05:27:28 -08:00
// disable wrap around
await ctx . proxy . reset ();
await ctx . proxy . write ( '\x1b[?7l' );
await ctx . proxy . write ( '#\x1b[15b' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 2 ), [ '##########' , '' ]);
// any successful sequence should reset REP
2025-12-30 05:27:28 -08:00
await ctx . proxy . reset ();
await ctx . proxy . write ( '\x1b[?7h' ); // re-enable wrap around
await ctx . proxy . write ( '#\n\x1b[3b' );
await ctx . proxy . write ( '#\r\x1b[3b' );
await ctx . proxy . writeln ( '' );
await ctx . proxy . write ( 'abcdefg\x1b[3D\x1b[10b#\x1b[3b' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getLinesAsArray ( 3 ), [ '#' , ' #' , 'abcd####' ]);
});
2026-01-31 21:05:36 -08:00
test ( 'CSI Ps c - ' , async () => {
await ctx . proxy . write ( '\x1b[c' );
await pollFor ( ctx . page , () => recordedData , [ '\x1b[?1;2c' ]);
2023-09-02 07:19:32 -07:00
});
test . skip ( 'CSI = Ps c - ' , async () => {
// TODO: Implement
});
2026-01-31 21:05:36 -08:00
test ( 'CSI > Ps c - ' , async () => {
await ctx . proxy . write ( '\x1b[>c' );
await pollFor ( ctx . page , () => recordedData , [ '\x1b[>0;276;0c' ]);
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'CSI Ps d - VPA: Line Position Absolute [row] (default = [1,column])' , async () => {
// Default
await ctx . proxy . write ( '\n\n\n \x1b[da' );
// Explicit
await ctx . proxy . write ( '\x1b[2d b' );
await pollFor ( ctx . page , () => getLinesAsArray ( 4 ), [ ' a' , ' b' , '' , ' ' ]);
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'CSI Ps e - VPR: Line Position Relative (default = 1)' , async () => {
// Default
await ctx . proxy . write ( '\x1b[ea' );
// Explicit
await ctx . proxy . write ( '\x1b[2eb' );
await pollFor ( ctx . page , () => getLinesAsArray ( 4 ), [ '' , 'a' , '' , ' b' ]);
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'CSI Ps ; Ps f - HVP: Horizontal and Vertical Position [row;column] (default = [1,1])' , async () => {
// Default
await ctx . proxy . write ( 'foo\x1b[fa' );
// Explicit
await ctx . proxy . write ( '\x1b[3;3fb' );
await pollFor ( ctx . page , () => getLinesAsArray ( 3 ), [ 'aoo' , '' , ' b' ]);
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'CSI Ps g - TBC: Tab Clear (default = 0)' , async () => {
// Default: Clear tab stop at cursor position
// Move to column 9 (first tab stop), clear it, go back to column 1, tab should skip to column 17
await ctx . proxy . write ( '\x1b[9G\x1b[g\x1b[1G\ta' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ ' a' ]);
// Ps=3: Clear all tab stops
await ctx . proxy . reset ();
await ctx . proxy . write ( '\x1b[3g\ta' );
// With all tabs cleared, tab moves to end of line
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ ' a' ]);
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'CSI Ps h - SM: Set Mode' , async () => {
await ctx . proxy . write ( '\x1b[4h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). insertMode , true );
await ctx . proxy . write ( '\x1b[20h' );
await pollFor ( ctx . page , async () => await ctx . proxy . getOption ( 'convertEol' ), true );
2023-09-02 07:19:32 -07:00
});
test . describe ( 'CSI ? Pm h - DECSET: Private Mode Set' , () => {
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 - Application Cursor Keys (DECCKM), VT100' , async () => {
await ctx . proxy . write ( '\x1b[?1h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). applicationCursorKeysMode , true );
recordedData . length = 0 ;
await ctx . proxy . focus ();
await ctx . page . keyboard . press ( 'ArrowUp' );
await pollFor ( ctx . page , () => recordedData , [ '\x1bOA' ]);
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 2 - Designate USASCII for character sets G0-G3 (DECANM), VT100, and set VT100 mode' , async () => {
await ctx . proxy . write ( '\x1b(0q\x1b[?2hq' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ '─q' ]);
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 3 - 132 Column Mode (DECCOLM), VT100' , async () => {
const windowOptions = await ctx . proxy . getOption ( 'windowOptions' );
await ctx . proxy . setOption ( 'windowOptions' , { ... windowOptions , setWinLines : true });
await ctx . proxy . write ( '\x1b[?3h' );
await pollFor ( ctx . page , async () => await ctx . proxy . cols , 132 );
await ctx . proxy . resize ( 80 , 24 );
await ctx . proxy . setOption ( 'windowOptions' , windowOptions );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 - Smooth (Slow) Scroll (DECSCLM), VT100' , async () => {
await assertNoModeChange ( '\x1b[?4h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 5 - Reverse Video (DECSCNM), VT100' , async () => {
await assertNoModeChange ( '\x1b[?5h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 6 - Origin Mode (DECOM), VT100' , async () => {
await ctx . proxy . write ( '\x1b[?6h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). originMode , true );
await pollFor ( ctx . page , () => getCursor (), { col : 0 , row : 0 });
await ctx . proxy . write ( '\x1b[2;3r' );
await ctx . proxy . write ( '\x1b[1;1HX' );
await pollFor ( ctx . page , () => getLinesAsArray ( 3 ), [ '' , 'X' , '' ]);
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 7 - Auto-Wrap Mode (DECAWM), VT100' , async () => {
await ctx . proxy . resize ( 5 , 2 );
await ctx . proxy . write ( '\x1b[?7h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). wraparoundMode , true );
await ctx . proxy . write ( '12345X' );
await pollFor ( ctx . page , () => getLinesAsArray ( 2 ), [ '12345' , 'X' ]);
await ctx . proxy . reset ();
await ctx . proxy . write ( '\x1b[?7l' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). wraparoundMode , false );
await ctx . proxy . write ( '12345X' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ '1234X' ]);
await ctx . proxy . resize ( 80 , 24 );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 8 - Auto-Repeat Keys (DECARM), VT100' , async () => {
await assertNoModeChange ( '\x1b[?8h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 9 - Send Mouse X & Y on button press' , async () => {
const selectionBefore = await dragSelection ();
ok ( selectionBefore > 0 );
await ctx . proxy . write ( '\x1b[?9h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). mouseTrackingMode , 'x10' );
const selectionAfter = await dragSelection ();
ok ( selectionAfter === 0 );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 - Show toolbar (rxvt)' , async () => {
await assertNoModeChange ( '\x1b[?10h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 21:05:36 -08:00
test ( 'Ps = 1 2 - Start blinking cursor (AT&T 610)' , async () => {
const previousQuirks = await ctx . proxy . getOption ( 'quirks' );
const previousCursorBlink = await ctx . proxy . getOption ( 'cursorBlink' );
await ctx . proxy . setOption ( 'quirks' , { ...( previousQuirks ?? {}), allowSetCursorBlink : true });
await ctx . proxy . write ( '\x1b[?12h' );
await pollFor ( ctx . page , async () => await ctx . proxy . getOption ( 'cursorBlink' ), true );
await ctx . proxy . setOption ( 'quirks' , previousQuirks );
await ctx . proxy . setOption ( 'cursorBlink' , previousCursorBlink );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 3 - Start blinking cursor (set only via resource or menu)' , async () => {
await assertNoModeChange ( '\x1b[?13h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 4 - Enable XOR of blinking cursor control sequence and menu' , async () => {
await assertNoModeChange ( '\x1b[?14h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 8 - Print Form Feed (DECPFF), VT220' , async () => {
await assertNoModeChange ( '\x1b[?18h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 9 - Set print extent to full screen (DECPEX), VT220' , async () => {
await assertNoModeChange ( '\x1b[?19h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 2 5 - Show cursor (DECTCEM), VT220' , async () => {
await ctx . proxy . write ( '\x1b[?25l' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). showCursor , false );
await ctx . proxy . write ( '\x1b[?25h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). showCursor , true );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 3 0 - Show scrollbar (rxvt)' , async () => {
await assertNoModeChange ( '\x1b[?30h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 3 5 - Enable font-shifting functions (rxvt)' , async () => {
await assertNoModeChange ( '\x1b[?35h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 3 8 - Enter Tektronix mode (DECTEK), VT240, xterm' , async () => {
await assertNoModeChange ( '\x1b[?38h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 0 - Allow 80 ⇒ 132 mode, xterm' , async () => {
await assertNoModeChange ( '\x1b[?40h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 1 - more(1) fix (see curses resource)' , async () => {
await assertNoModeChange ( '\x1b[?41h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 2 - Enable National Replacement Character sets (DECNRCM), VT220' , async () => {
await assertNoModeChange ( '\x1b[?42h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 3 - Enable Graphic Expanded Print Mode (DECGEPM), VT340' , async () => {
await assertNoModeChange ( '\x1b[?43h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 4 - Turn on margin bell, xterm' , async () => {
await assertNoModeChange ( '\x1b[?44h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 4 - Enable Graphic Print Color Mode (DECGPCM), VT340' , async () => {
await assertNoModeChange ( '\x1b[?44h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 4 5 - Reverse-wraparound mode (XTREVWRAP), xterm' , async () => {
await ctx . proxy . write ( '\x1b[?45h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). reverseWraparoundMode , true );
await ctx . proxy . resize ( 5 , 2 );
await ctx . proxy . write ( '\x1b[?7h' );
await ctx . proxy . write ( '12345X' );
await ctx . proxy . write ( '\r\bY' );
await pollFor ( ctx . page , () => getLinesAsArray ( 2 ), [ '1234Y' , 'X' ]);
await ctx . proxy . resize ( 80 , 24 );
2023-09-02 07:19:32 -07:00
});
test . skip ( 'Ps = 4 5 - Enable Graphic Print Color Syntax (DECGPCS), VT340' , async () => {
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 6 - Start logging (XTLOGGING), xterm' , async () => {
await assertNoModeChange ( '\x1b[?46h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 6 - Graphic Print Background Mode, VT340' , async () => {
await assertNoModeChange ( '\x1b[?46h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 4 7 - Use Alternate Screen Buffer, xterm' , async () => {
await ctx . proxy . write ( 'main' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'main' ]);
await ctx . proxy . write ( '\x1b[?47h' );
await pollFor ( ctx . page , async () => await ctx . proxy . buffer . active . type , 'alternate' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ '' ]);
await ctx . proxy . write ( '\x1b[Halt' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'alt' ]);
await ctx . proxy . write ( '\x1b[?47l' );
await pollFor ( ctx . page , async () => await ctx . proxy . buffer . active . type , 'normal' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'main' ]);
2023-09-02 07:19:32 -07:00
});
test . skip ( 'Ps = 4 7 - Enable Graphic Rotated Print Mode (DECGRPM), VT340' , async () => {
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 6 6 - Application keypad mode (DECNKM), VT320' , async () => {
await ctx . proxy . write ( '\x1b[?66h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). applicationKeypadMode , true );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 6 7 - Backarrow key sends backspace (DECBKM), VT340, VT420' , async () => {
await assertNoModeChange ( '\x1b[?67h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 6 9 - Enable left and right margin mode (DECLRMM), VT420 and up' , async () => {
await assertNoModeChange ( '\x1b[?69h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
// test.skip('Ps = 8 0 - Enable Sixel Display Mode (DECSDM), VT330, VT340, VT382', async () => {
// });
test ( 'Ps = 9 5 - Do not clear screen when DECCOLM is set/reset (DECNCSM), VT510 and up' , async () => {
await assertNoModeChange ( '\x1b[?95h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 0 0 0 - Send Mouse X & Y on button press and release' , async () => {
const selectionBefore = await dragSelection ();
ok ( selectionBefore > 0 );
await ctx . proxy . write ( '\x1b[?1000h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). mouseTrackingMode , 'vt200' );
const selectionAfter = await dragSelection ();
ok ( selectionAfter === 0 );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 0 1 - Use Hilite Mouse Tracking, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1001h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 0 0 2 - Use Cell Motion Mouse Tracking, xterm' , async () => {
const selectionBefore = await dragSelection ();
ok ( selectionBefore > 0 );
await ctx . proxy . write ( '\x1b[?1002h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). mouseTrackingMode , 'drag' );
const selectionAfter = await dragSelection ();
ok ( selectionAfter === 0 );
2023-09-02 07:19:32 -07:00
});
test ( 'Ps = 1 0 0 3 - Set Use All Motion (any event) Mouse Tracking' , async () => {
const coords : { left : number , top : number , bottom : number , right : number } = await ctx . page . evaluate ( `
(function() {
const rect = window.term.element.getBoundingClientRect();
return { left: rect.left, top: rect.top, bottom: rect.bottom, right: rect.right };
})();
` );
// Click and drag and ensure there is a selection
await ctx . page . mouse . click (( coords . left + coords . right ) / 2 , ( coords . top + coords . bottom ) / 2 );
await ctx . page . mouse . down ();
await ctx . page . mouse . move (( coords . left + coords . right ) / 2 , ( coords . top + coords . bottom ) / 4 );
2025-12-30 05:27:28 -08:00
ok (( await ctx . proxy . getSelection ()). length > 0 , 'mouse events are off so there should be a selection' );
2023-09-02 07:19:32 -07:00
await ctx . page . mouse . up ();
// Clear selection
await ctx . page . mouse . click (( coords . left + coords . right ) / 2 , ( coords . top + coords . bottom ) / 2 );
2025-12-30 05:27:28 -08:00
await pollFor ( ctx . page , async () => ( await ctx . proxy . getSelection ()). length , 0 );
2023-09-02 07:19:32 -07:00
// Enable mouse events
2025-12-30 05:27:28 -08:00
await ctx . proxy . write ( '\x1b[?1003h' );
2023-09-02 07:19:32 -07:00
// Click and drag and ensure there is no selection
await ctx . page . mouse . click (( coords . left + coords . right ) / 2 , ( coords . top + coords . bottom ) / 2 );
await ctx . page . mouse . down ();
await ctx . page . mouse . move (( coords . left + coords . right ) / 2 , ( coords . top + coords . bottom ) / 4 );
// mouse events are on so there should be no selection
2025-12-30 05:27:28 -08:00
await pollFor ( ctx . page , async () => ( await ctx . proxy . getSelection ()). length , 0 );
2023-09-02 07:19:32 -07:00
await ctx . page . mouse . up ();
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 0 0 4 - Send FocusIn/FocusOut events, xterm' , async () => {
await ctx . proxy . write ( '\x1b[?1004h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). sendFocusMode , true );
await ctx . proxy . blur ();
recordedData . length = 0 ;
await ctx . proxy . focus ();
await ctx . proxy . blur ();
await pollFor ( ctx . page , () => recordedData , [ '\x1b[I' , '\x1b[O' ]);
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 0 5 - Enable UTF-8 Mouse Mode, xterm' , async () => {
await ctx . proxy . write ( '\x1b[?1006h' );
await pollFor ( ctx . page , async () => await ctx . proxy . core . evaluate (([ core ]) => core . coreMouseService . activeEncoding ), 'SGR' );
await ctx . proxy . write ( '\x1b[?1005h' );
await pollFor ( ctx . page , async () => await ctx . proxy . core . evaluate (([ core ]) => core . coreMouseService . activeEncoding ), 'SGR' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 0 0 6 - Enable SGR Mouse Mode, xterm' , async () => {
await ctx . proxy . write ( '\x1b[?1006h' );
await pollFor ( ctx . page , async () => await ctx . proxy . core . evaluate (([ core ]) => core . coreMouseService . activeEncoding ), 'SGR' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 0 7 - Enable Alternate Scroll Mode, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1007h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 1 0 - Scroll to bottom on tty output (rxvt)' , async () => {
await assertNoModeChange ( '\x1b[?1010h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 1 1 - Scroll to bottom on key press (rxvt)' , async () => {
await assertNoModeChange ( '\x1b[?1011h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 1 5 - Enable urxvt Mouse Mode' , async () => {
await ctx . proxy . write ( '\x1b[?1006h' );
await pollFor ( ctx . page , async () => await ctx . proxy . core . evaluate (([ core ]) => core . coreMouseService . activeEncoding ), 'SGR' );
await ctx . proxy . write ( '\x1b[?1015h' );
await pollFor ( ctx . page , async () => await ctx . proxy . core . evaluate (([ core ]) => core . coreMouseService . activeEncoding ), 'SGR' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 0 1 6 - Enable SGR Mouse PixelMode, xterm' , async () => {
await ctx . proxy . write ( '\x1b[?1016h' );
await pollFor ( ctx . page , async () => await ctx . proxy . core . evaluate (([ core ]) => core . coreMouseService . activeEncoding ), 'SGR_PIXELS' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 3 4 - Interpret "meta" key, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1034h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 3 5 - Enable special modifiers for Alt and NumLock keys, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1035h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 3 6 - Send ESC when Meta modifies a key, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1036h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 3 7 - Send DEL from the editing-keypad Delete key, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1037h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 3 9 - Send ESC when Alt modifies a key, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1039h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 4 0 - Keep selection even if not highlighted, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1040h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 4 1 - Use the CLIPBOARD selection, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1041h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 4 2 - Enable Urgency window manager hint when Control-G is received, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1042h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 4 3 - Enable raising of the window when Control-G is received, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1043h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 4 4 - Reuse the most recent data copied to CLIPBOARD, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1044h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 4 5 - XTREVWRAP2: Extended Reverse-wraparound mode, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1045h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 4 6 - Enable switching to/from Alternate Screen Buffer, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1046h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 0 4 7 - Use Alternate Screen Buffer, xterm' , async () => {
await ctx . proxy . write ( 'main' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'main' ]);
await ctx . proxy . write ( '\x1b[?1047h' );
await pollFor ( ctx . page , async () => await ctx . proxy . buffer . active . type , 'alternate' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ '' ]);
await ctx . proxy . write ( '\x1b[Halt' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'alt' ]);
await ctx . proxy . write ( '\x1b[?1047l' );
await pollFor ( ctx . page , async () => await ctx . proxy . buffer . active . type , 'normal' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'main' ]);
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 0 4 8 - Save cursor as in DECSC, xterm' , async () => {
await ctx . proxy . write ( '\x1b[4;5H' );
await ctx . proxy . write ( '\x1b[?1048h' );
await ctx . proxy . write ( '\x1b[1;1H' );
await ctx . proxy . write ( '\x1b[?1048l' );
await pollFor ( ctx . page , () => getCursor (), { col : 4 , row : 3 });
2023-09-02 07:19:32 -07:00
});
2026-01-31 21:05:36 -08:00
test ( 'Ps = 1 0 4 9 - Save cursor as in DECSC, xterm' , async () => {
await ctx . proxy . write ( 'main' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'main' ]);
await ctx . proxy . write ( '\x1b[4;6H' );
await ctx . proxy . write ( '\x1b[?1049h' );
await pollFor ( ctx . page , async () => await ctx . proxy . buffer . active . type , 'alternate' );
await ctx . proxy . write ( '\x1b[Halt' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'alt' ]);
await ctx . proxy . write ( '\x1b[?1049l' );
await pollFor ( ctx . page , async () => await ctx . proxy . buffer . active . type , 'normal' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'main' ]);
await pollFor ( ctx . page , () => getCursor (), { col : 5 , row : 3 });
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 5 0 - Set terminfo/termcap function-key mode, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1050h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 5 1 - Set Sun function-key mode, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1051h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 5 2 - Set HP function-key mode, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1052h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 5 3 - Set SCO function-key mode, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1053h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 6 0 - Set legacy keyboard emulation, i.e, X11R6, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1060h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 6 1 - Set VT220 keyboard emulation, xterm' , async () => {
await assertNoModeChange ( '\x1b[?1061h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 2 0 0 1 - Enable readline mouse button-1, xterm' , async () => {
await assertNoModeChange ( '\x1b[?2001h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 2 0 0 2 - Enable readline mouse button-2, xterm' , async () => {
await assertNoModeChange ( '\x1b[?2002h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 2 0 0 3 - Enable readline mouse button-3, xterm' , async () => {
await assertNoModeChange ( '\x1b[?2003h' );
2023-09-02 07:19:32 -07:00
});
test ( 'Pm = 2 0 0 4, Set bracketed paste mode' , async () => {
if ( ctx . browser . browserType (). name () !== 'chromium' ) {
test . skip ();
return ;
}
await pollFor ( ctx . page , () => simulatePaste ( 'foo' ), 'foo' );
2025-12-30 05:27:28 -08:00
await ctx . proxy . write ( '\x1b[?2004h' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => simulatePaste ( 'bar' ), '\x1b[200~bar\x1b[201~' );
2025-12-30 05:27:28 -08:00
await ctx . proxy . write ( '\x1b[?2004l' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => simulatePaste ( 'baz' ), 'baz' );
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 2 0 0 5 - Enable readline character-quoting, xterm' , async () => {
await assertNoModeChange ( '\x1b[?2005h' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 2 0 0 6 - Enable readline newline pasting, xterm' , async () => {
await assertNoModeChange ( '\x1b[?2006h' );
2023-09-02 07:19:32 -07:00
});
});
test . skip ( 'CSI Ps i - MC: Media Copy' , async () => {
// TODO: Implement
});
test . skip ( 'CSI ? Ps i - MC: Media Copy, DEC-specified' , async () => {
// TODO: Implement
});
2026-01-31 18:21:32 -08:00
test ( 'CSI Pm l - RM: Reset Mode' , async () => {
await ctx . proxy . write ( '\x1b[4h\x1b[20h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). insertMode , true );
await pollFor ( ctx . page , async () => await ctx . proxy . getOption ( 'convertEol' ), true );
await ctx . proxy . write ( '\x1b[4l\x1b[20l' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). insertMode , false );
await pollFor ( ctx . page , async () => await ctx . proxy . getOption ( 'convertEol' ), false );
2023-09-02 07:19:32 -07:00
});
test . describe ( 'CSI ? Pm l - DECRST: DEC Private Mode Reset' , async () => {
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 - Normal Cursor Keys (DECCKM), VT100.' , async () => {
await ctx . proxy . write ( '\x1b[?1h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). applicationCursorKeysMode , true );
await ctx . proxy . write ( '\x1b[?1l' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). applicationCursorKeysMode , false );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 2 - Designate VT52 mode (DECANM), VT100.' , async () => {
await assertNoModeChange ( '\x1b[?2l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 21:05:36 -08:00
test ( 'Ps = 3 - 80 Column Mode (DECCOLM), VT100.' , async () => {
const windowOptions = await ctx . proxy . getOption ( 'windowOptions' );
await ctx . proxy . setOption ( 'windowOptions' , { ... windowOptions , setWinLines : true });
await ctx . proxy . write ( '\x1b[?3h' );
await pollFor ( ctx . page , async () => await ctx . proxy . cols , 132 );
await ctx . proxy . write ( '\x1b[?3l' );
await pollFor ( ctx . page , async () => await ctx . proxy . cols , 80 );
await ctx . proxy . resize ( 80 , 24 );
await ctx . proxy . setOption ( 'windowOptions' , windowOptions );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 - Jump (Fast) Scroll (DECSCLM), VT100.' , async () => {
await assertNoModeChange ( '\x1b[?4l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 5 - Normal Video (DECSCNM), VT100.' , async () => {
await assertNoModeChange ( '\x1b[?5l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 6 - Normal Cursor Mode (DECOM), VT100.' , async () => {
await ctx . proxy . write ( '\x1b[?6h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). originMode , true );
await ctx . proxy . write ( '\x1b[?6l' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). originMode , false );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 7 - No Auto-Wrap Mode (DECAWM), VT100.' , async () => {
await ctx . proxy . resize ( 5 , 2 );
await ctx . proxy . write ( '\x1b[?7h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). wraparoundMode , true );
await ctx . proxy . write ( '\x1b[?7l' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). wraparoundMode , false );
await ctx . proxy . write ( '12345X' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ '1234X' ]);
await ctx . proxy . write ( '\x1b[?7h' );
await ctx . proxy . reset ();
await ctx . proxy . write ( '\x1b[?7h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). wraparoundMode , true );
await ctx . proxy . write ( '12345X' );
await pollFor ( ctx . page , () => getLinesAsArray ( 2 ), [ '12345' , 'X' ]);
await ctx . proxy . resize ( 80 , 24 );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 8 - No Auto-Repeat Keys (DECARM), VT100.' , async () => {
await assertNoModeChange ( '\x1b[?8l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 9 - Don\'t send Mouse X & Y on button press, xterm.' , async () => {
await ctx . proxy . write ( '\x1b[?9h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). mouseTrackingMode , 'x10' );
await ctx . proxy . write ( '\x1b[?9l' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). mouseTrackingMode , 'none' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 - Hide toolbar (rxvt).' , async () => {
await assertNoModeChange ( '\x1b[?10l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 21:05:36 -08:00
test ( 'Ps = 1 2 - Stop blinking cursor (AT&T 610).' , async () => {
const previousQuirks = await ctx . proxy . getOption ( 'quirks' );
const previousCursorBlink = await ctx . proxy . getOption ( 'cursorBlink' );
await ctx . proxy . setOption ( 'quirks' , { ...( previousQuirks ?? {}), allowSetCursorBlink : true });
await ctx . proxy . setOption ( 'cursorBlink' , true );
await ctx . proxy . write ( '\x1b[?12l' );
await pollFor ( ctx . page , async () => await ctx . proxy . getOption ( 'cursorBlink' ), false );
await ctx . proxy . setOption ( 'quirks' , previousQuirks );
await ctx . proxy . setOption ( 'cursorBlink' , previousCursorBlink );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 3 - Disable blinking cursor (reset only via resource or menu).' , async () => {
await assertNoModeChange ( '\x1b[?13l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 4 - Disable XOR of blinking cursor control sequence and menu.' , async () => {
await assertNoModeChange ( '\x1b[?14l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 8 - Don\'t Print Form Feed (DECPFF), VT220.' , async () => {
await assertNoModeChange ( '\x1b[?18l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 9 - Limit print to scrolling region (DECPEX), VT220.' , async () => {
await assertNoModeChange ( '\x1b[?19l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 2 5 - Hide cursor (DECTCEM), VT220.' , async () => {
await ctx . proxy . write ( '\x1b[?25h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). showCursor , true );
await ctx . proxy . write ( '\x1b[?25l' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). showCursor , false );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 3 0 - Don\'t show scrollbar (rxvt).' , async () => {
await assertNoModeChange ( '\x1b[?30l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 3 5 - Disable font-shifting functions (rxvt).' , async () => {
await assertNoModeChange ( '\x1b[?35l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 0 - Disallow 80 ⇒ 132 mode, xterm.' , async () => {
await assertNoModeChange ( '\x1b[?40l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 1 - No more(1) fix (see curses resource).' , async () => {
await assertNoModeChange ( '\x1b[?41l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 2 - Disable National Replacement Character sets (DECNRCM), VT220.' , async () => {
await assertNoModeChange ( '\x1b[?42l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 3 - Disable Graphic Expanded Print Mode (DECGEPM), VT340.' , async () => {
await assertNoModeChange ( '\x1b[?43l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 4 - Turn off margin bell, xterm.' , async () => {
await assertNoModeChange ( '\x1b[?44l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 4 - Disable Graphic Print Color Mode (DECGPCM), VT340.' , async () => {
await assertNoModeChange ( '\x1b[?44l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 4 5 - No Reverse-wraparound mode (XTREVWRAP), xterm.' , async () => {
await ctx . proxy . write ( '\x1b[?45h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). reverseWraparoundMode , true );
await ctx . proxy . write ( '\x1b[?45l' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). reverseWraparoundMode , false );
2023-09-02 07:19:32 -07:00
});
test . skip ( 'Ps = 4 5 - Disable Graphic Print Color Syntax (DECGPCS), VT340.' , async () => {
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 4 6 - Stop logging (XTLOGGING), xterm. This is normally disabled by a compile-time option.' , async () => {
await assertNoModeChange ( '\x1b[?46l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 4 7 - Use Normal Screen Buffer, xterm.' , async () => {
await ctx . proxy . write ( '\x1b[?47h' );
await pollFor ( ctx . page , async () => await ctx . proxy . buffer . active . type , 'alternate' );
await ctx . proxy . write ( '\x1b[?47l' );
await pollFor ( ctx . page , async () => await ctx . proxy . buffer . active . type , 'normal' );
2023-09-02 07:19:32 -07:00
});
test . skip ( 'Ps = 4 7 - Disable Graphic Rotated Print Mode (DECGRPM), VT340.' , async () => {
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 6 6 - Numeric keypad mode (DECNKM), VT320.' , async () => {
await ctx . proxy . write ( '\x1b[?66h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). applicationKeypadMode , true );
await ctx . proxy . write ( '\x1b[?66l' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). applicationKeypadMode , false );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 6 7 - Backarrow key sends delete (DECBKM), VT340, VT420. This sets the backarrowKey resource to "false".' , async () => {
await assertNoModeChange ( '\x1b[?67l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 6 9 - Disable left and right margin mode (DECLRMM), VT420 and up.' , async () => {
await assertNoModeChange ( '\x1b[?69l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
// This is intentionally not implemented here are image support lives within an addon
// test.skip('Ps = 8 0 - Disable Sixel Display Mode (DECSDM), VT330, VT340, VT382. Turns on "Sixel Scrolling". See the section Sixel Graphics and mode 8 4 5 2 .', async () => {
// });
test ( 'Ps = 9 5 - Clear screen when DECCOLM is set/reset (DECNCSM), VT510 and up.' , async () => {
await assertNoModeChange ( '\x1b[?95l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 0 0 0 - Don\'t send Mouse X & Y on button press and release. See the section Mouse Tracking.' , async () => {
await ctx . proxy . write ( '\x1b[?1000h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). mouseTrackingMode , 'vt200' );
await ctx . proxy . write ( '\x1b[?1000l' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). mouseTrackingMode , 'none' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 0 1 - Don\'t use Hilite Mouse Tracking, xterm.' , async () => {
await assertNoModeChange ( '\x1b[?1001l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 0 0 2 - Don\'t use Cell Motion Mouse Tracking, xterm. See the section Button-event tracking.' , async () => {
await ctx . proxy . write ( '\x1b[?1002h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). mouseTrackingMode , 'drag' );
await ctx . proxy . write ( '\x1b[?1002l' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). mouseTrackingMode , 'none' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 0 0 3 - Don\'t use All Motion Mouse Tracking, xterm. See the section Any-event tracking.' , async () => {
await ctx . proxy . write ( '\x1b[?1003h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). mouseTrackingMode , 'any' );
await ctx . proxy . write ( '\x1b[?1003l' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). mouseTrackingMode , 'none' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 0 0 4 - Don\'t send FocusIn/FocusOut events, xterm.' , async () => {
await ctx . proxy . write ( '\x1b[?1004h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). sendFocusMode , true );
await ctx . proxy . write ( '\x1b[?1004l' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). sendFocusMode , false );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 0 5 - Disable UTF-8 Mouse Mode, xterm.' , async () => {
await ctx . proxy . write ( '\x1b[?1006h' );
await pollFor ( ctx . page , async () => await ctx . proxy . core . evaluate (([ core ]) => core . coreMouseService . activeEncoding ), 'SGR' );
await ctx . proxy . write ( '\x1b[?1005l' );
await pollFor ( ctx . page , async () => await ctx . proxy . core . evaluate (([ core ]) => core . coreMouseService . activeEncoding ), 'SGR' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 0 0 6 - Disable SGR Mouse Mode, xterm.' , async () => {
await ctx . proxy . write ( '\x1b[?1006h' );
await pollFor ( ctx . page , async () => await ctx . proxy . core . evaluate (([ core ]) => core . coreMouseService . activeEncoding ), 'SGR' );
await ctx . proxy . write ( '\x1b[?1006l' );
await pollFor ( ctx . page , async () => await ctx . proxy . core . evaluate (([ core ]) => core . coreMouseService . activeEncoding ), 'DEFAULT' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 0 7 - Disable Alternate Scroll Mode, xterm. This corresponds to the alternateScroll resource.' , async () => {
await assertNoModeChange ( '\x1b[?1007l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 1 0 - Don\'t scroll to bottom on tty output (rxvt). This sets the scrollTtyOutput resource to "false".' , async () => {
await assertNoModeChange ( '\x1b[?1010l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 1 1 - Don\'t scroll to bottom on key press (rxvt). This sets the scrollKey resource to "false".' , async () => {
await assertNoModeChange ( '\x1b[?1011l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 1 5 - Disable urxvt Mouse Mode.' , async () => {
await ctx . proxy . write ( '\x1b[?1006h' );
await pollFor ( ctx . page , async () => await ctx . proxy . core . evaluate (([ core ]) => core . coreMouseService . activeEncoding ), 'SGR' );
await ctx . proxy . write ( '\x1b[?1015l' );
await pollFor ( ctx . page , async () => await ctx . proxy . core . evaluate (([ core ]) => core . coreMouseService . activeEncoding ), 'SGR' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 0 1 6 - Disable SGR Mouse Pixel-Mode, xterm.' , async () => {
await ctx . proxy . write ( '\x1b[?1016h' );
await pollFor ( ctx . page , async () => await ctx . proxy . core . evaluate (([ core ]) => core . coreMouseService . activeEncoding ), 'SGR_PIXELS' );
await ctx . proxy . write ( '\x1b[?1016l' );
await pollFor ( ctx . page , async () => await ctx . proxy . core . evaluate (([ core ]) => core . coreMouseService . activeEncoding ), 'DEFAULT' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 3 4 - Don\'t interpret "meta" key, xterm. This disables the eightBitInput resource.' , async () => {
await assertNoModeChange ( '\x1b[?1034l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 3 5 - Disable special modifiers for Alt and NumLock keys, xterm. This disables the numLock resource.' , async () => {
await assertNoModeChange ( '\x1b[?1035l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 3 6 - Don\'t send ESC when Meta modifies a key, xterm. This disables the metaSendsEscape resource.' , async () => {
await assertNoModeChange ( '\x1b[?1036l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 3 7 - Send VT220 Remove from the editing-keypad Delete key, xterm.' , async () => {
await assertNoModeChange ( '\x1b[?1037l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 3 9 - Don\'t send ESC when Alt modifies a key, xterm. This disables the altSendsEscape resource.' , async () => {
await assertNoModeChange ( '\x1b[?1039l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 4 0 - Do not keep selection when not highlighted, xterm. This disables the keepSelection resource.' , async () => {
await assertNoModeChange ( '\x1b[?1040l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 4 1 - Use the PRIMARY selection, xterm. This disables the selectToClipboard resource.' , async () => {
await assertNoModeChange ( '\x1b[?1041l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 4 2 - Disable Urgency window manager hint when Control-G is received, xterm. This disables the bellIsUrgent resource.' , async () => {
await assertNoModeChange ( '\x1b[?1042l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 4 3 - Disable raising of the window when Control- G is received, xterm. This disables the popOnBell resource.' , async () => {
await assertNoModeChange ( '\x1b[?1043l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 4 5 - No Extended Reverse-wraparound mode (XTREVWRAP2), xterm.' , async () => {
await assertNoModeChange ( '\x1b[?1045l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 4 6 - Disable switching to/from Alternate Screen Buffer, xterm. This works for terminfo-based systems, updating the titeInhibit resource. If currently using the Alternate Screen Buffer, xterm switches to the Normal Screen Buffer.' , async () => {
await assertNoModeChange ( '\x1b[?1046l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 0 4 7 - Use Normal Screen Buffer, xterm. Clear the screen first if in the Alternate Screen Buffer. This may be disabled by the titeInhibit resource.' , async () => {
await ctx . proxy . write ( '\x1b[?1047h' );
await pollFor ( ctx . page , async () => await ctx . proxy . buffer . active . type , 'alternate' );
await ctx . proxy . write ( '\x1b[?1047l' );
await pollFor ( ctx . page , async () => await ctx . proxy . buffer . active . type , 'normal' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 0 4 8 - Restore cursor as in DECRC, xterm. This may be disabled by the titeInhibit resource.' , async () => {
await ctx . proxy . write ( '\x1b[4;6H' );
await ctx . proxy . write ( '\x1b[?1048h' );
await ctx . proxy . write ( '\x1b[1;1H' );
await ctx . proxy . write ( '\x1b[?1048l' );
await pollFor ( ctx . page , () => getCursor (), { col : 5 , row : 3 });
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 1 0 4 9 - Use Normal Screen Buffer and restore cursor as in DECRC, xterm. This may be disabled by the titeInhibit resource. This combines the effects of the 1 0 4 7 and 1 0 4 8 modes. Use this with terminfo-based applications rather than the 4 7 mode.' , async () => {
await ctx . proxy . write ( '\x1b[3;4H' );
await ctx . proxy . write ( '\x1b[?1048h' );
await ctx . proxy . write ( '\x1b[?47h' );
await pollFor ( ctx . page , async () => await ctx . proxy . buffer . active . type , 'alternate' );
await ctx . proxy . write ( '\x1b[1;1H' );
await ctx . proxy . write ( '\x1b[?1049l' );
await pollFor ( ctx . page , async () => await ctx . proxy . buffer . active . type , 'normal' );
await pollFor ( ctx . page , () => getCursor (), { col : 3 , row : 2 });
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 5 0 - Reset terminfo/termcap function-key mode, xterm.' , async () => {
await assertNoModeChange ( '\x1b[?1050l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 5 1 - Reset Sun function-key mode, xterm.' , async () => {
await assertNoModeChange ( '\x1b[?1051l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 5 2 - Reset HP function-key mode, xterm.' , async () => {
await assertNoModeChange ( '\x1b[?1052l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 5 3 - Reset SCO function-key mode, xterm.' , async () => {
await assertNoModeChange ( '\x1b[?1053l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 6 0 - Reset legacy keyboard emulation, i.e, X11R6, xterm.' , async () => {
await assertNoModeChange ( '\x1b[?1060l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 1 0 6 1 - Reset keyboard emulation to Sun/PC style, xterm.' , async () => {
await assertNoModeChange ( '\x1b[?1061l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 2 0 0 1 - Disable readline mouse button-1, xterm.' , async () => {
await assertNoModeChange ( '\x1b[?2001l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 2 0 0 2 - Disable readline mouse button-2, xterm.' , async () => {
await assertNoModeChange ( '\x1b[?2002l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 2 0 0 3 - Disable readline mouse button-3, xterm.' , async () => {
await assertNoModeChange ( '\x1b[?2003l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'Ps = 2 0 0 4 - Reset bracketed paste mode, xterm.' , async () => {
await ctx . proxy . write ( '\x1b[?2004h' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). bracketedPasteMode , true );
await ctx . proxy . write ( '\x1b[?2004l' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). bracketedPasteMode , false );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 2 0 0 5 - Disable readline character-quoting, xterm.' , async () => {
await assertNoModeChange ( '\x1b[?2005l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 22:01:35 -08:00
test ( 'Ps = 2 0 0 6 - Disable readline newline pasting, xterm.' , async () => {
await assertNoModeChange ( '\x1b[?2006l' );
2023-09-02 07:19:32 -07:00
});
});
test . describe ( 'CSI Pm m - SGR: Character Attributes' , () => {
2025-12-31 05:17:36 -08:00
test ( 'Ps = 0 - Normal (default), VT100' , async () => {
await ctx . proxy . write ( '\x1b[1;3;4;5;7;8;9m#\x1b[0m@' );
const cell0 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell0 ! . isBold ());
ok ( await cell0 ! . isItalic ());
ok ( await cell0 ! . isUnderline ());
ok ( await cell0 ! . isBlink ());
ok ( await cell0 ! . isInverse ());
ok ( await cell0 ! . isInvisible ());
ok ( await cell0 ! . isStrikethrough ());
const cell1 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 1 );
deepStrictEqual ( await cell1 ! . isAttributeDefault (), true );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 1 - Bold, VT100' , async () => {
await ctx . proxy . write ( '\x1b[1m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell ! . isBold ());
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 2 - Faint, decreased intensity, ECMA-48 2nd' , async () => {
await ctx . proxy . write ( '\x1b[2m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell ! . isDim ());
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 3 - Italicized, ECMA-48 2nd' , async () => {
await ctx . proxy . write ( '\x1b[3m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell ! . isItalic ());
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 4 - Underlined, VT100' , async () => {
await ctx . proxy . write ( '\x1b[4m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell ! . isUnderline ());
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 5 - Blink, VT100' , async () => {
await ctx . proxy . write ( '\x1b[5m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell ! . isBlink ());
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 7 - Inverse, VT100' , async () => {
await ctx . proxy . write ( '\x1b[7m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell ! . isInverse ());
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 8 - Invisible, ECMA-48 2nd, VT300' , async () => {
await ctx . proxy . write ( '\x1b[8m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell ! . isInvisible ());
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 9 - Crossed-out characters, ECMA-48 3rd' , async () => {
await ctx . proxy . write ( '\x1b[9m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell ! . isStrikethrough ());
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 21 - Doubly-underlined, ECMA-48 3rd' , async () => {
await ctx . proxy . write ( '\x1b[21m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell ! . isUnderline ());
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 22 - Normal (neither bold nor faint), ECMA-48 3rd' , async () => {
await ctx . proxy . write ( '\x1b[1;2m#\x1b[22m@' );
const cell0 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell0 ! . isBold ());
ok ( await cell0 ! . isDim ());
const cell1 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 1 );
deepStrictEqual ( await cell1 ! . isBold (), 0 );
deepStrictEqual ( await cell1 ! . isDim (), 0 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 23 - Not italicized, ECMA-48 3rd' , async () => {
await ctx . proxy . write ( '\x1b[3m#\x1b[23m@' );
const cell0 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell0 ! . isItalic ());
const cell1 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 1 );
deepStrictEqual ( await cell1 ! . isItalic (), 0 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 24 - Not underlined, ECMA-48 3rd' , async () => {
await ctx . proxy . write ( '\x1b[4m#\x1b[24m@' );
const cell0 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell0 ! . isUnderline ());
const cell1 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 1 );
deepStrictEqual ( await cell1 ! . isUnderline (), 0 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 25 - Steady (not blinking), ECMA-48 3rd' , async () => {
await ctx . proxy . write ( '\x1b[5m#\x1b[25m@' );
const cell0 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell0 ! . isBlink ());
const cell1 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 1 );
deepStrictEqual ( await cell1 ! . isBlink (), 0 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 27 - Positive (not inverse), ECMA-48 3rd' , async () => {
await ctx . proxy . write ( '\x1b[7m#\x1b[27m@' );
const cell0 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell0 ! . isInverse ());
const cell1 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 1 );
deepStrictEqual ( await cell1 ! . isInverse (), 0 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 28 - Visible, ECMA-48 3rd, VT300' , async () => {
await ctx . proxy . write ( '\x1b[8m#\x1b[28m@' );
const cell0 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell0 ! . isInvisible ());
const cell1 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 1 );
deepStrictEqual ( await cell1 ! . isInvisible (), 0 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 29 - Not crossed-out, ECMA-48 3rd' , async () => {
await ctx . proxy . write ( '\x1b[9m#\x1b[29m@' );
const cell0 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
ok ( await cell0 ! . isStrikethrough ());
const cell1 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 1 );
deepStrictEqual ( await cell1 ! . isStrikethrough (), 0 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 30 - Set foreground color to Black' , async () => {
await ctx . proxy . write ( '\x1b[30m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 0 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 31 - Set foreground color to Red' , async () => {
await ctx . proxy . write ( '\x1b[31m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 1 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 32 - Set foreground color to Green' , async () => {
await ctx . proxy . write ( '\x1b[32m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 2 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 33 - Set foreground color to Yellow' , async () => {
await ctx . proxy . write ( '\x1b[33m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 3 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 34 - Set foreground color to Blue' , async () => {
await ctx . proxy . write ( '\x1b[34m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 4 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 35 - Set foreground color to Magenta' , async () => {
await ctx . proxy . write ( '\x1b[35m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 5 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 36 - Set foreground color to Cyan' , async () => {
await ctx . proxy . write ( '\x1b[36m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 6 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 37 - Set foreground color to White' , async () => {
await ctx . proxy . write ( '\x1b[37m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 7 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 39 - Set foreground color to default, ECMA-48 3rd' , async () => {
await ctx . proxy . write ( '\x1b[31m#\x1b[39m@' );
const cell0 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell0 ! . isFgPalette (), true );
deepStrictEqual ( await cell0 ! . getFgColor (), 1 );
const cell1 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 1 );
deepStrictEqual ( await cell1 ! . isFgDefault (), true );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 40 - Set background color to Black' , async () => {
await ctx . proxy . write ( '\x1b[40m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 0 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 41 - Set background color to Red' , async () => {
await ctx . proxy . write ( '\x1b[41m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 1 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 42 - Set background color to Green' , async () => {
await ctx . proxy . write ( '\x1b[42m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 2 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 43 - Set background color to Yellow' , async () => {
await ctx . proxy . write ( '\x1b[43m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 3 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 44 - Set background color to Blue' , async () => {
await ctx . proxy . write ( '\x1b[44m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 4 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 45 - Set background color to Magenta' , async () => {
await ctx . proxy . write ( '\x1b[45m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 5 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 46 - Set background color to Cyan' , async () => {
await ctx . proxy . write ( '\x1b[46m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 6 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 47 - Set background color to White' , async () => {
await ctx . proxy . write ( '\x1b[47m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 7 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 49 - Set background color to default, ECMA-48 3rd' , async () => {
await ctx . proxy . write ( '\x1b[41m#\x1b[49m@' );
const cell0 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell0 ! . isBgPalette (), true );
deepStrictEqual ( await cell0 ! . getBgColor (), 1 );
const cell1 = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 1 );
deepStrictEqual ( await cell1 ! . isBgDefault (), true );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 90 - Set foreground color to bright Black' , async () => {
await ctx . proxy . write ( '\x1b[90m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 8 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 91 - Set foreground color to bright Red' , async () => {
await ctx . proxy . write ( '\x1b[91m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 9 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 92 - Set foreground color to bright Green' , async () => {
await ctx . proxy . write ( '\x1b[92m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 10 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 93 - Set foreground color to bright Yellow' , async () => {
await ctx . proxy . write ( '\x1b[93m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 11 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 94 - Set foreground color to bright Blue' , async () => {
await ctx . proxy . write ( '\x1b[94m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 12 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 95 - Set foreground color to bright Magenta' , async () => {
await ctx . proxy . write ( '\x1b[95m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 13 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 96 - Set foreground color to bright Cyan' , async () => {
await ctx . proxy . write ( '\x1b[96m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 14 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 97 - Set foreground color to bright White' , async () => {
await ctx . proxy . write ( '\x1b[97m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 15 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 100 - Set background color to bright Black' , async () => {
await ctx . proxy . write ( '\x1b[100m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 8 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 101 - Set background color to bright Red' , async () => {
await ctx . proxy . write ( '\x1b[101m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 9 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 102 - Set background color to bright Green' , async () => {
await ctx . proxy . write ( '\x1b[102m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 10 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 103 - Set background color to bright Yellow' , async () => {
await ctx . proxy . write ( '\x1b[103m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 11 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 104 - Set background color to bright Blue' , async () => {
await ctx . proxy . write ( '\x1b[104m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 12 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 105 - Set background color to bright Magenta' , async () => {
await ctx . proxy . write ( '\x1b[105m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 13 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 106 - Set background color to bright Cyan' , async () => {
await ctx . proxy . write ( '\x1b[106m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 14 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 107 - Set background color to bright White' , async () => {
await ctx . proxy . write ( '\x1b[107m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 15 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 38:2:Pi:Pr:Pg:Pb - Set foreground color using RGB values (colon separator)' , async () => {
await ctx . proxy . write ( '\x1b[38:2::171:205:239m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgRGB (), true );
deepStrictEqual ( await cell ! . getFgColor (), 0xabcdef );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 38:5:Ps - Set foreground color to Ps using indexed color (colon separator)' , async () => {
await ctx . proxy . write ( '\x1b[38:5:123m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgPalette (), true );
deepStrictEqual ( await cell ! . getFgColor (), 123 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 48:2:Pi:Pr:Pg:Pb - Set background color using RGB values (colon separator)' , async () => {
await ctx . proxy . write ( '\x1b[48:2::18:52:86m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgRGB (), true );
deepStrictEqual ( await cell ! . getBgColor (), 0x123456 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 48:5:Ps - Set background color to Ps using indexed color (colon separator)' , async () => {
await ctx . proxy . write ( '\x1b[48:5:200m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgPalette (), true );
deepStrictEqual ( await cell ! . getBgColor (), 200 );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 38;2;Pr;Pg;Pb - Set foreground color using RGB values (semicolon separator)' , async () => {
await ctx . proxy . write ( '\x1b[38;2;171;205;239m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isFgRGB (), true );
deepStrictEqual ( await cell ! . getFgColor (), 0xabcdef );
2023-09-02 07:19:32 -07:00
});
2025-12-31 05:17:36 -08:00
test ( 'Ps = 48;2;Pr;Pg;Pb - Set background color using RGB values (semicolon separator)' , async () => {
await ctx . proxy . write ( '\x1b[48;2;18;52;86m#' );
const cell = await ( await ctx . proxy . buffer . active . getLine ( 0 )) ! . getCell ( 0 );
deepStrictEqual ( await cell ! . isBgRGB (), true );
deepStrictEqual ( await cell ! . getBgColor (), 0x123456 );
2023-09-02 07:19:32 -07:00
});
});
test . skip ( 'CSI > Pp [; Pv] m - XTMODKEYS: Set/reset key modifier options, xterm' , () => {
// TODO: Implement
});
test . skip ( 'CSI ? Pp m - XTQMODKEYS: Query key modifier options, xterm' , () => {
// TODO: Implement
});
test . describe ( 'CSI Ps n - DSR: Device Status Report' , () => {
test ( 'Status Report - CSI 5 n' , async () => {
2025-12-30 05:27:28 -08:00
await ctx . proxy . write ( '\x1b[5n' );
deepStrictEqual ( recordedData , [ '\x1b[0n' ]);
2023-09-02 07:19:32 -07:00
});
test ( 'Report Cursor Position (CPR) - CSI 6 n' , async () => {
2025-12-30 05:27:28 -08:00
await ctx . proxy . write ( '\n\nfoo' );
await pollFor ( ctx . page , async () => [
await ctx . proxy . buffer . active . cursorY ,
await ctx . proxy . buffer . active . cursorX
], [ 2 , 3 ]);
await ctx . proxy . write ( '\x1b[6n' );
deepStrictEqual ( recordedData , [ '\x1b[3;4R' ]);
2023-09-02 07:19:32 -07:00
});
test ( 'Report Cursor Position (DECXCPR) - CSI ? 6 n' , async () => {
2025-12-30 05:27:28 -08:00
await ctx . proxy . write ( '\n\nfoo' );
await pollFor ( ctx . page , async () => [
await ctx . proxy . buffer . active . cursorY ,
await ctx . proxy . buffer . active . cursorX
], [ 2 , 3 ]);
await ctx . proxy . write ( '\x1b[?6n' );
deepStrictEqual ( recordedData , [ '\x1b[?3;4R' ]);
2023-09-02 07:19:32 -07:00
});
});
test . skip ( 'CSI > Ps n - Disable key modifier options, xterm' , () => {
// TODO: Implement
});
2026-01-27 10:19:26 -08:00
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 }` );
});
2023-09-02 07:19:32 -07:00
});
test . skip ( 'CSI > Ps p - XTSMPOINTER: Set resource value pointerMode, xterm' , () => {
// TODO: Implement
});
2026-01-31 18:21:32 -08:00
test ( 'CSI ! p - DECSTR: Soft terminal reset, VT220 and up.' , async () => {
const rows = await ctx . proxy . rows ;
await ctx . proxy . write ( '\x1b[4h\x1b[?6h\x1b[3;5r' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). insertMode , true );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). originMode , true );
await ctx . proxy . write ( '\x1b[!p' );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). insertMode , false );
await pollFor ( ctx . page , async () => ( await ctx . proxy . modes ). originMode , false );
await pollFor ( ctx . page , () => ctx . page . evaluate ( `({ top: window.term._core._bufferService.buffer.scrollTop, bottom: window.term._core._bufferService.buffer.scrollBottom })` ), { top : 0 , bottom : rows - 1 });
2023-09-02 07:19:32 -07:00
});
test . skip ( 'CSI Pl ; Pc " p - DECSCL: Set conformance level, VT220 and up.' , () => {
// TODO: Implement
});
2026-01-31 18:21:32 -08:00
test ( 'CSI Ps $ p - DECRQM: Request ANSI mode' , async () => {
await ctx . proxy . write ( '\x1b[4h' );
recordedData . length = 0 ;
await ctx . proxy . write ( '\x1b[4$p' );
deepStrictEqual ( recordedData , [ '\x1b[4;1$y' ]);
await ctx . proxy . write ( '\x1b[4l' );
recordedData . length = 0 ;
await ctx . proxy . write ( '\x1b[4$p' );
deepStrictEqual ( recordedData , [ '\x1b[4;2$y' ]);
await ctx . proxy . write ( '\x1b[20h' );
recordedData . length = 0 ;
await ctx . proxy . write ( '\x1b[20$p' );
deepStrictEqual ( recordedData , [ '\x1b[20;1$y' ]);
await ctx . proxy . write ( '\x1b[20l' );
2023-09-02 07:19:32 -07:00
});
2026-01-31 18:21:32 -08:00
test ( 'CSI ? Ps $ p - Request DEC private mode (DECRQM).' , async () => {
await ctx . proxy . write ( '\x1b[?1h' );
recordedData . length = 0 ;
await ctx . proxy . write ( '\x1b[?1$p' );
deepStrictEqual ( recordedData , [ '\x1b[?1;1$y' ]);
await ctx . proxy . write ( '\x1b[?1l' );
recordedData . length = 0 ;
await ctx . proxy . write ( '\x1b[?1$p' );
deepStrictEqual ( recordedData , [ '\x1b[?1;2$y' ]);
2023-09-02 07:19:32 -07:00
});
test . skip ( 'CSI [Pm] # p - Push video attributes onto stack (XTPUSHSGR), xterm. This is an alias for CSI # { , used to work around language limitations of C#.' , async () => {
// TODO: Implement
});
2026-01-31 18:21:32 -08:00
test ( 'CSI > Ps q - Report xterm name and version (XTVERSION).' , async () => {
await ctx . proxy . write ( '\x1b[>q' );
ok ( recordedData . length === 1 );
ok ( recordedData [ 0 ]. startsWith ( '\x1bP>|xterm.js(' ));
ok ( recordedData [ 0 ]. endsWith ( '\x1b\\' ));
2023-09-02 07:19:32 -07:00
});
test . skip ( 'CSI Ps q - Load LEDs (DECLL), VT100.' , async () => {
// TODO: Implement
});
2026-01-31 18:21:32 -08:00
test ( 'CSI Ps SP q - Set cursor style (DECSCUSR), VT520.' , async () => {
const getCursorMode = async () => ctx . proxy . core . evaluate (([ core ]) => {
const modes = core . coreService . decPrivateModes ;
return { style : modes.cursorStyle , blink : modes.cursorBlink };
});
await ctx . proxy . write ( '\x1b[1 q' );
deepStrictEqual ( await getCursorMode (), { style : 'block' , blink : true });
await ctx . proxy . write ( '\x1b[2 q' );
deepStrictEqual ( await getCursorMode (), { style : 'block' , blink : false });
await ctx . proxy . write ( '\x1b[3 q' );
deepStrictEqual ( await getCursorMode (), { style : 'underline' , blink : true });
await ctx . proxy . write ( '\x1b[4 q' );
deepStrictEqual ( await getCursorMode (), { style : 'underline' , blink : false });
await ctx . proxy . write ( '\x1b[5 q' );
deepStrictEqual ( await getCursorMode (), { style : 'bar' , blink : true });
await ctx . proxy . write ( '\x1b[6 q' );
deepStrictEqual ( await getCursorMode (), { style : 'bar' , blink : false });
await ctx . proxy . write ( '\x1b[0 q' );
deepStrictEqual ( await getCursorMode (), { style : undefined , blink : undefined });
2023-09-02 07:19:32 -07:00
});
2026-01-31 21:05:36 -08:00
test ( 'CSI Ps " q - Select character protection attribute (DECSCA), VT220.' , async () => {
await ctx . proxy . write ( '\x1b[1"q' );
await ctx . proxy . write ( 'PROT' );
await ctx . proxy . write ( '\x1b[2"q' );
await ctx . proxy . write ( 'open' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'PROTopen' ]);
await ctx . proxy . write ( '\x1b[1;1H\x1b[?2K' );
await pollFor ( ctx . page , () => getLinesAsArray ( 1 ), [ 'PROT' ]);
2023-09-02 07:19:32 -07:00
});
test . skip ( 'CSI # q - Pop video attributes from stack (XTPOPSGR), xterm.' , async () => {
// TODO: Implement
});
2026-01-31 18:21:32 -08:00
test ( 'CSI Ps ; Ps r - Set Scrolling Region [top;bottom] (default = full size of window) (DECSTBM), VT100.' , async () => {
const rows = await ctx . proxy . rows ;
await ctx . proxy . write ( '\x1b[2;4r' );
await pollFor ( ctx . page , () => ctx . page . evaluate ( `({ top: window.term._core._bufferService.buffer.scrollTop, bottom: window.term._core._bufferService.buffer.scrollBottom })` ), { top : 1 , bottom : 3 });
await ctx . proxy . write ( '\x1b[r' );
await pollFor ( ctx . page , () => ctx . page . evaluate ( `({ top: window.term._core._bufferService.buffer.scrollTop, bottom: window.term._core._bufferService.buffer.scrollBottom })` ), { top : 0 , bottom : rows - 1 });
2023-09-02 07:19:32 -07:00
});
test . skip ( 'CSI ? Pm r - Restore DEC Private Mode Values (XTRESTORE), xterm.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Pt ; Pl ; Pb ; Pr ; Pm $ r - Change Attributes in Rectangular Area (DECCARA), VT400 and up.' , async () => {
// TODO: Implement
});
2026-01-31 18:21:32 -08:00
test ( 'CSI s - Save cursor, available only when DECLRMM is disabled (SCOSC, also ANSI.SYS).' , async () => {
await ctx . proxy . write ( '\x1b[3;4H' );
await ctx . proxy . write ( '\x1b[s' );
await ctx . proxy . write ( '\x1b[1;1H' );
await ctx . proxy . write ( '\x1b[u' );
await pollFor ( ctx . page , () => getCursor (), { col : 3 , row : 2 });
2023-09-02 07:19:32 -07:00
});
test . skip ( 'CSI Pl ; Pr s - Set left and right margins (DECSLRM), VT420 and up.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI > Ps s - Set/reset shift-escape options (XTSHIFTESCAPE), xterm.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI ? Pm s - Save DEC Private Mode Values (XTSAVE), xterm. Ps values are the same as for DECSET.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI > Pm t - This xterm control sets one or more features of the title modes (XTSMTITLE), xterm.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Ps SP t - Set warning-bell volume (DECSWBV), VT520.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Pt ; Pl ; Pb ; Pr ; Pm $ t - Reverse Attributes in Rectangular Area (DECRARA), VT400 and up.' , async () => {
// TODO: Implement
});
2026-01-31 18:21:32 -08:00
test ( 'CSI u - Restore cursor (SCORC, also ANSI.SYS).' , async () => {
await ctx . proxy . write ( '\x1b[4;6H' );
await ctx . proxy . write ( '\x1b[s' );
await ctx . proxy . write ( '\x1b[1;1H' );
await ctx . proxy . write ( '\x1b[u' );
await pollFor ( ctx . page , () => getCursor (), { col : 5 , row : 3 });
2023-09-02 07:19:32 -07:00
});
test . skip ( 'CSI Ps SP u - Set margin-bell volume (DECSMBV), VT520.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Pt ; Pl ; Pb ; Pr ; Pp ; Pt ; Pl ; Pp $ v - Copy Rectangular Area (DECCRA), VT400 and up.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Ps $ w - Request presentation state report (DECRQPSR), VT320 and up.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Pt ; Pl ; Pb ; Pr \' w - Enable Filter Rectangle (DECEFR), VT420 and up.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Ps x - Request Terminal Parameters (DECREQTPARM).' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Ps * x - Select Attribute Change Extent (DECSACE), VT420 and up.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Pc ; Pt ; Pl ; Pb ; Pr $ x - Fill Rectangular Area (DECFRA), VT420 and up.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Ps # y - Select checksum extension (XTCHECKSUM), xterm.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Pi ; Pg ; Pt ; Pl ; Pb ; Pr * y - Request Checksum of Rectangular Area (DECRQCRA), VT420 and up.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Ps ; Pu \' z - Enable Locator Reporting (DECELR).' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Pt ; Pl ; Pb ; Pr $ z - Erase Rectangular Area (DECERA), VT400 and up.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Pm \' { - Select Locator Events (DECSLE).' , async () => {
// TODO: Implement
});
test . skip ( 'CSI [Pm] # { Push video attributes onto stack (XTPUSHSGR), xterm.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Pt ; Pl ; Pb ; Pr $ { - Selective Erase Rectangular Area (DECSERA), VT400 and up.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Pt ; Pl ; Pb ; Pr # | - Report selected graphic rendition (XTREPORTSGR), xterm.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Ps $ | - Select columns per page (DECSCPP), VT340.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Ps \' | - Request Locator Position (DECRQLP).' , async () => {
// TODO: Implement
});
test . skip ( 'CSI Ps * | - Select number of lines per screen (DECSNLS), VT420 and up.' , async () => {
// TODO: Implement
});
test . skip ( 'CSI # } - Pop video attributes from stack (XTPOPSGR), xterm.' , async () => {
// TODO: Implement
});
2026-01-31 18:21:32 -08:00
test ( 'CSI Ps \' } - Insert Ps Column(s) (default = 1) (DECIC), VT420 and up.' , async () => {
await ctx . proxy . resize ( 5 , 5 );
await ctx . proxy . write ( '12345' . repeat ( 6 ));
await ctx . proxy . write ( '\x1b[3;3H' );
await ctx . proxy . write ( '\x1b[\'}' );
await pollFor ( ctx . page , () => getLinesAsArray ( 6 ), [ '12345' , '12 34' , '12 34' , '12 34' , '12 34' , '12 34' ]);
2023-09-02 07:19:32 -07:00
});
test . skip ( 'CSI Ps $ } - Select active status display (DECSASD), VT320 and up.' , async () => {
// TODO: Implement
});
2026-01-31 18:21:32 -08:00
test ( 'CSI Ps \' ~ - Delete Ps Column(s) (default = 1) (DECDC), VT420 and up.' , async () => {
await ctx . proxy . resize ( 5 , 5 );
await ctx . proxy . write ( '12345' . repeat ( 6 ));
await ctx . proxy . write ( '\x1b[3;3H' );
await ctx . proxy . write ( '\x1b[\'~' );
await pollFor ( ctx . page , () => getLinesAsArray ( 6 ), [ '12345' , '1245' , '1245' , '1245' , '1245' , '1245' ]);
2023-09-02 07:19:32 -07:00
});
test . skip ( 'CSI Ps $ ~ - Select status line type (DECSSDT), VT320 and up.' , async () => {
// TODO: Implement
});
test . describe ( 'CSI Ps ; Ps ; Ps t - Window Options' , () => {
test ( 'should be disabled by default' , async () => {
2025-12-30 05:27:28 -08:00
await ctx . proxy . write ( '\x1b[14t' );
await ctx . proxy . write ( '\x1b[16t' );
await ctx . proxy . write ( '\x1b[18t' );
await ctx . proxy . write ( '\x1b[20t' );
await ctx . proxy . write ( '\x1b[21t' );
deepStrictEqual ( recordedData , []);
2023-09-02 07:19:32 -07:00
});
test ( '14 - GetWinSizePixels' , async () => {
2025-12-30 05:27:28 -08:00
await ctx . proxy . setOption ( 'windowOptions' , { getWinSizePixels : true });
await ctx . proxy . write ( '\x1b[14t' );
2023-09-02 07:19:32 -07:00
const d = await getDimensions ();
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ ` \ x1b[4; ${ d . height } ; ${ d . width } t` ]);
2023-09-02 07:19:32 -07:00
});
test ( '16 - GetCellSizePixels' , async () => {
2025-12-30 05:27:28 -08:00
await ctx . proxy . setOption ( 'windowOptions' , { getCellSizePixels : true });
await ctx . proxy . write ( '\x1b[16t' );
2023-09-02 07:19:32 -07:00
const d = await getDimensions ();
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ ` \ x1b[6; ${ d . cellHeight } ; ${ d . cellWidth } t` ]);
2023-09-02 07:19:32 -07:00
});
});
});
test . describe ( 'OSC' , () => {
test . describe ( 'OSC 4' , () => {
test ( 'query single color' , async () => {
await ctx . proxy . write ( '\x1b]4;0;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]4;0;rgb:2e2e/3434/3636\x1b\\' ]);
2023-09-02 07:19:32 -07:00
await ctx . proxy . write ( '\x1b]4;77;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]4;0;rgb:2e2e/3434/3636\x1b\\' , '\x1b]4;77;rgb:5f5f/d7d7/5f5f\x1b\\' ]);
2023-09-02 07:19:32 -07:00
});
test ( 'query multiple colors' , async () => {
await ctx . proxy . write ( '\x1b]4;0;?;77;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]4;0;rgb:2e2e/3434/3636\x1b\\' , '\x1b]4;77;rgb:5f5f/d7d7/5f5f\x1b\\' ]);
2023-09-02 07:19:32 -07:00
});
test ( 'set & query single color' , async () => {
await ctx . proxy . write ( '\x1b]4;0;?\x07' );
2025-12-30 05:27:28 -08:00
const restore = [... recordedData ];
deepStrictEqual ( recordedData , restore );
2023-09-02 07:19:32 -07:00
// set new color & query
await ctx . proxy . write ( '\x1b]4;0;rgb:01/02/03\x07\x1b]4;0;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ restore [ 0 ], '\x1b]4;0;rgb:0101/0202/0303\x1b\\' ]);
2023-09-02 07:19:32 -07:00
// restore should set old color
await ctx . proxy . write ( restore [ 0 ] + '\x1b]4;0;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ restore [ 0 ], '\x1b]4;0;rgb:0101/0202/0303\x1b\\' , restore [ 0 ]]);
2023-09-02 07:19:32 -07:00
});
test ( 'query & set colors mixed' , async () => {
await ctx . proxy . write ( '\x1b]4;0;?;77;?\x07' );
2025-12-30 05:27:28 -08:00
const restore = [... recordedData ];
recordedData . length = 0 ;
2023-09-02 07:19:32 -07:00
// mixed call - change 0, query 43, change 77
await ctx . proxy . write ( '\x1b]4;0;rgb:01/02/03;43;?;77;#aabbcc\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]4;43;rgb:0000/d7d7/afaf\x1b\\' ]);
recordedData . length = 0 ;
2023-09-02 07:19:32 -07:00
// query new values for 0 + 77
await ctx . proxy . write ( '\x1b]4;0;?;77;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]4;0;rgb:0101/0202/0303\x1b\\' , '\x1b]4;77;rgb:aaaa/bbbb/cccc\x1b\\' ]);
recordedData . length = 0 ;
2023-09-02 07:19:32 -07:00
// restore old values for 0 + 77
await ctx . proxy . write ( restore [ 0 ] + restore [ 1 ] + '\x1b]4;0;?;77;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , restore );
2023-09-02 07:19:32 -07:00
});
});
test . describe ( 'OSC 4 & 104' , () => {
test ( 'change & restore single color' , async () => {
// test for some random color slots
for ( const i of [ 0 , 43 , 77 , 255 ]) {
await ctx . proxy . write ( ` \ x1b]4; ${ i } ;? \ x07` );
2025-12-30 05:27:28 -08:00
const restore = [... recordedData ];
2023-09-02 07:19:32 -07:00
await ctx . proxy . write ( ` \ x1b]4; ${ i } ;rgb:01/02/03 \ x07 \ x1b]4; ${ i } ;? \ x07` );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ restore [ 0 ], ` \ x1b]4; ${ i } ;rgb:0101/0202/0303 \ x1b\\` ]);
2023-09-02 07:19:32 -07:00
// restore slot color
await ctx . proxy . write ( ` \ x1b]104; ${ i } \ x07 \ x1b]4; ${ i } ;? \ x07` );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ restore [ 0 ], ` \ x1b]4; ${ i } ;rgb:0101/0202/0303 \ x1b\\` , restore [ 0 ]]);
recordedData . length = 0 ;
2023-09-02 07:19:32 -07:00
}
});
test ( 'restore multiple at once' , async () => {
// change 3 random slots
await ctx . proxy . write ( ` \ x1b]4;0;?;43;?;77;? \ x07` );
2025-12-30 05:27:28 -08:00
const restore = [... recordedData ];
recordedData . length = 0 ;
2023-09-02 07:19:32 -07:00
await ctx . proxy . write ( ` \ x1b]4;0;rgb:01/02/03;43;#aabbcc;77;#123456 \ x07` );
// restore specific slots
await ctx . proxy . write ( ` \ x1b]104;0;43;77 \ x07` + ` \ x1b]4;0;?;43;?;77;? \ x07` );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , restore );
2023-09-02 07:19:32 -07:00
});
test ( 'restore full table' , async () => {
// change 3 random slots
await ctx . proxy . write ( ` \ x1b]4;0;?;43;?;77;? \ x07` );
2025-12-30 05:27:28 -08:00
const restore = [... recordedData ];
recordedData . length = 0 ;
2023-09-02 07:19:32 -07:00
await ctx . proxy . write ( ` \ x1b]4;0;rgb:01/02/03;43;#aabbcc;77;#123456 \ x07` );
// restore all
await ctx . proxy . write ( ` \ x1b]104 \ x07` + ` \ x1b]4;0;?;43;?;77;? \ x07` );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , restore );
2023-09-02 07:19:32 -07:00
});
});
test . describe ( 'OSC 10 & 11 + 110 | 111 | 112' , () => {
test ( 'query FG color' , async () => {
await ctx . proxy . write ( '\x1b]10;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]10;rgb:ffff/ffff/ffff\x1b\\' ]);
2023-09-02 07:19:32 -07:00
});
test ( 'query BG color' , async () => {
await ctx . proxy . write ( '\x1b]11;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]11;rgb:0000/0000/0000\x1b\\' ]);
2023-09-02 07:19:32 -07:00
});
test ( 'query FG & BG color in one call' , async () => {
await ctx . proxy . write ( '\x1b]10;?;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]10;rgb:ffff/ffff/ffff\x1b\\' , '\x1b]11;rgb:0000/0000/0000\x1b\\' ]);
2023-09-02 07:19:32 -07:00
});
test ( 'set & query FG' , async () => {
await ctx . proxy . write ( '\x1b]10;rgb:1/2/3\x07\x1b]10;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]10;rgb:1111/2222/3333\x1b\\' ]);
2023-09-02 07:19:32 -07:00
await ctx . proxy . write ( '\x1b]10;#ffffff\x07\x1b]10;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]10;rgb:1111/2222/3333\x1b\\' , '\x1b]10;rgb:ffff/ffff/ffff\x1b\\' ]);
2023-09-02 07:19:32 -07:00
});
test ( 'set & query BG' , async () => {
await ctx . proxy . write ( '\x1b]11;rgb:1/2/3\x07\x1b]11;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]11;rgb:1111/2222/3333\x1b\\' ]);
2023-09-02 07:19:32 -07:00
await ctx . proxy . write ( '\x1b]11;#000000\x07\x1b]11;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]11;rgb:1111/2222/3333\x1b\\' , '\x1b]11;rgb:0000/0000/0000\x1b\\' ]);
2023-09-02 07:19:32 -07:00
});
test ( 'set & query cursor color' , async () => {
await ctx . proxy . write ( '\x1b]12;rgb:1/2/3\x07\x1b]12;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]12;rgb:1111/2222/3333\x1b\\' ]);
2023-09-02 07:19:32 -07:00
await ctx . proxy . write ( '\x1b]12;#ffffff\x07\x1b]12;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]12;rgb:1111/2222/3333\x1b\\' , '\x1b]12;rgb:ffff/ffff/ffff\x1b\\' ]);
2023-09-02 07:19:32 -07:00
});
test ( 'set & query FG & BG color in one call' , async () => {
await ctx . proxy . write ( '\x1b]10;#123456;rgb:aa/bb/cc\x07\x1b]10;?;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]10;rgb:1212/3434/5656\x1b\\' , '\x1b]11;rgb:aaaa/bbbb/cccc\x1b\\' ]);
2023-09-02 07:19:32 -07:00
await ctx . proxy . write ( '\x1b]10;#ffffff;#000000\x07' );
});
test ( 'OSC 110: restore FG color' , async () => {
await ctx . proxy . write ( '\x1b]10;rgb:1/2/3\x07\x1b]10;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]10;rgb:1111/2222/3333\x1b\\' ]);
recordedData . length = 0 ;
2023-09-02 07:19:32 -07:00
// restore
await ctx . proxy . write ( '\x1b]110\x07\x1b]10;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]10;rgb:ffff/ffff/ffff\x1b\\' ]);
2023-09-02 07:19:32 -07:00
});
test ( 'OSC 111: restore BG color' , async () => {
await ctx . proxy . write ( '\x1b]11;rgb:1/2/3\x07\x1b]11;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]11;rgb:1111/2222/3333\x1b\\' ]);
recordedData . length = 0 ;
2023-09-02 07:19:32 -07:00
// restore
await ctx . proxy . write ( '\x1b]111\x07\x1b]11;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]11;rgb:0000/0000/0000\x1b\\' ]);
2023-09-02 07:19:32 -07:00
});
test ( 'OSC 112: restore cursor color' , async () => {
await ctx . proxy . write ( '\x1b]12;rgb:1/2/3\x07\x1b]12;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]12;rgb:1111/2222/3333\x1b\\' ]);
recordedData . length = 0 ;
2023-09-02 07:19:32 -07:00
// restore
await ctx . proxy . write ( '\x1b]112\x07\x1b]12;?\x07' );
2025-12-30 05:27:28 -08:00
deepStrictEqual ( recordedData , [ '\x1b]12;rgb:ffff/ffff/ffff\x1b\\' ]);
2023-09-02 07:19:32 -07:00
});
});
});
test . describe ( 'ESC' , () => {
test . describe ( 'DECRC: Save cursor, ESC 7' , () => {
test ( 'should save the absolute cursor position so resizing restores to the correct position' , async () => {
2025-12-30 05:27:28 -08:00
await ctx . proxy . resize ( 10 , 2 );
await ctx . proxy . write ( '1\n\r2\n\r3\n\r4\n\r5' );
await ctx . proxy . write ( '\x1b7\x1b[?47h' );
await ctx . proxy . resize ( 10 , 4 );
await ctx . proxy . write ( '\x1b[?47l\x1b8' );
2023-09-02 07:19:32 -07:00
await pollFor ( ctx . page , () => getCursor (), { col : 1 , row : 3 });
});
});
});
});
2026-01-31 22:01:35 -08:00
async function getModeSnapshot () : Promise < any > {
return {
modes : await ctx . proxy . modes ,
cursorBlink : await ctx . proxy . getOption ( 'cursorBlink' ),
cols : await ctx . proxy . cols ,
rows : await ctx . proxy . rows ,
bufferType : await ctx . proxy . buffer . active . type ,
mouseProtocol : await ctx . proxy . core . evaluate (([ core ]) => core . coreMouseService . activeProtocol ),
mouseEncoding : await ctx . proxy . core . evaluate (([ core ]) => core . coreMouseService . activeEncoding )
};
}
async function assertNoModeChange ( sequence : string ) : Promise < void > {
const before = await getModeSnapshot ();
await ctx . proxy . write ( sequence );
deepStrictEqual ( await getModeSnapshot (), before );
}
2023-09-02 07:19:32 -07:00
async function getLinesAsArray ( count : number , start : number = 0 ) : Promise < string [] > {
let text = '' ;
for ( let i = start ; i < start + count ; i ++ ) {
text += `window.term.buffer.active.getLine( ${ i } ).translateToString(true),` ;
}
return await ctx . page . evaluate ( `[ ${ text } ]` );
}
async function simulatePaste ( text : string ) : Promise < string > {
const id = Math . floor ( Math . random () * 1000000 );
await ctx . page . evaluate ( `
2025-12-30 05:27:28 -08:00
(function() {
window.disposable_ ${ id } = window.term.onData(e => window.result_ ${ id } = e);
const clipboardData = new DataTransfer();
clipboardData.setData('text/plain', ' ${ text } ');
window.term.textarea.dispatchEvent(new ClipboardEvent('paste', { clipboardData }));
})();
` );
const result = await ctx . page . evaluate < string >( `window.result_ ${ id } ` );
await ctx . page . evaluate ( `window.disposable_ ${ id } .dispose()` );
return result ;
2023-09-02 07:19:32 -07:00
}
2026-01-31 18:21:32 -08:00
async function dragSelection () : Promise < number > {
await ctx . proxy . clearSelection ();
const coords : { left : number , top : number , bottom : number , right : number } = await ctx . page . evaluate ( `
(function() {
const rect = window.term.element.getBoundingClientRect();
return { left: rect.left, top: rect.top, bottom: rect.bottom, right: rect.right };
})();
` );
await ctx . page . mouse . click (( coords . left + coords . right ) / 2 , ( coords . top + coords . bottom ) / 2 );
await ctx . page . mouse . down ();
await ctx . page . mouse . move (( coords . left + coords . right ) / 2 , ( coords . top + coords . bottom ) / 4 );
await ctx . page . mouse . up ();
return ( await ctx . proxy . getSelection ()). length ;
}
2023-09-02 07:19:32 -07:00
async function getCursor () : Promise < { col : number , row : number } > {
2025-12-30 05:27:28 -08:00
return {
col : await ctx . proxy . buffer . active . cursorX ,
row : await ctx . proxy . buffer . active . cursorY
};
2023-09-02 07:19:32 -07:00
}
async function getDimensions () : Promise < any > {
2025-12-30 05:27:28 -08:00
const dim = await ctx . proxy . dimensions ;
2023-09-02 07:19:32 -07:00
return {
2025-12-30 05:27:28 -08:00
cellWidth : dim ! . css . cell . width . toFixed ( 0 ),
cellHeight : dim ! . css . cell . height . toFixed ( 0 ),
width : dim ! . css . canvas . width . toFixed ( 0 ),
height : dim ! . css . canvas . height . toFixed ( 0 )
2023-09-02 07:19:32 -07:00
};
}