diff --git a/addons/xterm-addon-serialize/src/SerializeAddon.ts b/addons/xterm-addon-serialize/src/SerializeAddon.ts index 5cd834b8..72780765 100644 --- a/addons/xterm-addon-serialize/src/SerializeAddon.ts +++ b/addons/xterm-addon-serialize/src/SerializeAddon.ts @@ -403,6 +403,35 @@ export class SerializeAddon implements ITerminalAddon { return handler.serialize(maxRows - correctRows, maxRows); } + private _serializeModes(terminal: Terminal): string { + let content = ''; + const modes = terminal.modes; + + // Default: false + if (modes.applicationCursorKeysMode) content += '\x1b[?1h'; + if (modes.applicationKeypadMode) content += '\x1b[?66h'; + if (modes.bracketedPasteMode) content += '\x1b[?2004h'; + if (modes.insertMode) content += '\x1b[4h'; + if (modes.originMode) content += '\x1b[?6h'; + if (modes.reverseWraparoundMode) content += '\x1b[?45h'; + if (modes.sendFocusMode) content += '\x1b[?1004h'; + + // Default: true + if (modes.wraparoundMode === false) content += '\x1b[?7l'; + + // Default: 'none' + if (modes.mouseTrackingMode !== 'none') { + switch (modes.mouseTrackingMode) { + case 'x10': content += '\x1b[?9h'; break; + case 'vt200': content += '\x1b[?1000h'; break; + case 'drag': content += '\x1b[?1002h'; break; + case 'any': content += '\x1b[?1003h'; break; + } + } + + return content; + } + public serialize(scrollback?: number): string { // TODO: Add combinedData support if (!this._terminal) { @@ -418,6 +447,9 @@ export class SerializeAddon implements ITerminalAddon { content += `\u001b[?1049h\u001b[H${alternativeScreenContent}`; } + // Modes + content += this._serializeModes(this._terminal); + return content; } diff --git a/addons/xterm-addon-serialize/test/SerializeAddon.api.ts b/addons/xterm-addon-serialize/test/SerializeAddon.api.ts index c8b7302f..87f77f59 100644 --- a/addons/xterm-addon-serialize/test/SerializeAddon.api.ts +++ b/addons/xterm-addon-serialize/test/SerializeAddon.api.ts @@ -30,6 +30,12 @@ const testNormalScreenEqual = async (page: any, str: string): Promise => { assert.equal(JSON.stringify(originalBuffer), JSON.stringify(newBuffer)); }; +async function testSerializeEquals(writeContent: string, expectedSerialized: string): Promise { + await writeRawSync(page, writeContent); + const result = await page.evaluate(`serializeAddon.serialize();`) as string; + assert.strictEqual(result, expectedSerialized); +} + describe('SerializeAddon', () => { before(async function(): Promise { const browserType = getBrowserType(); @@ -479,6 +485,52 @@ describe('SerializeAddon', () => { await testNormalScreenEqual(page, lines.join('')); }); + + describe('handle modes', () => { + it('applicationCursorKeysMode', async () => { + await testSerializeEquals('test\u001b[?1h', 'test\u001b[?1h'); + await testSerializeEquals('\u001b[?1l', 'test'); + }); + it('applicationKeypadMode', async () => { + await testSerializeEquals('test\u001b[?66h', 'test\u001b[?66h'); + await testSerializeEquals('\u001b[?66l', 'test'); + }); + it('bracketedPasteMode', async () => { + await testSerializeEquals('test\u001b[?2004h', 'test\u001b[?2004h'); + await testSerializeEquals('\u001b[?2004l', 'test'); + }); + it('insertMode', async () => { + await testSerializeEquals('test\u001b[4h', 'test\u001b[4h'); + await testSerializeEquals('\u001b[4l', 'test'); + }); + it('mouseTrackingMode', async () => { + await testSerializeEquals('test\u001b[?9h', 'test\u001b[?9h'); + await testSerializeEquals('\u001b[?9l', 'test'); + await testSerializeEquals('\u001b[?1000h', 'test\u001b[?1000h'); + await testSerializeEquals('\u001b[?1000l', 'test'); + await testSerializeEquals('\u001b[?1002h', 'test\u001b[?1002h'); + await testSerializeEquals('\u001b[?1002l', 'test'); + await testSerializeEquals('\u001b[?1003h', 'test\u001b[?1003h'); + await testSerializeEquals('\u001b[?1003l', 'test'); + }); + it('originMode', async () => { + // origin mode moves cursor to (0,0) + await testSerializeEquals('test\u001b[?6h', 'test\u001b[4D\u001b[?6h'); + await testSerializeEquals('\u001b[?6l', 'test\u001b[4D'); + }); + it('reverseWraparoundMode', async () => { + await testSerializeEquals('test\u001b[?45h', 'test\u001b[?45h'); + await testSerializeEquals('\u001b[?45l', 'test'); + }); + it('sendFocusMode', async () => { + await testSerializeEquals('test\u001b[?1004h', 'test\u001b[?1004h'); + await testSerializeEquals('\u001b[?1004l', 'test'); + }); + it('wraparoundMode', async () => { + await testSerializeEquals('test\u001b[?7l', 'test\u001b[?7l'); + await testSerializeEquals('\u001b[?7h', 'test'); + }); + }); }); function newArray(initial: T | ((index: number) => T), count: number): T[] {