diff --git a/src/common/parser/EscapeSequenceParser.test.ts b/src/common/parser/EscapeSequenceParser.test.ts index a5bcbfb7..5c4fe5b0 100644 --- a/src/common/parser/EscapeSequenceParser.test.ts +++ b/src/common/parser/EscapeSequenceParser.test.ts @@ -34,7 +34,8 @@ class MockOscPutParser implements IOscParser { } public dispose(): void { } public start(): void { } - public end(): void { + public end(success: boolean): void { + this.data += `, success: ${success}`; const id = parseInt(this.data.slice(0, this.data.indexOf(';'))); if (!isNaN(id)) { this._fallback(id, 'END', this.data.slice(this.data.indexOf(';') + 1)); @@ -121,8 +122,8 @@ const testTerminal: any = { actionDCSPrint: function (s: string): void { this.calls.push(['dcs put', s]); }, - actionDCSUnhook: function (): void { - this.calls.push(['dcs unhook']); + actionDCSUnhook: function (success: boolean): void { + this.calls.push(['dcs unhook', success]); } }; @@ -172,7 +173,7 @@ testParser.setDcsHandlerFallback((collectAndFlag, action, payload) => { testTerminal.actionDCSPrint(payload); break; case 'UNHOOK': - testTerminal.actionDCSUnhook(); + testTerminal.actionDCSUnhook(payload); } }); @@ -253,7 +254,8 @@ describe('EscapeSequenceParser', function (): void { '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97', '\x99', '\x9a' ]; const exceptions: { [key: number]: { [key: string]: any[] } } = { - 8: { '\x18': [], '\x1a': [] } // simply abort osc state + 8: { '\x18': [], '\x1a': [] }, // abort OSC_STRING + 13: { '\x18': [['dcs unhook', false]], '\x1a': [['dcs unhook', false]] } // abort DCS_PASSTHROUGH }; parser.reset(); testTerminal.clear(); @@ -1025,14 +1027,14 @@ describe('EscapeSequenceParser', function (): void { }); it('OSC', function (): void { test('\x1b]0;abc123€öäü\x07', [ - ['osc', '0;abc123€öäü'] + ['osc', '0;abc123€öäü, success: true'] ], null); }); it('single DCS', function (): void { test('\x1bP1;2;3+$aäbc;däe\x9c', [ ['dcs hook', [1, 2, 3]], ['dcs put', 'äbc;däe'], - ['dcs unhook'] + ['dcs unhook', true] ], null); }); it('multi DCS', function (): void { @@ -1043,7 +1045,7 @@ describe('EscapeSequenceParser', function (): void { testTerminal.clear(); test('abc\x9c', [ ['dcs put', 'abc'], - ['dcs unhook'] + ['dcs unhook', true] ], true); }); it('print + DCS(C1)', function (): void { @@ -1051,7 +1053,7 @@ describe('EscapeSequenceParser', function (): void { ['print', 'abc'], ['dcs hook', [1, 2, 3]], ['dcs put', 'bc;de'], - ['dcs unhook'] + ['dcs unhook', true] ], null); }); it('print + PM(C1) + print', function (): void { @@ -1063,7 +1065,7 @@ describe('EscapeSequenceParser', function (): void { it('print + OSC(C1) + print', function (): void { test('abc\x9d123;tzf\x9cdefg', [ ['print', 'abc'], - ['osc', '123;tzf'], + ['osc', '123;tzf, success: true'], ['print', 'defg'] ], null); }); @@ -1076,7 +1078,7 @@ describe('EscapeSequenceParser', function (): void { it('7bit ST should be swallowed', function (): void { test('abc\x9d123;tzf\x1b\\defg', [ ['print', 'abc'], - ['osc', '123;tzf'], + ['osc', '123;tzf, success: true'], ['print', 'defg'] ], null); }); @@ -1094,7 +1096,33 @@ describe('EscapeSequenceParser', function (): void { ['print', 'abc'], ['dcs hook', [1, 2, [-1, 55], 3]], ['dcs put', 'bc;de'], - ['dcs unhook'] + ['dcs unhook', true] + ], null); + }); + it('CAN should abort DCS', () => { + test('abc\x901;2::55;3+$abc;de\x18', [ + ['print', 'abc'], + ['dcs hook', [1, 2, [-1, 55], 3]], + ['dcs put', 'bc;de'], + ['dcs unhook', false] // false for abort + ], null); + }); + it('SUB should abort DCS', () => { + test('abc\x901;2::55;3+$abc;de\x1a', [ + ['print', 'abc'], + ['dcs hook', [1, 2, [-1, 55], 3]], + ['dcs put', 'bc;de'], + ['dcs unhook', false] // false for abort + ], null); + }); + it('CAN should abort OSC', () => { + test('\x1b]0;abc123€öäü\x18', [ + ['osc', '0;abc123€öäü, success: false'] + ], null); + }); + it('SUB should abort OSC', () => { + test('\x1b]0;abc123€öäü\x1a', [ + ['osc', '0;abc123€öäü, success: false'] ], null); }); }); diff --git a/src/common/parser/EscapeSequenceParser.ts b/src/common/parser/EscapeSequenceParser.ts index 8342de4c..d40f39de 100644 --- a/src/common/parser/EscapeSequenceParser.ts +++ b/src/common/parser/EscapeSequenceParser.ts @@ -187,7 +187,7 @@ export const VT500_TRANSITION_TABLE = (function (): TransitionTable { table.addMany(EXECUTABLES, ParserState.DCS_PASSTHROUGH, ParserAction.DCS_PUT, ParserState.DCS_PASSTHROUGH); table.addMany(PRINTABLES, ParserState.DCS_PASSTHROUGH, ParserAction.DCS_PUT, ParserState.DCS_PASSTHROUGH); table.add(0x7f, ParserState.DCS_PASSTHROUGH, ParserAction.IGNORE, ParserState.DCS_PASSTHROUGH); - table.addMany([0x1b, 0x9c], ParserState.DCS_PASSTHROUGH, ParserAction.DCS_UNHOOK, ParserState.GROUND); + table.addMany([0x1b, 0x9c, 0x18, 0x1a], ParserState.DCS_PASSTHROUGH, ParserAction.DCS_UNHOOK, ParserState.GROUND); // special handling of unicode chars table.add(NON_ASCII_PRINTABLE, ParserState.GROUND, ParserAction.PRINT, ParserState.GROUND); table.add(NON_ASCII_PRINTABLE, ParserState.OSC_STRING, ParserAction.OSC_PUT, ParserState.OSC_STRING); @@ -591,7 +591,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP break; case ParserAction.DCS_PUT: // inner loop - exit DCS_PUT: 0x18, 0x1a, 0x1b, 0x7f, 0x80 - 0x9f - // unhook triggered by: 0x1b, 0x9c + // unhook triggered by: 0x1b, 0x9c (success) and 0x18, 0x1a (abort) for (let j = i + 1; ; ++j) { if (j >= length || (code = data[j]) === 0x18 || code === 0x1a || code === 0x1b || (code > 0x7f && code < NON_ASCII_PRINTABLE)) { dcs.put(data, i, j); @@ -601,7 +601,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP } break; case ParserAction.DCS_UNHOOK: - dcs.unhook(true); // FIXME: apply abort vs. success exit rules + dcs.unhook(code !== 0x18 && code !== 0x1a); if (code === 0x1b) transition |= ParserState.ESCAPE; osc.reset(); params.reset();