From 1c4a71f0df478144a1ca9f1e45420bcc39e23ab4 Mon Sep 17 00:00:00 2001 From: Per Bothner Date: Sun, 9 Dec 2018 10:56:34 -0800 Subject: [PATCH 1/3] Optimize parsing of OSC_STRING to minimize string concatenation. --- src/EscapeSequenceParser.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/EscapeSequenceParser.ts b/src/EscapeSequenceParser.ts index b38c50f543..dbb14058f1 100644 --- a/src/EscapeSequenceParser.ts +++ b/src/EscapeSequenceParser.ts @@ -391,7 +391,11 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP } // normal transition & action lookup - transition = (code < 0xa0) ? (table[currentState << 8 | code]) : DEFAULT_TRANSITION; + transition = (code < 0xa0 + ? (table[currentState << 8 | code]) + : currentState === ParserState.OSC_STRING + ? (ParserAction.OSC_PUT << 4) | ParserState.OSC_STRING + : DEFAULT_TRANSITION); switch (transition >> 4) { case ParserAction.PRINT: print = (~print) ? print : i; @@ -423,10 +427,6 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP case ParserState.GROUND: print = (~print) ? print : i; break; - case ParserState.OSC_STRING: - osc += String.fromCharCode(code); - transition |= ParserState.OSC_STRING; - break; case ParserState.CSI_IGNORE: transition |= ParserState.CSI_IGNORE; break; @@ -517,7 +517,16 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP osc = ''; break; case ParserAction.OSC_PUT: - osc += data.charAt(i); + for (let j = i + 1; ; j++) { + if (j >= l + || ((code = data.charCodeAt(j)) <= 0x9f + && (table[ParserState.OSC_STRING << 8 | code] >> 4 + !== ParserAction.OSC_PUT))) { + osc += data.substring(i, j); + i = j - 1; + break; + } + } break; case ParserAction.OSC_END: if (osc && code !== 0x18 && code !== 0x1a) { From 2cb293ceb270823dae117d777e995408c563eda1 Mon Sep 17 00:00:00 2001 From: Per Bothner Date: Sun, 9 Dec 2018 19:03:58 -0800 Subject: [PATCH 2/3] Further tweaks to optimize parsing of OSC_STRING. --- src/EscapeSequenceParser.ts | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/EscapeSequenceParser.ts b/src/EscapeSequenceParser.ts index dbb14058f1..3fa3ba49e3 100644 --- a/src/EscapeSequenceParser.ts +++ b/src/EscapeSequenceParser.ts @@ -67,7 +67,8 @@ const PRINTABLES = r(0x20, 0x7f); const EXECUTABLES = r(0x00, 0x18); EXECUTABLES.push(0x19); EXECUTABLES.push.apply(EXECUTABLES, r(0x1c, 0x20)); -const DEFAULT_TRANSITION = ParserAction.ERROR << 4 | ParserState.GROUND; +// Pseudo-character placeholder for printable non-ascii characters. +const NON_ASCII_PRINTABLE = 0xA0; /** * VT500 compatible transition table. @@ -79,7 +80,7 @@ export const VT500_TRANSITION_TABLE = (function (): TransitionTable { const states: number[] = r(ParserState.GROUND, ParserState.DCS_PASSTHROUGH + 1); let state: any; - // table with default transition [any] --> DEFAULT_TRANSITION + // table with default transition for (state in states) { // NOTE: table lookup is capped at 0xa0 in parse to keep the table small for (let code = 0; code < 160; ++code) { @@ -184,6 +185,7 @@ export const VT500_TRANSITION_TABLE = (function (): TransitionTable { 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.add(NON_ASCII_PRINTABLE, ParserState.OSC_STRING, ParserAction.OSC_PUT, ParserState.OSC_STRING); return table; })(); @@ -391,11 +393,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP } // normal transition & action lookup - transition = (code < 0xa0 - ? (table[currentState << 8 | code]) - : currentState === ParserState.OSC_STRING - ? (ParserAction.OSC_PUT << 4) | ParserState.OSC_STRING - : DEFAULT_TRANSITION); + transition = table[currentState << 8 | (code < 0xa0 ? code : NON_ASCII_PRINTABLE)]; switch (transition >> 4) { case ParserAction.PRINT: print = (~print) ? print : i; @@ -519,9 +517,8 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP case ParserAction.OSC_PUT: for (let j = i + 1; ; j++) { if (j >= l - || ((code = data.charCodeAt(j)) <= 0x9f - && (table[ParserState.OSC_STRING << 8 | code] >> 4 - !== ParserAction.OSC_PUT))) { + || (code = data.charCodeAt(j)) < 0x20 + || (code > 0x7f && code <= 0x9f)) { osc += data.substring(i, j); i = j - 1; break; From 2d8f420db8db4ca1c53053da3cb385545b004e9d Mon Sep 17 00:00:00 2001 From: jerch Date: Mon, 10 Dec 2018 16:37:48 +0100 Subject: [PATCH 3/3] fix default transition for 0xa0 --- src/EscapeSequenceParser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EscapeSequenceParser.ts b/src/EscapeSequenceParser.ts index 3fa3ba49e3..f489884177 100644 --- a/src/EscapeSequenceParser.ts +++ b/src/EscapeSequenceParser.ts @@ -83,7 +83,7 @@ export const VT500_TRANSITION_TABLE = (function (): TransitionTable { // table with default transition for (state in states) { // NOTE: table lookup is capped at 0xa0 in parse to keep the table small - for (let code = 0; code < 160; ++code) { + for (let code = 0; code <= NON_ASCII_PRINTABLE; ++code) { table.add(code, state, ParserAction.ERROR, ParserState.GROUND); } }