[vte] parser: Record intermediates in order



commit e25a901cf561a3b884f6ab83884309632e56e533
Author: Christian Persch <chpe src gnome org>
Date:   Tue Mar 27 19:40:13 2018 +0200

    parser: Record intermediates in order
    
    Previously the parser would store intermediates as
    a bit mask, which loses the order and, when matching,
    makes any permutation of the intermediates match the
    same sequence.
    
    This commit changes that to record the intermediates in
    the order they are used.
    
    Store the intermediate (and, for CSI and DCS sequences,
    the optional parameter character at the beginning of the
    parameters) in one unsigned int, packed as much as possible.
    
    Simplify the ESC, CSI and DCS matchers by using a combined
    code of final character and intermediates.

 src/Makefile.am    |   11 +-
 src/parser-cat.cc  |   69 +++--
 src/parser-cmd.hh  |    2 +
 src/parser-csi.hh  |  143 +++++++
 src/parser-dcs.hh  |   36 ++
 src/parser-esc.hh  |   49 +++
 src/parser-glue.hh |   24 +-
 src/parser-test.cc |  164 +++++++--
 src/parser.cc      | 1052 ++++++++++++++++-----------------------------------
 src/parser.hh      |  121 ++++---
 src/vteseq.cc      |   51 ++-
 11 files changed, 852 insertions(+), 870 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 2b2f6c5..37281c1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -64,6 +64,9 @@ libvte_@VTE_API_MAJOR_VERSION@_@VTE_API_MINOR_VERSION@_la_SOURCES = \
        parser-charset.hh \
        parser-charset-tables.hh \
        parser-cmd.hh \
+       parser-csi.hh \
+       parser-dcs.hh \
+       parser-esc.hh \
        parser-glue.hh \
        parser-osc.hh \
        parser-reply.hh \
@@ -250,6 +253,9 @@ parser_cat_SOURCES = \
        parser-charset.hh \
        parser-charset-tables.hh \
        parser-cmd.hh \
+       parser-csi.hh \
+       parser-dcs.hh \
+       parser-esc.hh \
        parser-glue.hh \
        parser-osc.hh \
        parser-reply.hh \
@@ -283,9 +289,12 @@ test_parser_SOURCES = \
        parser.cc \
        parser.hh \
        parser-arg.hh \
-       parser-cmd.hh \
        parser-charset.hh \
        parser-charset-tables.hh \
+       parser-cmd.hh \
+       parser-csi.hh \
+       parser-dcs.hh \
+       parser-esc.hh \
        parser-glue.hh \
        parser-osc.hh \
        parser-reply.hh \
diff --git a/src/parser-cat.cc b/src/parser-cat.cc
index 41d97f3..21462aa 100644
--- a/src/parser-cat.cc
+++ b/src/parser-cat.cc
@@ -138,10 +138,13 @@ private:
         char const* m_outro;
 };
 
-static bool
+static void
 print_params(GString* str,
              struct vte_seq const* seq)
 {
+        if (seq->n_args > 0)
+                g_string_append_c(str, ' ');
+
         for (unsigned int i = 0; i < seq->n_args; i++) {
                 auto arg = seq->args[i];
                 if (!vte_seq_arg_default(arg))
@@ -149,27 +152,46 @@ print_params(GString* str,
                 if (i + 1 < seq->n_args)
                         g_string_append_c(str, vte_seq_arg_nonfinal(arg) ? ':' : ';');
         }
+}
 
-        return seq->n_args > 0;
+static void
+print_pintro(GString* str,
+             unsigned int type,
+             unsigned int intermediates)
+{
+        if (type != VTE_SEQ_CSI &&
+            type != VTE_SEQ_DCS)
+                return;
+
+        unsigned int p = intermediates & 0x7;
+        if (p == 0)
+                return;
+
+        g_string_append_c(str, ' ');
+        g_string_append_c(str, 0x40 - p);
 }
 
-static bool
+static void
 print_intermediates(GString* str,
-                    unsigned int intermediates,
-                    unsigned int start,
-                    unsigned int end)
+                    unsigned int type,
+                    unsigned int intermediates)
 {
-        bool any = false;
-        for (unsigned int i = start; i <= end; i++) {
-                unsigned int mask = (1U << (i - 0x20));
+        if (type == VTE_SEQ_CSI ||
+            type == VTE_SEQ_DCS)
+                intermediates = intermediates >> 3; /* remove pintro */
 
-                if (intermediates & mask) {
-                        g_string_append_c(str, i);
-                        any = true;
-                }
-        }
+        while (intermediates != 0) {
+                unsigned int i = intermediates & 0x1f;
+                char c = 0x20 + i - 1;
+
+                g_string_append_c(str, ' ');
+                if (c == 0x20)
+                        g_string_append(str, "SP");
+                else
+                        g_string_append_c(str, c);
 
-        return any;
+                intermediates = intermediates >> 5;
+        }
 }
 
 static void
@@ -193,19 +215,14 @@ print_seq_and_params(GString* str,
         printer p(str, plain, SEQ_START, SEQ_END);
 
         if (seq->command != VTE_CMD_NONE) {
-                g_string_append_printf(str, "{%s ", cmd_to_str(seq->command));
+                g_string_append_printf(str, "{%s", cmd_to_str(seq->command));
                 print_params(str, seq);
                 g_string_append_c(str, '}');
         } else {
-                g_string_append_printf(str, "{%s ", seq_to_str(seq->type));
-                if ((seq->intermediates & 0xffff0000U) &&
-                    print_intermediates(str, seq->intermediates, 0x30, 0x3f))
-                        g_string_append_c(str, ' ');
-                if (print_params(str, seq))
-                        g_string_append_c(str, ' ');
-                if ((seq->intermediates & 0x0000ffffU) &&
-                    print_intermediates(str, seq->intermediates, 0x20, 0x2f))
-                        g_string_append_c(str, ' ');
+                g_string_append_printf(str, "{%s", seq_to_str(seq->type));
+                print_pintro(str, seq->type, seq->intermediates);
+                print_params(str, seq);
+                print_intermediates(str, seq->type, seq->intermediates);
                 g_string_append_printf(str, " %c}", seq->terminator);
         }
 }
diff --git a/src/parser-cmd.hh b/src/parser-cmd.hh
index e57e2c7..29fb212 100644
--- a/src/parser-cmd.hh
+++ b/src/parser-cmd.hh
@@ -71,6 +71,7 @@ _VTE_CMD(DECLFKC) /* local-function-key-control */
 _VTE_CMD(DECLL) /* load-leds */
 _VTE_CMD(DECLTOD) /* load-time-of-day */
 _VTE_CMD(DECPCTERM) /* pcterm-mode */
+_VTE_CMD(DECPCTERM_OR_XTERM_RPM) /* ambiguous */
 _VTE_CMD(DECPAK) /* program-alphanumeric-key */
 _VTE_CMD(DECPFK) /* program-function-key */
 _VTE_CMD(DECPKA) /* program-key-action */
@@ -180,6 +181,7 @@ _VTE_CMD(RIS) /* reset-to-initial-state */
 _VTE_CMD(RM_ECMA) /* reset-mode-ecma */
 _VTE_CMD(RM_DEC) /* reset-mode-dec */
 _VTE_CMD(SD) /* scroll-down */
+_VTE_CMD(SD_OR_XTERM_IHMT) /* ambiguous */
 _VTE_CMD(SGR) /* select-graphics-rendition */
 _VTE_CMD(SI) /* shift-in */
 _VTE_CMD(SM_ECMA) /* set-mode-ecma */
diff --git a/src/parser-csi.hh b/src/parser-csi.hh
new file mode 100644
index 0000000..01326ad
--- /dev/null
+++ b/src/parser-csi.hh
@@ -0,0 +1,143 @@
+/*
+ * Copyright © 2015 David Herrmann <dh herrmann gmail com>
+ * Copyright © 2018 Christian Persch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+_VTE_SEQ(ICH,                    CSI,    '@',  NONE,  0, NONE     ) /* insert-character */
+_VTE_SEQ(CUU,                    CSI,    'A',  NONE,  0, NONE     ) /* cursor-up */
+_VTE_SEQ(CUD,                    CSI,    'B',  NONE,  0, NONE     ) /* cursor-down */
+_VTE_SEQ(CUF,                    CSI,    'C',  NONE,  0, NONE     ) /* cursor-forward */
+_VTE_SEQ(CUB,                    CSI,    'D',  NONE,  0, NONE     ) /* cursor-backward */
+_VTE_SEQ(CNL,                    CSI,    'E',  NONE,  0, NONE     ) /* cursor-next-line */
+_VTE_SEQ(CPL,                    CSI,    'F',  NONE,  0, NONE     ) /* cursor-previous-line */
+_VTE_SEQ(CHA,                    CSI,    'G',  NONE,  0, NONE     ) /* cursor-horizontal-absolute */
+_VTE_SEQ(CUP,                    CSI,    'H',  NONE,  0, NONE     ) /* cursor-position */
+_VTE_SEQ(CHT,                    CSI,    'I',  NONE,  0, NONE     ) /* cursor-horizontal-forward-tabulation 
*/
+_VTE_SEQ(ED,                     CSI,    'J',  NONE,  0, NONE     ) /* erase-in-display */
+_VTE_SEQ(DECSED,                 CSI,    'J',  WHAT,  0, NONE     ) /* selective-erase-in-display */
+_VTE_SEQ(EL,                     CSI,    'K',  NONE,  0, NONE     ) /* erase-in-line */
+_VTE_SEQ(DECSEL,                 CSI,    'K',  WHAT,  0, NONE     ) /* selective-erase-in-line */
+_VTE_SEQ(IL,                     CSI,    'L',  NONE,  0, NONE     ) /* insert-line */
+_VTE_SEQ(DL,                     CSI,    'M',  NONE,  0, NONE     ) /* delete-line */
+_VTE_SEQ(DCH,                    CSI,    'P',  NONE,  0, NONE     ) /* delete-character */
+_VTE_SEQ(PPA,                    CSI,    'P',  NONE,  1, SPACE    ) /* page-position-absolute */
+_VTE_SEQ(PPR,                    CSI,    'Q',  NONE,  1, SPACE    ) /* page-position-relative */
+_VTE_SEQ(PPB,                    CSI,    'R',  NONE,  1, SPACE    ) /* page-position-backward */
+_VTE_SEQ(SU,                     CSI,    'S',  NONE,  0, NONE     ) /* scroll-up */
+_VTE_SEQ(XTERM_SGFX,             CSI,    'S',  WHAT,  0, NONE     ) /* xterm-sixel-graphics */
+_VTE_SEQ(SD_OR_XTERM_IHMT,       CSI,    'T',  NONE,  0, NONE     ) /* scroll-down or 
xterm-initiate-highlight-mouse-tracking */
+_VTE_SEQ(XTERM_RTM,              CSI,    'T',  GT,    0, NONE     ) /* xterm-reset-title-mode */
+_VTE_SEQ(NP,                     CSI,    'U',  NONE,  0, NONE     ) /* next-page */
+_VTE_SEQ(PP,                     CSI,    'V',  NONE,  0, NONE     ) /* preceding-page */
+_VTE_SEQ(DECST8C,                CSI,    'W',  WHAT,  0, NONE     ) /* set-tab-at-every-8-columns */
+_VTE_SEQ(ECH,                    CSI,    'X',  NONE,  0, NONE     ) /* erase-character */
+_VTE_SEQ(CBT,                    CSI,    'Z',  NONE,  0, NONE     ) /* cursor-backward-tabulation */
+_VTE_SEQ(HPA,                    CSI,    '`',  NONE,  0, NONE     ) /* horizontal-position-absolute */
+_VTE_SEQ(TATE,                   CSI,    '`',  NONE,  1, SPACE    ) /* tabulation-aligned-trailing-edge */
+_VTE_SEQ(HPR,                    CSI,    'a',  NONE,  0, NONE     ) /* horizontal-position-relative */
+_VTE_SEQ(TALE,                   CSI,    'a',  NONE,  1, SPACE    ) /* tabulation-aligned-leading-edge */
+_VTE_SEQ(REP,                    CSI,    'b',  NONE,  0, NONE     ) /* repeat */
+_VTE_SEQ(TAC,                    CSI,    'b',  NONE,  1, SPACE    ) /* tabulation-aligned-centre */
+_VTE_SEQ(DA1,                    CSI,    'c',  NONE,  0, NONE     ) /* primary-device-attributes */
+_VTE_SEQ(TCC,                    CSI,    'c',  NONE,  1, SPACE    ) /* tabulation-centred-on-character */
+_VTE_SEQ(DA3,                    CSI,    'c',  EQUAL, 0, NONE     ) /* tertiary-device-attributes */
+_VTE_SEQ(DA2,                    CSI,    'c',  GT,    0, NONE     ) /* secondary-device-attributes */
+_VTE_SEQ(VPA,                    CSI,    'd',  NONE,  0, NONE     ) /* vertical-line-position-absolute */
+_VTE_SEQ(TSR,                    CSI,    'd',  NONE,  1, SPACE    ) /* tabulation-stop-remove */
+_VTE_SEQ(VPR,                    CSI,    'e',  NONE,  0, NONE     ) /* vertical-line-position-relative */
+_VTE_SEQ(HVP,                    CSI,    'f',  NONE,  0, NONE     ) /* horizontal-and-vertical-position */
+_VTE_SEQ(TBC,                    CSI,    'g',  NONE,  0, NONE     ) /* tab-clear */
+_VTE_SEQ(DECLFKC,                CSI,    'g',  NONE,  1, MULT     ) /* local-function-key-control */
+_VTE_SEQ(SM_ECMA,                CSI,    'h',  NONE,  0, NONE     ) /* set-mode-ecma */
+_VTE_SEQ(SM_DEC,                 CSI,    'h',  WHAT,  0, NONE     ) /* set-mode-dec */
+_VTE_SEQ(MC_ANSI,                CSI,    'i',  NONE,  0, NONE     ) /* media-copy-ansi */
+_VTE_SEQ(MC_DEC,                 CSI,    'i',  WHAT,  0, NONE     ) /* media-copy-dec */
+_VTE_SEQ(RM_ECMA,                CSI,    'l',  NONE,  0, NONE     ) /* reset-mode-ecma */
+_VTE_SEQ(RM_DEC,                 CSI,    'l',  WHAT,  0, NONE     ) /* reset-mode-dec */
+_VTE_SEQ(SGR,                    CSI,    'm',  NONE,  0, NONE     ) /* select-graphics-rendition */
+_VTE_SEQ(XTERM_SRV,              CSI,    'm',  GT,    0, NONE     ) /* xterm-set-resource-value */
+_VTE_SEQ(DSR_ECMA,               CSI,    'n',  NONE,  0, NONE     ) /* device-status-report-ecma */
+_VTE_SEQ(XTERM_RRV,              CSI,    'n',  GT,    0, NONE     ) /* xterm-reset-resource-value */
+_VTE_SEQ(DSR_DEC,                CSI,    'n',  WHAT,  0, NONE     ) /* device-status-report-dec */
+_VTE_SEQ(DECSSL,                 CSI,    'p',  NONE,  0, NONE     ) /* select-setup-language */
+_VTE_SEQ(DECSSCLS,               CSI,    'p',  NONE,  1, SPACE    ) /* set-scroll-speed */
+_VTE_SEQ(DECSTR,                 CSI,    'p',  NONE,  1, BANG     ) /* soft-terminal-reset */
+_VTE_SEQ(DECSCL,                 CSI,    'p',  NONE,  1, DQUOTE   ) /* select-conformance-level */
+_VTE_SEQ(DECRQM_ECMA,            CSI,    'p',  NONE,  1, CASH     ) /* request-mode-ecma */
+_VTE_SEQ(DECSDPT,                CSI,    'p',  NONE,  1, PCLOSE   ) /* select-digital-printed-data-type */
+_VTE_SEQ(DECSPPCS,               CSI,    'p',  NONE,  1, MULT     ) /* select-pro-printer-character-set */
+_VTE_SEQ(DECSR,                  CSI,    'p',  NONE,  1, PLUS     ) /* secure-reset */
+_VTE_SEQ(DECLTOD,                CSI,    'p',  NONE,  1, COMMA    ) /* load-time-of-day */
+_VTE_SEQ(XTERM_SPM,              CSI,    'p',  GT,    0, NONE     ) /* xterm-set-private-mode */
+_VTE_SEQ(DECRQM_DEC,             CSI,    'p',  WHAT,  1, CASH     ) /* request-mode-dec */
+_VTE_SEQ(DECLL,                  CSI,    'q',  NONE,  0, NONE     ) /* load-leds */
+_VTE_SEQ(DECSCUSR,               CSI,    'q',  NONE,  1, SPACE    ) /* set-cursor-style */
+_VTE_SEQ(DECSCA,                 CSI,    'q',  NONE,  1, DQUOTE   ) /* select-character-protection-attribute 
*/
+_VTE_SEQ(DECSDDT,                CSI,    'q',  NONE,  1, CASH     ) /* select-disconnect-delay-time */
+_VTE_SEQ(DECSR,                  CSI,    'q',  NONE,  1, MULT     ) /* secure-reset */
+_VTE_SEQ(DECELF,                 CSI,    'q',  NONE,  1, PLUS     ) /* enable-local-functions */
+_VTE_SEQ(DECTID,                 CSI,    'q',  NONE,  1, COMMA    ) /* select-terminal-id */
+_VTE_SEQ(DECSTBM,                CSI,    'r',  NONE,  0, NONE     ) /* set-top-and-bottom-margins */
+_VTE_SEQ(DECSKCV,                CSI,    'r',  NONE,  1, SPACE    ) /* set-key-click-volume */
+_VTE_SEQ(DECCARA,                CSI,    'r',  NONE,  1, CASH     ) /* change-attributes-in-rectangular-area 
*/
+_VTE_SEQ(DECSCS,                 CSI,    'r',  NONE,  1, MULT     ) /* select-communication-speed */
+_VTE_SEQ(DECSMKR,                CSI,    'r',  NONE,  1, PLUS     ) /* select-modifier-key-reporting */
+_VTE_SEQ(DECPCTERM_OR_XTERM_RPM, CSI,    'r',  WHAT,  0, NONE     ) /* pcterm or xterm-restore-private-mode 
*/
+_VTE_SEQ(DECSLRM_OR_SC,          CSI,    's',  NONE,  0, NONE     ) /* set-left-and-right-margins or 
save-cursor */
+_VTE_SEQ(DECSPRTT,               CSI,    's',  NONE,  1, CASH     ) /* select-printer-type */
+_VTE_SEQ(DECSFC,                 CSI,    's',  NONE,  1, MULT     ) /* select-flow-control */
+_VTE_SEQ(XTERM_SPM,              CSI,    's',  WHAT,  0, NONE     ) /* xterm-set-private-mode */
+_VTE_SEQ(XTERM_WM,               CSI,    't',  NONE,  0, NONE     ) /* xterm-window-management */
+_VTE_SEQ(DECSWBV,                CSI,    't',  NONE,  1, SPACE    ) /* set-warning-bell-volume */
+_VTE_SEQ(DECSRFR,                CSI,    't',  NONE,  1, DQUOTE   ) /* select-refresh-rate */
+_VTE_SEQ(DECRARA,                CSI,    't',  NONE,  1, CASH     ) /* 
reverse-attributes-in-rectangular-area */
+_VTE_SEQ(XTERM_STM,              CSI,    't',  GT,    0, NONE     ) /* xterm-set-title-mode */
+_VTE_SEQ(RC,                     CSI,    'u',  NONE,  0, NONE     ) /* restore-cursor */
+_VTE_SEQ(DECSMBV,                CSI,    'u',  NONE,  1, SPACE    ) /* set-margin-bell-volume */
+_VTE_SEQ(DECSTRL,                CSI,    'u',  NONE,  1, DQUOTE   ) /* set-transmit-rate-limit */
+_VTE_SEQ(DECRQTSR,               CSI,    'u',  NONE,  1, CASH     ) /* request-terminal-state-report */
+_VTE_SEQ(DECSCP,                 CSI,    'u',  NONE,  1, MULT     ) /* select-communication-port */
+_VTE_SEQ(DECRQKT,                CSI,    'u',  NONE,  1, COMMA    ) /* request-key-type */
+_VTE_SEQ(DECRQUPSS,              CSI,    'u',  WHAT,  0, NONE     ) /* 
request-user-preferred-supplemental-set */
+_VTE_SEQ(DECSLCK,                CSI,    'v',  NONE,  1, SPACE    ) /* set-lock-key-style */
+_VTE_SEQ(DECRQDE,                CSI,    'v',  NONE,  1, DQUOTE   ) /* request-display-extent */
+_VTE_SEQ(DECCRA,                 CSI,    'v',  NONE,  1, CASH     ) /* copy-rectangular-area */
+_VTE_SEQ(DECRPKT,                CSI,    'v',  NONE,  1, COMMA    ) /* report-key-type */
+_VTE_SEQ(DECRQPSR,               CSI,    'w',  NONE,  1, CASH     ) /* request-presentation-state-report */
+_VTE_SEQ(DECEFR,                 CSI,    'w',  NONE,  1, SQUOTE   ) /* enable-filter-rectangle */
+_VTE_SEQ(DECSPP,                 CSI,    'w',  NONE,  1, PLUS     ) /* set-port-parameter */
+_VTE_SEQ(DECREQTPARM,            CSI,    'x',  NONE,  0, NONE     ) /* request-terminal-parameters */
+_VTE_SEQ(DECFRA,                 CSI,    'x',  NONE,  1, CASH     ) /* fill-rectangular-area */
+_VTE_SEQ(DECSACE,                CSI,    'x',  NONE,  1, MULT     ) /* select-attribute-change-extent */
+_VTE_SEQ(DECRQPKFM,              CSI,    'x',  NONE,  1, PLUS     ) /* request-program-key-free-memory */
+_VTE_SEQ(DECTST,                 CSI,    'y',  NONE,  0, NONE     ) /* invoke-confidence-test */
+_VTE_SEQ(DECRQCRA,               CSI,    'y',  NONE,  1, MULT     ) /* request-checksum-of-rectangular-area 
*/
+_VTE_SEQ(DECPKFMR,               CSI,    'y',  NONE,  1, PLUS     ) /* program-key-free-memory-report */
+_VTE_SEQ(DECERA,                 CSI,    'z',  NONE,  1, CASH     ) /* erase-rectangular-area */
+_VTE_SEQ(DECELR,                 CSI,    'z',  NONE,  1, SQUOTE   ) /* enable-locator-reporting */
+_VTE_SEQ(DECINVM,                CSI,    'z',  NONE,  1, MULT     ) /* invoke-macro */
+_VTE_SEQ(DECPKA,                 CSI,    'z',  NONE,  1, PLUS     ) /* program-key-action */
+_VTE_SEQ(DECSERA,                CSI,    '{',  NONE,  1, CASH     ) /* selective-erase-rectangular-area */
+_VTE_SEQ(DECSLE,                 CSI,    '{',  NONE,  1, SQUOTE   ) /* select-locator-events */
+_VTE_SEQ(DECSCPP,                CSI,    '|',  NONE,  1, CASH     ) /* select-columns-per-page */
+_VTE_SEQ(DECRQLP,                CSI,    '|',  NONE,  1, SQUOTE   ) /* request-locator-position */
+_VTE_SEQ(DECSNLS,                CSI,    '|',  NONE,  1, MULT     ) /* set-lines-per-screen */
+_VTE_SEQ(DECKBD,                 CSI,    '}',  NONE,  1, SPACE    ) /* keyboard-language-selection */
+_VTE_SEQ(DECSASD,                CSI,    '}',  NONE,  1, CASH     ) /* select-active-status-display */
+_VTE_SEQ(DECIC,                  CSI,    '}',  NONE,  1, SQUOTE   ) /* insert-column */
+_VTE_SEQ(DECTME,                 CSI,    '~',  NONE,  1, SPACE    ) /* terminal-mode-emulation */
+_VTE_SEQ(DECSSDT,                CSI,    '~',  NONE,  1, CASH     ) /* select-status-display-line-type */
+_VTE_SEQ(DECDC,                  CSI,    '~',  NONE,  1, SQUOTE   ) /* delete-column */
diff --git a/src/parser-dcs.hh b/src/parser-dcs.hh
new file mode 100644
index 0000000..a579c8d
--- /dev/null
+++ b/src/parser-dcs.hh
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2015 David Herrmann <dh herrmann gmail com>
+ * Copyright © 2018 Christian Persch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+_VTE_SEQ(DECREGIS,               DCS,    'p',  NONE,  0, NONE     ) /* ReGIS-graphics */
+_VTE_SEQ(DECRSTS,                DCS,    'p',  NONE,  1, CASH     ) /* restore-terminal-state */
+_VTE_SEQ(DECSIXEL,               DCS,    'q',  NONE,  0, NONE     ) /* SIXEL-graphics */
+_VTE_SEQ(DECRQSS,                DCS,    'q',  NONE,  1, CASH     ) /* request-selection-or-setting */
+_VTE_SEQ(DECLBAN,                DCS,    'r',  NONE,  0, NONE     ) /* load-banner-message */
+_VTE_SEQ(DECRQSS,                DCS,    'r',  NONE,  1, CASH     ) /* request-selection-or-setting */
+_VTE_SEQ(DECRQTSR,               DCS,    's',  NONE,  1, CASH     ) /* request-terminal-state-report */
+_VTE_SEQ(DECRSPS,                DCS,    't',  NONE,  1, CASH     ) /* restore-presentation-state */
+_VTE_SEQ(DECAUPSS,               DCS,    'u',  NONE,  1, BANG     ) /* 
assign-user-preferred-supplemental-sets */
+_VTE_SEQ(DECLANS,                DCS,    'v',  NONE,  0, NONE     ) /* load-answerback-message */
+_VTE_SEQ(DECLBD,                 DCS,    'w',  NONE,  0, NONE     ) /* locator-button-define */
+_VTE_SEQ(DECPFK,                 DCS,    'x',  NONE,  1, DQUOTE   ) /* program-function-key */
+_VTE_SEQ(DECPAK,                 DCS,    'y',  NONE,  1, DQUOTE   ) /* program-alphanumeric-key */
+_VTE_SEQ(DECDMAC,                DCS,    'z',  NONE,  1, BANG     ) /* define-macro */
+_VTE_SEQ(DECCKD,                 DCS,    'z',  NONE,  1, DQUOTE   ) /* copy-key-default */
+_VTE_SEQ(DECDLD,                 DCS,    '{',  NONE,  0, NONE     ) /* 
dynamically-redefinable-character-sets-extension */
+_VTE_SEQ(DECSTUI,                DCS,    '{',  NONE,  1, BANG     ) /* set-terminal-unit-id */
+_VTE_SEQ(DECUDK,                 DCS,    '|',  NONE,  0, NONE     ) /* user-defined-keys */
diff --git a/src/parser-esc.hh b/src/parser-esc.hh
new file mode 100644
index 0000000..661ce75
--- /dev/null
+++ b/src/parser-esc.hh
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2015 David Herrmann <dh herrmann gmail com>
+ * Copyright © 2018 Christian Persch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+_VTE_SEQ(DECDHL_TH,              ESCAPE, '3',  NONE,  1, HASH     ) /* double-width-double-height-line: top 
half */
+_VTE_SEQ(DECDHL_BH,              ESCAPE, '4',  NONE,  1, HASH     ) /* double-width-double-height-line: 
bottom half */
+_VTE_SEQ(DECSWL,                 ESCAPE, '5',  NONE,  1, HASH     ) /* single-width-single-height-line */
+_VTE_SEQ(DECBI,                  ESCAPE, '6',  NONE,  0, NONE     ) /* back-index */
+_VTE_SEQ(DECDWL,                 ESCAPE, '6',  NONE,  1, HASH     ) /* double-width-single-height-line */
+_VTE_SEQ(DECSC,                  ESCAPE, '7',  NONE,  0, NONE     ) /* save-cursor */
+_VTE_SEQ(DECRC,                  ESCAPE, '8',  NONE,  0, NONE     ) /* restore-cursor */
+_VTE_SEQ(DECALN,                 ESCAPE, '8',  NONE,  1, HASH     ) /* screen-alignment-pattern */
+_VTE_SEQ(DECFI,                  ESCAPE, '9',  NONE,  0, NONE     ) /* forward-index */
+_VTE_SEQ(DECANM,                 ESCAPE, '<',  NONE,  0, NONE     ) /* ansi-mode */
+_VTE_SEQ(DECKPAM,                ESCAPE, '=',  NONE,  0, NONE     ) /* keypad-application-mode */
+_VTE_SEQ(DECKPNM,                ESCAPE, '>',  NONE,  0, NONE     ) /* keypad-numeric-mode */
+_VTE_SEQ(IND,                    ESCAPE, 'D',  NONE,  0, NONE     ) /* index */
+_VTE_SEQ(NEL,                    ESCAPE, 'E',  NONE,  0, NONE     ) /* next-line */
+_VTE_SEQ(XTERM_CLLHP,            ESCAPE, 'F',  NONE,  0, NONE     ) /* xterm-cursor-lower-left-hp-bugfix */
+_VTE_SEQ(HTS,                    ESCAPE, 'H',  NONE,  0, NONE     ) /* horizontal-tab-set */
+_VTE_SEQ(RI,                     ESCAPE, 'M',  NONE,  0, NONE     ) /* reverse-index */
+_VTE_SEQ(SS2,                    ESCAPE, 'N',  NONE,  0, NONE     ) /* single-shift-2 */
+_VTE_SEQ(SS3,                    ESCAPE, 'O',  NONE,  0, NONE     ) /* single-shift-3 */
+_VTE_SEQ(SPA,                    ESCAPE, 'V',  NONE,  0, NONE     ) /* start-of-protected-area */
+_VTE_SEQ(EPA,                    ESCAPE, 'W',  NONE,  0, NONE     ) /* end-of-guarded-area */
+_VTE_SEQ(ST,                     ESCAPE, '\\', NONE,  0, NONE     ) /* string-terminator */
+_VTE_SEQ(RIS,                    ESCAPE, 'c',  NONE,  0, NONE     ) /* reset-to-initial-state */
+_VTE_SEQ(CMD,                    ESCAPE, 'd',  NONE,  0, NONE     ) /* coding-method-delimiter */
+_VTE_SEQ(XTERM_MLHP,             ESCAPE, 'l',  NONE,  0, NONE     ) /* xterm-memory-lock-hp-bugfix */
+_VTE_SEQ(XTERM_MUHP,             ESCAPE, 'm',  NONE,  0, NONE     ) /* xterm-memory-unlock-hp-bugfix */
+_VTE_SEQ(LS2,                    ESCAPE, 'n',  NONE,  0, NONE     ) /* locking-shift-2 */
+_VTE_SEQ(LS3,                    ESCAPE, 'o',  NONE,  0, NONE     ) /* locking-shift-3 */
+_VTE_SEQ(LS3R,                   ESCAPE, '|',  NONE,  0, NONE     ) /* locking-shift-3-right */
+_VTE_SEQ(LS2R,                   ESCAPE, '}',  NONE,  0, NONE     ) /* locking-shift-2-right */
+_VTE_SEQ(LS1R,                   ESCAPE, '~',  NONE,  0, NONE     ) /* locking-shift-1-right */
diff --git a/src/parser-glue.hh b/src/parser-glue.hh
index bc983f6..17e530b 100644
--- a/src/parser-glue.hh
+++ b/src/parser-glue.hh
@@ -67,18 +67,19 @@ public:
          */
         inline constexpr unsigned int charset() const noexcept
         {
-                return m_seq->charset;
+                return VTE_CHARSET_GET_CHARSET(m_seq->charset);
         }
 
-        /* intermediates:
+        /* slot:
          *
-         * The intermediate bytes of the ESCAPE, CSI or DCS sequence.
+         * This is the slot in a %VTE_CMD_GnDm, %VTE_CMD_GnDMm,
+         * or %VTE_CMD_CnD command.
          *
-         * Returns: the immediates as flag values from the VTE_SEQ_FLAG_* enum
+         * Returns: the slot, a value from the 0..3 for Gn*, or 0..1 for CnD
          */
-        inline constexpr unsigned int intermediates() const noexcept
+        inline constexpr unsigned int slot() const noexcept
         {
-                return m_seq->intermediates;
+                return VTE_CHARSET_GET_SLOT(m_seq->charset);
         }
 
         /* terminator:
@@ -414,7 +415,6 @@ public:
         {
                 assert(unsigned(m_n_intermediates + 1) <= 
(sizeof(m_intermediates)/sizeof(m_intermediates[0])));
 
-                m_seq.intermediates |= (1u << (i - 0x20));
                 m_intermediates[m_n_intermediates++] = i;
         }
 
@@ -423,7 +423,6 @@ public:
                 assert(m_n_intermediates + l.size() <= (sizeof(m_intermediates)/sizeof(m_intermediates[0])));
 
                 for (uint32_t i : l) {
-                        m_seq.intermediates |= (1u << (i - 0x20));
                         m_intermediates[m_n_intermediates++] = i;
                 }
         }
@@ -431,9 +430,6 @@ public:
         inline void set_param_intro(unsigned char p) noexcept
         {
                 m_param_intro = p;
-                if (p != 0) {
-                        m_seq.intermediates |= (1u << (p - 0x20));
-                }
         }
 
         inline void append_params(std::initializer_list<int> params) noexcept
@@ -631,9 +627,9 @@ public:
                 case VTE_REPLY_##cmd: \
                         set_type(VTE_SEQ_##type); \
                         set_final(final); \
-                        set_param_intro(VTE_SEQ_INTERMEDIATE_##pintro); \
-                        if (VTE_SEQ_INTERMEDIATE_##intermediate != VTE_SEQ_INTERMEDIATE_NONE) \
-                                append_intermediate(VTE_SEQ_INTERMEDIATE_##intermediate); \
+                        set_param_intro(VTE_SEQ_PARAMETER_CHAR_##pintro); \
+                        if (VTE_SEQ_INTERMEDIATE_CHAR_##intermediate != VTE_SEQ_INTERMEDIATE_CHAR_NONE) \
+                                append_intermediate(VTE_SEQ_INTERMEDIATE_CHAR_##intermediate); \
                         code \
                         break;
 #include "parser-reply.hh"
diff --git a/src/parser-test.cc b/src/parser-test.cc
index 04073d5..2c20295 100644
--- a/src/parser-test.cc
+++ b/src/parser-test.cc
@@ -176,13 +176,11 @@ public:
         void set_intermediates(uint32_t* i,
                                unsigned int ni)
         {
-                unsigned int flags = 0;
                 for (unsigned int n = 0; n < ni; n++) {
-                        flags |= (1u << (i[n] - 0x20));
                         m_i[n] = i[n];
                 }
                 m_ni = ni;
-                m_seq.intermediates = flags;
+                m_seq.n_intermediates = ni;
         }
 
         void set_params(vte_seq_arg_t params[16])
@@ -199,9 +197,6 @@ public:
         void set_param_byte(uint32_t p)
         {
                 m_p = p;
-                if (p != 0) {
-                        m_seq.intermediates |= (1u << (p - 0x20));
-                }
         }
 
         void set_string(std::u32string const& str)
@@ -229,7 +224,7 @@ public:
 
 private:
         uint32_t m_i[4]{0, 0, 0, 0};
-        uint32_t m_p;
+        uint32_t m_p{0};
         unsigned int m_ni{0};
         std::u32string m_arg_str;
         struct vte_seq m_seq;
@@ -601,7 +596,8 @@ test_seq_esc_charset(uint32_t f, /* final */
                      uint32_t i[], /* intermediates */
                      unsigned int ni, /* number of intermediates */
                      unsigned int cmd, /* expected command */
-                     unsigned int cs /* expected charset */)
+                     unsigned int cs /* expected charset */,
+                     unsigned int slot /* expected slot */)
 {
         vte_seq_builder b{VTE_SEQ_ESCAPE, f};
         b.set_intermediates(i, ni);
@@ -613,7 +609,8 @@ test_seq_esc_charset(uint32_t f, /* final */
         b.assert_equal(seq);
 
         g_assert_cmpint(seq->command, ==, cmd);
-        g_assert_cmpint(seq->charset, ==, cs);
+        g_assert_cmpint(VTE_CHARSET_GET_CHARSET(seq->charset), ==, cs);
+        g_assert_cmpint(VTE_CHARSET_GET_SLOT(seq->charset), ==, slot);
 }
 
 static void
@@ -623,7 +620,8 @@ test_seq_esc_charset(uint32_t i[], /* intermediates */
                      unsigned int ntable, /* number of table entries */
                      uint32_t ts, /* start of table */
                      unsigned int cmd, /* expected command */
-                     unsigned int defaultcs /* default charset */)
+                     unsigned int defaultcs /* default charset */,
+                     unsigned int slot /* expected slot */)
 {
         for (uint32_t f = 0x30; f < 0x7f; f++) {
                 int cs;
@@ -633,7 +631,7 @@ test_seq_esc_charset(uint32_t i[], /* intermediates */
                 else
                         cs = defaultcs;
 
-                test_seq_esc_charset(f, i, ni, cmd, cs);
+                test_seq_esc_charset(f, i, ni, cmd, cs, slot);
         }
 }
 
@@ -644,30 +642,32 @@ test_seq_esc_charset_94(void)
 
         /* Single byte 94-sets */
         for (i[0] = 0x28; i[0] <= 0x2b; i[0]++) {
+                int slot = i[0] - 0x28;
+
                 test_seq_esc_charset(i, 1,
                                      charset_graphic_94,
                                      G_N_ELEMENTS(charset_graphic_94),
-                                     0x30, VTE_CMD_GnDm, VTE_CHARSET_NONE);
+                                     0x30, VTE_CMD_GnDm, VTE_CHARSET_NONE, slot);
 
                 i[1] = 0x20;
                 test_seq_esc_charset(i, 2, nullptr, 0, 0,
-                                     VTE_CMD_GnDm, VTE_CHARSET_DRCS);
+                                     VTE_CMD_GnDm, VTE_CHARSET_DRCS, slot);
 
                 i[1] = 0x21;
                 test_seq_esc_charset(i, 2,
                                      charset_graphic_94_with_2_1,
                                      G_N_ELEMENTS(charset_graphic_94_with_2_1),
-                                     0x40, VTE_CMD_GnDm, VTE_CHARSET_NONE);
+                                     0x40, VTE_CMD_GnDm, VTE_CHARSET_NONE, slot);
 
                 i[1] = 0x22;
                 test_seq_esc_charset(i, 2,
                                      charset_graphic_94_with_2_2,
                                      G_N_ELEMENTS(charset_graphic_94_with_2_2),
-                                     0x30, VTE_CMD_GnDm, VTE_CHARSET_NONE);
+                                     0x30, VTE_CMD_GnDm, VTE_CHARSET_NONE, slot);
 
                 i[1] = 0x23;
                 test_seq_esc_charset(i, 2, nullptr, 0,
-                                     0x30, VTE_CMD_GnDm, VTE_CHARSET_NONE);
+                                     0x30, VTE_CMD_GnDm, VTE_CHARSET_NONE, slot);
 
                 /* 2/4 is multibyte charsets */
 
@@ -675,17 +675,17 @@ test_seq_esc_charset_94(void)
                 test_seq_esc_charset(i, 2,
                                      charset_graphic_94_with_2_5,
                                      G_N_ELEMENTS(charset_graphic_94_with_2_5),
-                                     0x30, VTE_CMD_GnDm, VTE_CHARSET_NONE);
+                                     0x30, VTE_CMD_GnDm, VTE_CHARSET_NONE, slot);
 
                 i[1] = 0x26;
                 test_seq_esc_charset(i, 2,
                                      charset_graphic_94_with_2_6,
                                      G_N_ELEMENTS(charset_graphic_94_with_2_6),
-                                     0x30, VTE_CMD_GnDm, VTE_CHARSET_NONE);
+                                     0x30, VTE_CMD_GnDm, VTE_CHARSET_NONE, slot);
 
                 i[1] = 0x27;
                 test_seq_esc_charset(i, 2, nullptr, 0, 0,
-                                     VTE_CMD_GnDm, VTE_CHARSET_NONE);
+                                     VTE_CMD_GnDm, VTE_CHARSET_NONE, slot);
         }
 }
 
@@ -696,14 +696,16 @@ test_seq_esc_charset_96(void)
 
         /* Single byte 96-sets */
         for (i[0] = 0x2d; i[0] <= 0x2f; i[0]++) {
+                int slot = i[0] - 0x2c;
+
                 test_seq_esc_charset(i, 1,
                                      charset_graphic_96,
                                      G_N_ELEMENTS(charset_graphic_96),
-                                     0x30, VTE_CMD_GnDm, VTE_CHARSET_NONE);
+                                     0x30, VTE_CMD_GnDm, VTE_CHARSET_NONE, slot);
 
                 i[1] = 0x20;
                 test_seq_esc_charset(i, 2, nullptr, 0, 0,
-                                     VTE_CMD_GnDm, VTE_CHARSET_DRCS);
+                                     VTE_CMD_GnDm, VTE_CHARSET_DRCS, slot);
 
                 /* 2/4 is multibyte charsets, 2/5 is DOCS. Other indermediates may be present
                  * in Fp sequences, but none are actually in use.
@@ -713,7 +715,7 @@ test_seq_esc_charset_96(void)
                                 continue;
 
                         test_seq_esc_charset(i, 2, nullptr, 0, 0,
-                                             VTE_CMD_GnDm, VTE_CHARSET_NONE);
+                                             VTE_CMD_GnDm, VTE_CHARSET_NONE, slot);
                 }
         }
 }
@@ -726,14 +728,16 @@ test_seq_esc_charset_94_n(void)
         /* Multibyte 94-sets */
         i[0] = 0x24;
         for (i[1] = 0x28; i[1] <= 0x2b; i[1]++) {
+                int slot = i[1] - 0x28;
+
                 test_seq_esc_charset(i, 2,
                                      charset_graphic_94_n,
                                      G_N_ELEMENTS(charset_graphic_94_n),
-                                     0x30, VTE_CMD_GnDMm, VTE_CHARSET_NONE);
+                                     0x30, VTE_CMD_GnDMm, VTE_CHARSET_NONE, slot);
 
                 i[2] = 0x20;
                 test_seq_esc_charset(i, 3, nullptr, 0, 0,
-                                     VTE_CMD_GnDMm, VTE_CHARSET_DRCS);
+                                     VTE_CMD_GnDMm, VTE_CHARSET_DRCS, slot);
 
                 /* There could be one more intermediate byte. */
                 for (i[2] = 0x21; i[2] < 0x28; i[2]++) {
@@ -741,14 +745,14 @@ test_seq_esc_charset_94_n(void)
                                 continue;
 
                         test_seq_esc_charset(i, 3, nullptr, 0, 0,
-                                             VTE_CMD_GnDMm, VTE_CHARSET_NONE);
+                                             VTE_CMD_GnDMm, VTE_CHARSET_NONE, slot);
                 }
         }
 
         /* As a special exception, ESC 2/4 4/[012] are also possible */
-        test_seq_esc_charset(0x40, i, 1, VTE_CMD_GnDMm, charset_graphic_94_n[0x40 - 0x30]);
-        test_seq_esc_charset(0x41, i, 1, VTE_CMD_GnDMm, charset_graphic_94_n[0x41 - 0x30]);
-        test_seq_esc_charset(0x42, i, 1, VTE_CMD_GnDMm, charset_graphic_94_n[0x42 - 0x30]);
+        test_seq_esc_charset(0x40, i, 1, VTE_CMD_GnDMm, charset_graphic_94_n[0x40 - 0x30], 0);
+        test_seq_esc_charset(0x41, i, 1, VTE_CMD_GnDMm, charset_graphic_94_n[0x41 - 0x30], 0);
+        test_seq_esc_charset(0x42, i, 1, VTE_CMD_GnDMm, charset_graphic_94_n[0x42 - 0x30], 0);
 }
 
 static void
@@ -759,17 +763,19 @@ test_seq_esc_charset_96_n(void)
         /* Multibyte 94-sets */
         i[0] = 0x24;
         for (i[1] = 0x2d; i[1] <= 0x2f; i[1]++) {
+                int slot = i[1] - 0x2c;
+
                 test_seq_esc_charset(i, 2, nullptr, 0, 0,
-                                     VTE_CMD_GnDMm, VTE_CHARSET_NONE);
+                                     VTE_CMD_GnDMm, VTE_CHARSET_NONE, slot);
 
                 i[2] = 0x20;
                 test_seq_esc_charset(i, 3, nullptr, 0, 0,
-                                     VTE_CMD_GnDMm, VTE_CHARSET_DRCS);
+                                     VTE_CMD_GnDMm, VTE_CHARSET_DRCS, slot);
 
                 /* There could be one more intermediate byte. */
                 for (i[2] = 0x21; i[2] < 0x28; i[2]++) {
                         test_seq_esc_charset(i, 3, nullptr, 0, 0,
-                                             VTE_CMD_GnDMm, VTE_CHARSET_NONE);
+                                             VTE_CMD_GnDMm, VTE_CHARSET_NONE, slot);
                 }
         }
 }
@@ -784,14 +790,14 @@ test_seq_esc_charset_control(void)
         test_seq_esc_charset(i, 1,
                              charset_control_c0,
                              G_N_ELEMENTS(charset_control_c0),
-                             0x40, VTE_CMD_CnD, VTE_CHARSET_NONE);
+                             0x40, VTE_CMD_CnD, VTE_CHARSET_NONE, 0);
 
         /* C1 controls: ESC 2/2 F */
         i[0] = 0x22;
         test_seq_esc_charset(i, 1,
                              charset_control_c1,
                              G_N_ELEMENTS(charset_control_c1),
-                             0x40, VTE_CMD_CnD, VTE_CHARSET_NONE);
+                             0x40, VTE_CMD_CnD, VTE_CHARSET_NONE, 1);
 }
 
 static void
@@ -804,13 +810,13 @@ test_seq_esc_charset_other(void)
         test_seq_esc_charset(i, 1,
                              charset_ocs_with_return,
                              G_N_ELEMENTS(charset_ocs_with_return),
-                             0x40, VTE_CMD_DOCS, VTE_CHARSET_NONE);
+                             0x40, VTE_CMD_DOCS, VTE_CHARSET_NONE, 0);
 
         i[1] = 0x2f;
         test_seq_esc_charset(i, 2,
                              charset_ocs_without_return,
                              G_N_ELEMENTS(charset_ocs_without_return),
-                             0x40, VTE_CMD_DOCS, VTE_CHARSET_NONE);
+                             0x40, VTE_CMD_DOCS, VTE_CHARSET_NONE, 0);
 }
 
 static void
@@ -847,6 +853,32 @@ test_seq_esc_Fpes(void)
 }
 
 static void
+test_seq_esc_known(uint32_t f,
+                   uint32_t i,
+                   unsigned int cmd)
+{
+        vte_seq_builder b{VTE_SEQ_ESCAPE, f};
+        if (i != 0)
+                b.set_intermediates(&i, 1);
+
+        struct vte_seq* seq;
+        auto rv = feed_parser(b, &seq);
+        g_assert_cmpint(rv, ==, VTE_SEQ_ESCAPE);
+        g_assert_cmpint(seq->command, ==, cmd);
+}
+
+static void
+test_seq_esc_known(void)
+{
+        vte_parser_reset(parser);
+
+#define _VTE_SEQ(cmd,type,f,p,ni,i) \
+        test_seq_esc_known(f, VTE_SEQ_INTERMEDIATE_CHAR_##i, VTE_CMD_##cmd);
+#include "parser-esc.hh"
+#undef _VTE_SEQ
+}
+
+static void
 test_seq_csi(uint32_t f,
              uint32_t p,
              vte_seq_arg_t params[16],
@@ -964,6 +996,35 @@ test_seq_sci(void)
 }
 
 static void
+test_seq_csi_known(uint32_t f,
+                   uint32_t p,
+                   uint32_t i,
+                   unsigned int cmd)
+{
+        vte_seq_builder b{VTE_SEQ_CSI, f};
+        if (p != 0)
+                b.set_param_byte(p);
+        if (i != 0)
+                b.set_intermediates(&i, 1);
+
+        struct vte_seq* seq;
+        auto rv = feed_parser(b, &seq);
+        g_assert_cmpint(rv, ==, VTE_SEQ_CSI);
+        g_assert_cmpint(seq->command, ==, cmd);
+}
+
+static void
+test_seq_csi_known(void)
+{
+        vte_parser_reset(parser);
+
+#define _VTE_SEQ(cmd,type,f,p,ni,i) \
+        test_seq_csi_known(f, VTE_SEQ_PARAMETER_CHAR_##p, VTE_SEQ_INTERMEDIATE_CHAR_##i, VTE_CMD_##cmd);
+#include "parser-csi.hh"
+#undef _VTE_SEQ
+}
+
+static void
 test_seq_dcs(uint32_t f,
              uint32_t p,
              vte_seq_arg_t params[16],
@@ -1056,6 +1117,35 @@ test_seq_dcs(void)
 }
 
 static void
+test_seq_dcs_known(uint32_t f,
+                   uint32_t p,
+                   uint32_t i,
+                   unsigned int cmd)
+{
+        vte_seq_builder b{VTE_SEQ_DCS, f};
+        if (p != 0)
+                b.set_param_byte(p);
+        if (i != 0)
+                b.set_intermediates(&i, 1);
+
+        struct vte_seq* seq;
+        auto rv = feed_parser(b, &seq);
+        g_assert_cmpint(rv, ==, VTE_SEQ_DCS);
+        g_assert_cmpint(seq->command, ==, cmd);
+}
+
+static void
+test_seq_dcs_known(void)
+{
+        vte_parser_reset(parser);
+
+#define _VTE_SEQ(cmd,type,f,p,ni,i) \
+        test_seq_dcs_known(f, VTE_SEQ_PARAMETER_CHAR_##p, VTE_SEQ_INTERMEDIATE_CHAR_##i, VTE_CMD_##cmd);
+#include "parser-dcs.hh"
+#undef _VTE_SEQ
+}
+
+static void
 test_seq_parse(char const* str,
                struct vte_seq** seq)
 {
@@ -1141,7 +1231,6 @@ test_seq_glue_arg(char const* str,
         g_assert_cmpuint(seq.type(), ==, raw_seq->type);
         g_assert_cmpuint(seq.command(), ==, raw_seq->command);
         g_assert_cmpuint(seq.terminator(), ==, raw_seq->terminator);
-        g_assert_cmpuint(seq.intermediates(), ==, raw_seq->intermediates);
 
         for (unsigned int i = 0; i < raw_seq->n_args; i++)
                 g_assert_cmpuint(seq.param(i), ==, vte_seq_arg_value(raw_seq->args[i]));
@@ -1507,10 +1596,13 @@ main(int argc,
         g_test_add_func("/vte/parser/sequences/escape/charset/other", test_seq_esc_charset_other);
         g_test_add_func("/vte/parser/sequences/escape/nF", test_seq_esc_nF);
         g_test_add_func("/vte/parser/sequences/escape/F[pes]", test_seq_esc_Fpes);
+        g_test_add_func("/vte/parser/sequences/escape/known", test_seq_esc_known);
         g_test_add_func("/vte/parser/sequences/csi", test_seq_csi);
+        g_test_add_func("/vte/parser/sequences/csi/known", test_seq_csi_known);
         g_test_add_func("/vte/parser/sequences/csi/parameters", test_seq_csi_param);
         g_test_add_func("/vte/parser/sequences/sci", test_seq_sci);
         g_test_add_func("/vte/parser/sequences/dcs", test_seq_dcs);
+        g_test_add_func("/vte/parser/sequences/dcs/known", test_seq_dcs_known);
         g_test_add_func("/vte/parser/sequences/osc", test_seq_osc);
 
         auto rv = g_test_run();
diff --git a/src/parser.cc b/src/parser.cc
index 0c3968f..9ffccb2 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -30,7 +30,6 @@
 #include "parser-charset-tables.hh"
 
 #define WARN(num,str) do { } while (0)
-#define hweight32(v) (__builtin_popcount(v))
 #define kzalloc(n,v) calloc((n),1)
 #define kfree(ptr) free(ptr)
 
@@ -55,6 +54,73 @@ struct vte_parser {
  * are used to figure out their meaning.
  */
 
+/*
+ * Intermediates (and, for CSI/DCS, the optional parameter character) are
+ * stored efficiently in an unsigned int. Intermediates can be 2/00..2/15,
+ * plus one value for 'no intermediate'; together that fits into 5 bits.
+ * Parameter character can be 'no parameter character', or one from
+ * 3/12..3/15; that fits into 3 bits.
+ *
+ * In @seq.intermediates, the nth intermediates is stored with shift n * 5,
+ * plus (for CSI/DCS) an additional shift of 3 for the parameter character
+ * which is stored at bits 0..2.
+ *
+ * VTE_SEQ_PARAMETER(u) extracts the parameter character
+ *   of a CSI or DCS sequence
+ * VTE_SEQ_REMOVE_PARAMETER(u) extracts the intermediates
+ *   of a CSI or DCS sequence
+ * VTE_SEQ_INTERMEDIATE(u) extracts the first intermediate from an
+ *   intermediates value (for CSI/DCS, that must be without parameter
+ *   character, see VTE_SEQ_REMOVE_PARAMETER)
+ * VTE_SEQ_REMOVE_INTERMEDIATE(u) extracts the remaining intermediates
+ *   after the first one; use VTE_SEQ_INTERMEDIATE on its return value
+ *   to extract the 2nd intermediate, and so on
+ */
+
+#define VTE_SEQ_PARAMETER_BITS         (3)
+#define VTE_SEQ_INTERMEDIATE_BITS      (5)
+#define VTE_SEQ_INTERMEDIATE_MASK      ((1U << VTE_SEQ_INTERMEDIATE_BITS) - 1U)
+#define VTE_SEQ_PARAMETER_MASK         ((1U << VTE_SEQ_PARAMETER_BITS) - 1U)
+#define VTE_SEQ_PARAMETER(u)           ((u) & VTE_SEQ_PARAMETER_MASK)
+#define VTE_SEQ_REMOVE_PARAMETER(u)    ((u) >> VTE_SEQ_PARAMETER_BITS)
+#define VTE_SEQ_INTERMEDIATE(u)        ((u) & VTE_SEQ_INTERMEDIATE_MASK)
+#define VTE_SEQ_REMOVE_INTERMEDIATE(u) ((u) >> VTE_SEQ_INTERMEDIATE_BITS)
+#define VTE_MAKE_CHARSET(c,s)          ((c) | ((s) << VTE_CHARSET_SLOT_OFFSET))
+
+/*
+ * _VTE_SEQ_CODE_ESC(final, intermediates):
+ *
+ * Make a value combining the final character and the intermediates,
+ * to be used to match a sequence against known sequences.
+ *
+ * Since this is only used with NONE or HASH as first intermediate,
+ * we can reduce the size of the lookup table by slashing the least
+ * significant bit off.
+ *
+ * Final characters is 3/0..7/14, needing 7 bits.
+ */
+#define _VTE_SEQ_CODE_ESC(f,i) (((f) - 0x30) | ((i) >> 1) << 7)
+
+/*
+ * _VTE_SEQ_CODE_COMBINE(parameter, intermediates)
+ *
+ * Combines intermediates and the parameter character into one
+ * value to be used when matching a sequence against known sequences.
+ */
+#define _VTE_SEQ_CODE_COMBINE(p,i) ((p) | ((i) << VTE_SEQ_PARAMETER_BITS))
+
+/*
+ * _VTE_SEQ_CODE(final, intermediates):
+ *
+ * Make a value combining the final character and the intermediates,
+ * to be used to match a sequence against known sequences. Used for
+ * CSI and DCS sequences; use _VTE_SEQ_CODE_COMBINE to combine
+ * parameter and intermediates into one to pass as 2nd argument here.
+ *
+ * Final character is 4/0..7/14, needing 6 bits.
+ */
+#define _VTE_SEQ_CODE(f,i) (((f) - 0x40) | ((i) << 6))
+
 static unsigned int vte_parse_host_control(const struct vte_seq *seq)
 {
         switch (seq->terminator) {
@@ -140,44 +206,47 @@ static unsigned int vte_parse_host_control(const struct vte_seq *seq)
 }
 
 static unsigned int vte_parse_charset_94(uint32_t raw,
-                                         unsigned int flags)
+                                         unsigned int intermediates)
 {
         assert (raw >= 0x30 && raw < 0x7f);
 
-        if (flags & VTE_SEQ_FLAG_SPACE)
-                return VTE_CHARSET_DRCS;
+        unsigned int remaining_intermediates = VTE_SEQ_REMOVE_INTERMEDIATE(intermediates);
 
-        switch (flags) {
-        case 0:
-                if (raw < (0x30 + G_N_ELEMENTS(charset_graphic_94)))
+        switch (VTE_SEQ_INTERMEDIATE(intermediates)) {
+        case VTE_SEQ_INTERMEDIATE_NONE:
+                if (remaining_intermediates == 0 &&
+                    raw < (0x30 + G_N_ELEMENTS(charset_graphic_94)))
                         return charset_graphic_94[raw - 0x30];
                 break;
 
-        case VTE_SEQ_FLAG_BANG:
-                if (raw >= 0x40 && (raw < 0x40 + G_N_ELEMENTS(charset_graphic_94_with_2_1)))
+        case VTE_SEQ_INTERMEDIATE_SPACE:
+                return VTE_CHARSET_DRCS;
+
+        case VTE_SEQ_INTERMEDIATE_BANG:
+                if (remaining_intermediates == 0 &&
+                    raw >= 0x40 && (raw < 0x40 + G_N_ELEMENTS(charset_graphic_94_with_2_1)))
                         return charset_graphic_94_with_2_1[raw - 0x40];
                 break;
 
-        case VTE_SEQ_FLAG_DQUOTE:
-                if (raw < (0x30 + G_N_ELEMENTS(charset_graphic_94_with_2_2)))
+        case VTE_SEQ_INTERMEDIATE_DQUOTE:
+                if (remaining_intermediates == 0 &&
+                    raw < (0x30 + G_N_ELEMENTS(charset_graphic_94_with_2_2)))
                         return charset_graphic_94_with_2_2[raw - 0x30];
                 break;
 
-        case VTE_SEQ_FLAG_HASH:
+        case VTE_SEQ_INTERMEDIATE_HASH:
+        case VTE_SEQ_INTERMEDIATE_CASH:
                 break;
 
-        case VTE_SEQ_FLAG_CASH:
-                if (raw < (0x30 + G_N_ELEMENTS(charset_graphic_94_n)))
-                        return charset_graphic_94_n[raw - 0x30];
-                break;
-
-        case VTE_SEQ_FLAG_PERCENT:
-                if (raw < (0x30 + G_N_ELEMENTS(charset_graphic_94_with_2_5)))
+        case VTE_SEQ_INTERMEDIATE_PERCENT:
+                if (remaining_intermediates == 0 &&
+                    raw < (0x30 + G_N_ELEMENTS(charset_graphic_94_with_2_5)))
                         return charset_graphic_94_with_2_5[raw - 0x30];
                 break;
 
-        case VTE_SEQ_FLAG_AND:
-                if (raw < (0x30 + G_N_ELEMENTS(charset_graphic_94_with_2_6)))
+        case VTE_SEQ_INTERMEDIATE_AND:
+                if (remaining_intermediates == 0 &&
+                    raw < (0x30 + G_N_ELEMENTS(charset_graphic_94_with_2_6)))
                         return charset_graphic_94_with_2_6[raw - 0x30];
                 break;
         }
@@ -185,50 +254,100 @@ static unsigned int vte_parse_charset_94(uint32_t raw,
         return VTE_CHARSET_NONE;
 }
 
+static unsigned int vte_parse_charset_94_n(uint32_t raw,
+                                           unsigned int intermediates)
+{
+        assert (raw >= 0x30 && raw < 0x7f);
+
+        unsigned int remaining_intermediates = VTE_SEQ_REMOVE_INTERMEDIATE(intermediates);
+
+        switch (VTE_SEQ_INTERMEDIATE(intermediates)) {
+        case VTE_SEQ_INTERMEDIATE_NONE:
+                if (remaining_intermediates == 0 &&
+                    raw < (0x30 + G_N_ELEMENTS(charset_graphic_94_n)))
+                        return charset_graphic_94_n[raw - 0x30];
+                break;
+
+        case VTE_SEQ_INTERMEDIATE_SPACE:
+                return VTE_CHARSET_DRCS;
+        }
+
+        return VTE_CHARSET_NONE;
+}
+
 static unsigned int vte_parse_charset_96(uint32_t raw,
-                                         unsigned int flags)
+                                         unsigned int intermediates)
 {
         assert (raw >= 0x30 && raw < 0x7f);
 
-        if (flags == 0) { /* Graphic 96-set */
-                if (raw < (0x30 + G_N_ELEMENTS(charset_graphic_96)))
+        unsigned int remaining_intermediates = VTE_SEQ_REMOVE_INTERMEDIATE(intermediates);
+
+        switch (VTE_SEQ_INTERMEDIATE(intermediates)) {
+        case VTE_SEQ_INTERMEDIATE_NONE:
+                if (remaining_intermediates == 0 &&
+                    raw < (0x30 + G_N_ELEMENTS(charset_graphic_96)))
                         return charset_graphic_96[raw - 0x30];
-        } else if (flags & VTE_SEQ_FLAG_SPACE) { /* DRCS */
+                break;
+
+        case VTE_SEQ_INTERMEDIATE_SPACE:
                 return VTE_CHARSET_DRCS;
         }
 
         return VTE_CHARSET_NONE;
 }
 
+static unsigned int vte_parse_charset_96_n(uint32_t raw,
+                                           unsigned int intermediates)
+{
+        if (VTE_SEQ_INTERMEDIATE(intermediates) == VTE_SEQ_INTERMEDIATE_SPACE)
+                return VTE_CHARSET_DRCS;
+
+        return VTE_CHARSET_NONE;
+}
+
 static unsigned int vte_parse_charset_ocs(uint32_t raw,
-                                          unsigned int flags)
+                                          unsigned int intermediates)
 {
         assert (raw >= 0x30 && raw < 0x7f);
 
-        if (flags == VTE_SEQ_FLAG_PERCENT) {
-                /* OCS with standard return */
-                if (raw >= 0x40 && raw < (0x40 + G_N_ELEMENTS(charset_ocs_with_return)))
+        unsigned int remaining_intermediates = VTE_SEQ_REMOVE_INTERMEDIATE(intermediates);
+
+        switch (VTE_SEQ_INTERMEDIATE(intermediates)) {
+        case VTE_SEQ_INTERMEDIATE_NONE:  /* OCS with standard return */
+                if (remaining_intermediates == 0 &&
+                    raw >= 0x40 && raw < (0x40 + G_N_ELEMENTS(charset_ocs_with_return)))
                         return charset_ocs_with_return[raw - 0x40];
-        } else if (flags == (VTE_SEQ_FLAG_PERCENT | VTE_SEQ_FLAG_SLASH)) {
-                /* OCS without standard return */
-                if (raw >= 0x40 && raw < (0x40 + G_N_ELEMENTS(charset_ocs_without_return)))
+                break;
+
+        case VTE_SEQ_INTERMEDIATE_SLASH: /* OCS without standard return */
+                if (remaining_intermediates == 0 &&
+                    raw >= 0x40 && raw < (0x40 + G_N_ELEMENTS(charset_ocs_without_return)))
                         return charset_ocs_without_return[raw - 0x40];
+                break;
         }
 
         return VTE_CHARSET_NONE;
 }
 
 static unsigned int vte_parse_charset_control(uint32_t raw,
-                                              unsigned int flags)
+                                              unsigned int intermediates)
 {
         assert (raw >= 0x30 && raw < 0x7f);
 
-        if (flags == VTE_SEQ_FLAG_BANG) { /* C0 controls */
-                if (raw >= 0x40 && raw < (0x40 + G_N_ELEMENTS(charset_control_c0)))
+        unsigned int remaining_intermediates = VTE_SEQ_REMOVE_INTERMEDIATE(intermediates);
+
+        switch (VTE_SEQ_INTERMEDIATE(intermediates)) {
+        case VTE_SEQ_INTERMEDIATE_BANG: /* C0 controls */
+                if (remaining_intermediates == 0 &&
+                    raw >= 0x40 && raw < (0x40 + G_N_ELEMENTS(charset_control_c0)))
                         return charset_control_c0[raw - 0x40];
-        } else if (flags == VTE_SEQ_FLAG_DQUOTE) { /* C1 controls */
-                if (raw >= 0x40 && raw < (0x40 + G_N_ELEMENTS(charset_control_c1)))
+                break;
+
+        case VTE_SEQ_INTERMEDIATE_DQUOTE: /* C1 controls */
+                if (remaining_intermediates == 0 &&
+                    raw >= 0x40 && raw < (0x40 + G_N_ELEMENTS(charset_control_c1)))
                         return charset_control_c1[raw - 0x40];
+                break;
         }
 
         return VTE_CHARSET_NONE;
@@ -237,175 +356,112 @@ static unsigned int vte_parse_charset_control(uint32_t raw,
 static unsigned int vte_parse_host_escape(const struct vte_seq *seq,
                                           unsigned int *cs_out)
 {
-        unsigned int const flags = seq->intermediates;
-
-        if (flags == 0) {
-                switch (seq->terminator) {
-                case '6': /* DECBI */
-                        return VTE_CMD_DECBI;
-                case '7': /* DECSC */
-                        return VTE_CMD_DECSC;
-                case '8': /* DECRC */
-                        return VTE_CMD_DECRC;
-                case '9': /* DECFI */
-                        return VTE_CMD_DECFI;
-                case '<': /* DECANM */
-                        return VTE_CMD_DECANM;
-                case '=': /* DECKPAM */
-                        return VTE_CMD_DECKPAM;
-                case '>': /* DECKPNM */
-                        return VTE_CMD_DECKPNM;
-                case 'D': /* IND */
-                        return VTE_CMD_IND;
-                case 'E': /* NEL */
-                        return VTE_CMD_NEL;
-                case 'F': /* Cursor to lower-left corner of screen */
-                        return VTE_CMD_XTERM_CLLHP;
-                case 'H': /* HTS */
-                        return VTE_CMD_HTS;
-                case 'M': /* RI */
-                        return VTE_CMD_RI;
-                case 'N': /* SS2 */
-                        return VTE_CMD_SS2;
-                case 'O': /* SS3 */
-                        return VTE_CMD_SS3;
-                case 'P': /* DCS */
-                        /* this is already handled by the state-machine */
-                        break;
-                case 'V': /* SPA */
-                        return VTE_CMD_SPA;
-                case 'W': /* EPA */
-                        return VTE_CMD_EPA;
-                case 'X': /* SOS */
-                        /* this is already handled by the state-machine */
-                        break;
-                case 'Z': /* SCI */
-                        /* this is already handled by the state-machine */
-                        break;
-                case '[': /* CSI */
-                        /* this is already handled by the state-machine */
-                        break;
-                case '\\': /* ST */
-                        return VTE_CMD_ST;
-                case ']': /* OSC */
-                        /* this is already handled by the state-machine */
-                        break;
-                case '^': /* PM */
-                        /* this is already handled by the state-machine */
-                        break;
-                case '_': /* APC */
-                        /* this is already handled by the state-machine */
-                        break;
-                case 'c': /* RIS */
-                        return VTE_CMD_RIS;
-                case 'd': /* CMD */
-                        return VTE_CMD_CMD;
-                case 'l': /* Memory lock */
-                        return VTE_CMD_XTERM_MLHP;
-                case 'm': /* Memory unlock */
-                        return VTE_CMD_XTERM_MUHP;
-                case 'n': /* LS2 */
-                        return VTE_CMD_LS2;
-                case 'o': /* LS3 */
-                        return VTE_CMD_LS3;
-                case '|': /* LS3R */
-                        return VTE_CMD_LS3R;
-                case '}': /* LS2R */
-                        return VTE_CMD_LS2R;
-                case '~': /* LS1R */
-                        return VTE_CMD_LS1R;
+        unsigned int intermediates = seq->intermediates;
+        unsigned int intermediate0 = VTE_SEQ_INTERMEDIATE(intermediates);
+
+        /* Switch on the first intermediate */
+        switch (intermediate0) {
+        case VTE_SEQ_INTERMEDIATE_NONE:
+        case VTE_SEQ_INTERMEDIATE_HASH: {  /* Single control functions */
+                switch (_VTE_SEQ_CODE_ESC(seq->terminator, intermediates)) {
+#define _VTE_SEQ(cmd,type,f,p,ni,i) \
+                        case _VTE_SEQ_CODE_ESC(f, VTE_SEQ_INTERMEDIATE_##i): return VTE_CMD_##cmd;
+#include "parser-esc.hh"
+#undef _VTE_SEQ
+                default: return VTE_CMD_NONE;
                 }
-
-                return VTE_CMD_NONE;
+                break;
         }
 
-        unsigned int const g_designators =
-                VTE_SEQ_FLAG_POPEN | VTE_SEQ_FLAG_PCLOSE |
-                VTE_SEQ_FLAG_MULT  | VTE_SEQ_FLAG_PLUS   |
-                VTE_SEQ_FLAG_MINUS | VTE_SEQ_FLAG_DOT    |
-                VTE_SEQ_FLAG_SLASH;
-
-        if (hweight32(flags & g_designators) == 1) {
-                unsigned int const remaining_flags = flags & ~g_designators;
-                int cmd = (remaining_flags & VTE_SEQ_FLAG_CASH) ? VTE_CMD_GnDMm : VTE_CMD_GnDm;
-                int cs = VTE_CHARSET_NONE;
-
-                switch (flags & g_designators) {
-                case VTE_SEQ_FLAG_POPEN:
-                case VTE_SEQ_FLAG_PCLOSE:
-                case VTE_SEQ_FLAG_MULT:
-                case VTE_SEQ_FLAG_PLUS:
-                        cs = vte_parse_charset_94(seq->terminator, remaining_flags);
-                        break;
-                case VTE_SEQ_FLAG_SLASH:
-                        if (remaining_flags == VTE_SEQ_FLAG_PERCENT) { /* DOCS */
-                                cmd = VTE_CMD_DOCS;
-                                cs = vte_parse_charset_ocs(seq->terminator, /* all */ flags);
-                                break;
+        case VTE_SEQ_INTERMEDIATE_SPACE:   /* Announce code structure */
+                if (VTE_SEQ_REMOVE_INTERMEDIATE(intermediates) == 0)
+                        return VTE_CMD_ACS;
+                break;
+
+        case VTE_SEQ_INTERMEDIATE_BANG:    /* C0-designate */
+        case VTE_SEQ_INTERMEDIATE_DQUOTE:  /* C1-designate */
+                *cs_out = VTE_MAKE_CHARSET(vte_parse_charset_control(seq->terminator, intermediates),
+                                           intermediate0 - VTE_SEQ_INTERMEDIATE_BANG);
+                return VTE_CMD_CnD;
+
+        case VTE_SEQ_INTERMEDIATE_CASH: {  /* Designate multi-byte character sets */
+                unsigned int remaining_intermediates = VTE_SEQ_REMOVE_INTERMEDIATE(intermediates);
+                unsigned int intermediate1 = VTE_SEQ_INTERMEDIATE(remaining_intermediates);
+                remaining_intermediates = VTE_SEQ_REMOVE_INTERMEDIATE(remaining_intermediates);
+
+                /* Check the 2nd intermediate */
+                switch (intermediate1) {
+                case VTE_SEQ_INTERMEDIATE_NONE:
+                        /* For compatibility with an earlier version of ISO-2022,
+                         * ESC 2/4 4/0, ESC 2/4 4/1 and ESC 2/4 4/2 designate G0
+                         * sets (i.e., without the 2/8 as 2nd intermediate byte).
+                         */
+                        switch (seq->terminator) {
+                        case '@':
+                        case 'A':
+                        case 'B': /* G0-designate multibyte charset */
+                                *cs_out = VTE_MAKE_CHARSET(vte_parse_charset_94_n(seq->terminator,
+                                                                                  remaining_intermediates),
+                                                           0);
+                                return VTE_CMD_GnDMm;
                         }
-                        /* fallthrough */
-                case VTE_SEQ_FLAG_MINUS:
-                case VTE_SEQ_FLAG_DOT:
-                        cs = vte_parse_charset_96(seq->terminator, remaining_flags);
                         break;
-                }
 
-                if (cs_out)
-                        *cs_out = cs;
+                case VTE_SEQ_INTERMEDIATE_POPEN:  /* G0-designate 94^n-set */
+                case VTE_SEQ_INTERMEDIATE_PCLOSE: /* G1-designate 94^n-set */
+                case VTE_SEQ_INTERMEDIATE_MULT:   /* G2-designate 94^n-set */
+                case VTE_SEQ_INTERMEDIATE_PLUS:   /* G3-designate 94^n-set */
+                        *cs_out = VTE_MAKE_CHARSET(vte_parse_charset_94_n(seq->terminator,
+                                                                          remaining_intermediates),
+                                                   intermediate1 - VTE_SEQ_INTERMEDIATE_POPEN);
+                        return VTE_CMD_GnDMm;
 
-                return cmd;
-        }
+                case VTE_SEQ_INTERMEDIATE_COMMA:  /* Reserved for future standardisation */
+                        break;
 
-        switch (flags) {
-        case VTE_SEQ_FLAG_SPACE: /* ACS */
-                return VTE_CMD_ACS;
+                case VTE_SEQ_INTERMEDIATE_MINUS:  /* G1-designate 96^n-set */
+                case VTE_SEQ_INTERMEDIATE_DOT:    /* G2-designate 96^n-set */
+                case VTE_SEQ_INTERMEDIATE_SLASH:  /* G3-designate 96^n-set */
+                        *cs_out = VTE_MAKE_CHARSET(vte_parse_charset_96_n(seq->terminator,
+                                                                          remaining_intermediates),
+                                                   intermediate1 - VTE_SEQ_INTERMEDIATE_COMMA);
+                        return VTE_CMD_GnDMm;
+                }
+                break;
+        }
 
-        case VTE_SEQ_FLAG_BANG: /* C0-designate */
-        case VTE_SEQ_FLAG_DQUOTE: /* C1-designate */
-                if (cs_out)
-                        *cs_out = vte_parse_charset_control(seq->terminator, flags);
-                return VTE_CMD_CnD;
+        case VTE_SEQ_INTERMEDIATE_PERCENT: /* Designate other coding system */
+                *cs_out = vte_parse_charset_ocs(seq->terminator,
+                                                VTE_SEQ_REMOVE_INTERMEDIATE(intermediates));
+                return VTE_CMD_DOCS;
 
-        case VTE_SEQ_FLAG_HASH:
-                switch (seq->terminator) {
-                case '3': /* DECDHL top-half */
-                        return VTE_CMD_DECDHL_TH;
-                case '4': /* DECDHL bottom-half */
-                        return VTE_CMD_DECDHL_BH;
-                case '5': /* DECSWL */
-                        return VTE_CMD_DECSWL;
-                case '6': /* DECDWL */
-                        return VTE_CMD_DECDWL;
-                case '8': /* DECALN */
-                        return VTE_CMD_DECALN;
-                }
+        case VTE_SEQ_INTERMEDIATE_AND:     /* Identify revised registration */
+                if (VTE_SEQ_REMOVE_INTERMEDIATE(intermediates) == 0)
+                        return VTE_CMD_IRR;
                 break;
 
-        case VTE_SEQ_FLAG_CASH:
-                /* For compatibility with an earlier version of ISO-2022,
-                 * ESC 2/4 4/0, ESC 2/4 4/1 and ESC 2/4 4/2 designate G0
-                 * sets (i.e., without the 2/8 as 2nd intermediate byte).
-                 */
-                switch (seq->terminator) {
-                case '@':
-                case 'A':
-                case 'B': /* G0-designate multibyte charset */
-                        if (cs_out)
-                                *cs_out = vte_parse_charset_94(seq->terminator,
-                                                               flags /* | VTE_SEQ_FLAG_POPEN */);
-                        return VTE_CMD_GnDMm;
-                }
+        case VTE_SEQ_INTERMEDIATE_SQUOTE:  /* Reserved for future standardisation */
                 break;
 
-        case VTE_SEQ_FLAG_PERCENT: /* DOCS */
-        case VTE_SEQ_FLAG_PERCENT | VTE_SEQ_FLAG_SLASH: /* DOCS, but already handled above */
-                if (cs_out)
-                        *cs_out = vte_parse_charset_ocs(seq->terminator, flags);
+        case VTE_SEQ_INTERMEDIATE_POPEN:   /* G0-designate 94-set */
+        case VTE_SEQ_INTERMEDIATE_PCLOSE:  /* G1-designate 94-set */
+        case VTE_SEQ_INTERMEDIATE_MULT:    /* G2-designate 94-set */
+        case VTE_SEQ_INTERMEDIATE_PLUS:    /* G3-designate 94-set */
+                *cs_out = VTE_MAKE_CHARSET(vte_parse_charset_94(seq->terminator,
+                                                                VTE_SEQ_REMOVE_INTERMEDIATE(intermediates)),
+                                           intermediate0 - VTE_SEQ_INTERMEDIATE_POPEN);
+                return VTE_CMD_GnDm;
 
-                return VTE_CMD_DOCS;
+        case VTE_SEQ_INTERMEDIATE_COMMA:   /* Reserved for future standardisation */
+                break;
 
-        case VTE_SEQ_FLAG_AND: /* IRR */
-                return VTE_CMD_IRR;
+        case VTE_SEQ_INTERMEDIATE_MINUS:   /* G1-designate 96-set */
+        case VTE_SEQ_INTERMEDIATE_DOT:     /* G2-designate 96-set */
+        case VTE_SEQ_INTERMEDIATE_SLASH:   /* G3-designate 96-set */
+                *cs_out = VTE_MAKE_CHARSET(vte_parse_charset_96(seq->terminator,
+                                                                VTE_SEQ_REMOVE_INTERMEDIATE(intermediates)),
+                                           intermediate0 - VTE_SEQ_INTERMEDIATE_COMMA);
+                return VTE_CMD_GnDm;
         }
 
         return VTE_CMD_NONE;
@@ -413,505 +469,24 @@ static unsigned int vte_parse_host_escape(const struct vte_seq *seq,
 
 static unsigned int vte_parse_host_csi(const struct vte_seq *seq)
 {
-        unsigned int flags;
-
-        flags = seq->intermediates;
-
-        switch (seq->terminator) {
-        case 'A':
-                if (flags == 0) /* CUU */
-                        return VTE_CMD_CUU;
-                break;
-        case 'a':
-                if (flags == 0) /* HPR */
-                        return VTE_CMD_HPR;
-                else if (flags == VTE_SEQ_FLAG_SPACE) /* TALE */
-                        return VTE_CMD_TALE;
-                break;
-        case 'B':
-                if (flags == 0) /* CUD */
-                        return VTE_CMD_CUD;
-                break;
-        case 'b':
-                if (flags == 0) /* REP */
-                        return VTE_CMD_REP;
-                else if (flags == VTE_SEQ_FLAG_SPACE) /* TAC */
-                        return VTE_CMD_TAC;
-                break;
-        case 'C':
-                if (flags == 0) /* CUF */
-                        return VTE_CMD_CUF;
-                break;
-        case 'c':
-                if (flags == 0) /* DA1 */
-                        return VTE_CMD_DA1;
-                else if (flags == VTE_SEQ_FLAG_SPACE) /* TCC */
-                        return VTE_CMD_TCC;
-                else if (flags == VTE_SEQ_FLAG_GT) /* DA2 */
-                        return VTE_CMD_DA2;
-                else if (flags == VTE_SEQ_FLAG_EQUAL) /* DA3 */
-                        return VTE_CMD_DA3;
-                break;
-        case 'D':
-                if (flags == 0) /* CUB */
-                        return VTE_CMD_CUB;
-                break;
-        case 'd':
-                if (flags == 0) /* VPA */
-                        return VTE_CMD_VPA;
-                else if (flags == VTE_SEQ_FLAG_SPACE) /* TSR */
-                        return VTE_CMD_TSR;
-                break;
-        case 'E':
-                if (flags == 0) /* CNL */
-                        return VTE_CMD_CNL;
-                break;
-        case 'e':
-                if (flags == 0) /* VPR */
-                        return VTE_CMD_VPR;
-                break;
-        case 'F':
-                if (flags == 0) /* CPL */
-                        return VTE_CMD_CPL;
-                break;
-        case 'f':
-                if (flags == 0) /* HVP */
-                        return VTE_CMD_HVP;
-                break;
-        case 'G':
-                if (flags == 0) /* CHA */
-                        return VTE_CMD_CHA;
-                break;
-        case 'g':
-                if (flags == 0) /* TBC */
-                        return VTE_CMD_TBC;
-                else if (flags == VTE_SEQ_FLAG_MULT) /* DECLFKC */
-                        return VTE_CMD_DECLFKC;
-                break;
-        case 'H':
-                if (flags == 0) /* CUP */
-                        return VTE_CMD_CUP;
-                break;
-        case 'h':
-                if (flags == 0) /* SM ECMA */
-                        return VTE_CMD_SM_ECMA;
-                else if (flags == VTE_SEQ_FLAG_WHAT) /* SM DEC */
-                        return VTE_CMD_SM_DEC;
-                break;
-        case 'I':
-                if (flags == 0) /* CHT */
-                        return VTE_CMD_CHT;
-                break;
-        case 'i':
-                if (flags == 0) /* MC ANSI */
-                        return VTE_CMD_MC_ANSI;
-                else if (flags == VTE_SEQ_FLAG_WHAT) /* MC DEC */
-                        return VTE_CMD_MC_DEC;
-                break;
-        case 'J':
-                if (flags == 0) /* ED */
-                        return VTE_CMD_ED;
-                else if (flags == VTE_SEQ_FLAG_WHAT) /* DECSED */
-                        return VTE_CMD_DECSED;
-                break;
-        case 'K':
-                if (flags == 0) /* EL */
-                        return VTE_CMD_EL;
-                else if (flags == VTE_SEQ_FLAG_WHAT) /* DECSEL */
-                        return VTE_CMD_DECSEL;
-                break;
-        case 'L':
-                if (flags == 0) /* IL */
-                        return VTE_CMD_IL;
-                break;
-        case 'l':
-                if (flags == 0) /* RM ECMA */
-                        return VTE_CMD_RM_ECMA;
-                else if (flags == VTE_SEQ_FLAG_WHAT) /* RM DEC */
-                        return VTE_CMD_RM_DEC;
-                break;
-        case 'M':
-                if (flags == 0) /* DL */
-                        return VTE_CMD_DL;
-                break;
-        case 'm':
-                if (flags == 0) /* SGR */
-                        return VTE_CMD_SGR;
-                else if (flags == VTE_SEQ_FLAG_GT) /* XTERM SMR */
-                        return VTE_CMD_XTERM_SRV;
-                break;
-        case 'n':
-                if (flags == 0) /* DSR ECMA */
-                        return VTE_CMD_DSR_ECMA;
-                else if (flags == VTE_SEQ_FLAG_GT) /* XTERM RMR */
-                        return VTE_CMD_XTERM_RRV;
-                else if (flags == VTE_SEQ_FLAG_WHAT) /* DSR DEC */
-                        return VTE_CMD_DSR_DEC;
-                break;
-        case 'P':
-                if (flags == 0) /* DCH */
-                        return VTE_CMD_DCH;
-                else if (flags == VTE_SEQ_FLAG_SPACE) /* PPA */
-                        return VTE_CMD_PPA;
-                break;
-        case 'p':
-                if (flags == 0) /* DECSSL */
-                        return VTE_CMD_DECSSL;
-                else if (flags == VTE_SEQ_FLAG_SPACE) /* DECSSCLS */
-                        return VTE_CMD_DECSSCLS;
-                else if (flags == VTE_SEQ_FLAG_BANG) /* DECSTR */
-                        return VTE_CMD_DECSTR;
-                else if (flags == VTE_SEQ_FLAG_DQUOTE) /* DECSCL */
-                        return VTE_CMD_DECSCL;
-                else if (flags == VTE_SEQ_FLAG_CASH) /* DECRQM-ECMA */
-                        return VTE_CMD_DECRQM_ECMA;
-                else if (flags == (VTE_SEQ_FLAG_CASH |
-                                   VTE_SEQ_FLAG_WHAT)) /* DECRQM-DEC */
-                        return VTE_CMD_DECRQM_DEC;
-                else if (flags == VTE_SEQ_FLAG_PCLOSE) /* DECSDPT */
-                        return VTE_CMD_DECSDPT;
-                else if (flags == VTE_SEQ_FLAG_MULT) /* DECSPPCS */
-                        return VTE_CMD_DECSPPCS;
-                else if (flags == VTE_SEQ_FLAG_PLUS) /* DECSR */
-                        return VTE_CMD_DECSR;
-                else if (flags == VTE_SEQ_FLAG_COMMA) /* DECLTOD */
-                        return VTE_CMD_DECLTOD;
-                else if (flags == VTE_SEQ_FLAG_GT) /* XTERM SPM */
-                        return VTE_CMD_XTERM_SPM;
-                break;
-        case 'Q':
-                if (flags == VTE_SEQ_FLAG_SPACE) /* PPR */
-                        return VTE_CMD_PPR;
-                break;
-        case 'q':
-                if (flags == 0) /* DECLL */
-                        return VTE_CMD_DECLL;
-                else if (flags == VTE_SEQ_FLAG_SPACE) /* DECSCUSR */
-                        return VTE_CMD_DECSCUSR;
-                else if (flags == VTE_SEQ_FLAG_DQUOTE) /* DECSCA */
-                        return VTE_CMD_DECSCA;
-                else if (flags == VTE_SEQ_FLAG_CASH) /* DECSDDT */
-                        return VTE_CMD_DECSDDT;
-                else if (flags == VTE_SEQ_FLAG_MULT) /* DECSRC */
-                        return VTE_CMD_DECSR;
-                else if (flags == VTE_SEQ_FLAG_PLUS) /* DECELF */
-                        return VTE_CMD_DECELF;
-                else if (flags == VTE_SEQ_FLAG_COMMA) /* DECTID */
-                        return VTE_CMD_DECTID;
-                break;
-        case 'R':
-                if (flags == VTE_SEQ_FLAG_SPACE) /* PPB */
-                        return VTE_CMD_PPB;
-                break;
-        case 'r':
-                if (flags == 0) {
-                        /* DECSTBM */
-                        return VTE_CMD_DECSTBM;
-                } else if (flags == VTE_SEQ_FLAG_SPACE) {
-                        /* DECSKCV */
-                        return VTE_CMD_DECSKCV;
-                } else if (flags == VTE_SEQ_FLAG_CASH) {
-                        /* DECCARA */
-                        return VTE_CMD_DECCARA;
-                } else if (flags == VTE_SEQ_FLAG_MULT) {
-                        /* DECSCS */
-                        return VTE_CMD_DECSCS;
-                } else if (flags == VTE_SEQ_FLAG_PLUS) {
-                        /* DECSMKR */
-                        return VTE_CMD_DECSMKR;
-                } else if (flags == VTE_SEQ_FLAG_WHAT) {
-                        /*
-                         * There's a conflict between DECPCTERM and XTERM-RPM.
-                         * XTERM-RPM takes a single argument, DECPCTERM takes 2.
-                         * Split both up and forward the call to the closer
-                         * match.
-                         */
-                        // FIXMEchpe!
-                        if (seq->n_final_args <= 1) /* XTERM RPM */
-                                return VTE_CMD_XTERM_RPM;
-                        else if (seq->n_final_args >= 2) /* DECPCTERM */
-                                return VTE_CMD_DECPCTERM;
-                }
-                break;
-        case 'S':
-                if (flags == 0) /* SU */
-                        return VTE_CMD_SU;
-                else if (flags == VTE_SEQ_FLAG_WHAT) /* XTERM SGFX */
-                        return VTE_CMD_XTERM_SGFX;
-                break;
-        case 's':
-                if (flags == 0) {
-                        /*
-                         * There's a conflict between DECSLRM and SC-ANSI which
-                         * cannot be resolved without knowing the state of
-                         * DECLRMM. We leave that decision up to the caller.
-                         */
-                        return VTE_CMD_DECSLRM_OR_SC;
-                } else if (flags == VTE_SEQ_FLAG_CASH) {
-                        /* DECSPRTT */
-                        return VTE_CMD_DECSPRTT;
-                } else if (flags == VTE_SEQ_FLAG_MULT) {
-                        /* DECSFC */
-                        return VTE_CMD_DECSFC;
-                } else if (flags == VTE_SEQ_FLAG_WHAT) {
-                        /* XTERM SPM */
-                        return VTE_CMD_XTERM_SPM;
-                }
-                break;
-        case 'T':
-                if (flags == 0) {
-                        /*
-                         * There's a conflict between SD and XTERM IHMT that we
-                         * have to resolve by checking the parameter count.
-                         * XTERM_IHMT needs exactly 5 arguments, SD takes 0 or
-                         * 1. We're conservative here and give both a wider
-                         * range to allow unused arguments (compat...).
-                         */
-                        // FIXMEchpe!
-                        if (seq->n_final_args < 5) {
-                                /* SD */
-                                return VTE_CMD_SD;
-                        } else if (seq->n_final_args >= 5) {
-                                /* XTERM IHMT */
-                                return VTE_CMD_XTERM_IHMT;
-                        }
-                } else if (flags == VTE_SEQ_FLAG_GT) {
-                        /* XTERM RTM */
-                        return VTE_CMD_XTERM_RTM;
-                }
-                break;
-        case 't':
-                if (flags == 0) {
-                        /*
-                         * There's a conflict between XTERM_WM and DECSLPP. We
-                         * cannot resolve it as some combinations are valid for
-                         * both. We go with XTERM_WM for now.
-                         *
-                         * TODO: Figure out how to resolve that conflict and
-                         *       return VTE_CMD_DECSLPP if possible.
-                         */
-                        return VTE_CMD_XTERM_WM; /* XTERM WM */
-                } else if (flags == VTE_SEQ_FLAG_SPACE) {
-                        /* DECSWBV */
-                        return VTE_CMD_DECSWBV;
-                } else if (flags == VTE_SEQ_FLAG_DQUOTE) {
-                        /* DECSRFR */
-                        return VTE_CMD_DECSRFR;
-                } else if (flags == VTE_SEQ_FLAG_CASH) {
-                        /* DECRARA */
-                        return VTE_CMD_DECRARA;
-                } else if (flags == VTE_SEQ_FLAG_GT) {
-                        /* XTERM STM */
-                        return VTE_CMD_XTERM_STM;
-                }
-                break;
-        case 'U':
-                if (flags == 0) /* NP */
-                        return VTE_CMD_NP;
-                break;
-        case 'u':
-                if (flags == 0) {
-                        /* RC */
-                        return VTE_CMD_RC;
-                } else if (flags == VTE_SEQ_FLAG_SPACE) {
-                        /* DECSMBV */
-                        return VTE_CMD_DECSMBV;
-                } else if (flags == VTE_SEQ_FLAG_DQUOTE) {
-                        /* DECSTRL */
-                        return VTE_CMD_DECSTRL;
-                } else if (flags == VTE_SEQ_FLAG_WHAT) {
-                        /* DECRQUPSS */
-                        return VTE_CMD_DECRQUPSS;
-                } else if (vte_seq_arg_value(seq->args[0]) == 1 && flags == VTE_SEQ_FLAG_CASH) {
-                        /* DECRQTSR */
-                        return VTE_CMD_DECRQTSR;
-                } else if (flags == VTE_SEQ_FLAG_MULT) {
-                        /* DECSCP */
-                        return VTE_CMD_DECSCP;
-                } else if (flags == VTE_SEQ_FLAG_COMMA) {
-                        /* DECRQKT */
-                        return VTE_CMD_DECRQKT;
-                }
-                break;
-        case 'V':
-                if (flags == 0) /* PP */
-                        return VTE_CMD_PP;
-                break;
-        case 'v':
-                if (flags == VTE_SEQ_FLAG_SPACE) /* DECSLCK */
-                        return VTE_CMD_DECSLCK;
-                else if (flags == VTE_SEQ_FLAG_DQUOTE) /* DECRQDE */
-                        return VTE_CMD_DECRQDE;
-                else if (flags == VTE_SEQ_FLAG_CASH) /* DECCRA */
-                        return VTE_CMD_DECCRA;
-                else if (flags == VTE_SEQ_FLAG_COMMA) /* DECRPKT */
-                        return VTE_CMD_DECRPKT;
-                break;
-        case 'W':
-                if (vte_seq_arg_value(seq->args[0]) == 5 && flags == VTE_SEQ_FLAG_WHAT) {
-                        /* DECST8C */
-                        return VTE_CMD_DECST8C;
-                }
-                break;
-        case 'w':
-                if (flags == VTE_SEQ_FLAG_CASH) /* DECRQPSR */
-                        return VTE_CMD_DECRQPSR;
-                else if (flags == VTE_SEQ_FLAG_SQUOTE) /* DECEFR */
-                        return VTE_CMD_DECEFR;
-                else if (flags == VTE_SEQ_FLAG_PLUS) /* DECSPP */
-                        return VTE_CMD_DECSPP;
-                break;
-        case 'X':
-                if (flags == 0) /* ECH */
-                        return VTE_CMD_ECH;
-                break;
-        case 'x':
-                if (flags == 0) /* DECREQTPARM */
-                        return VTE_CMD_DECREQTPARM;
-                else if (flags == VTE_SEQ_FLAG_CASH) /* DECFRA */
-                        return VTE_CMD_DECFRA;
-                else if (flags == VTE_SEQ_FLAG_MULT) /* DECSACE */
-                        return VTE_CMD_DECSACE;
-                else if (flags == VTE_SEQ_FLAG_PLUS) /* DECRQPKFM */
-                        return VTE_CMD_DECRQPKFM;
-                break;
-        case 'y':
-                if (flags == 0) /* DECTST */
-                        return VTE_CMD_DECTST;
-                else if (flags == VTE_SEQ_FLAG_MULT) /* DECRQCRA */
-                        return VTE_CMD_DECRQCRA;
-                else if (flags == VTE_SEQ_FLAG_PLUS) /* DECPKFMR */
-                        return VTE_CMD_DECPKFMR;
-                break;
-        case 'Z':
-                if (flags == 0) /* CBT */
-                        return VTE_CMD_CBT;
-                break;
-        case 'z':
-                if (flags == VTE_SEQ_FLAG_CASH) /* DECERA */
-                        return VTE_CMD_DECERA;
-                else if (flags == VTE_SEQ_FLAG_SQUOTE) /* DECELR */
-                        return VTE_CMD_DECELR;
-                else if (flags == VTE_SEQ_FLAG_MULT) /* DECINVM */
-                        return VTE_CMD_DECINVM;
-                else if (flags == VTE_SEQ_FLAG_PLUS) /* DECPKA */
-                        return VTE_CMD_DECPKA;
-                break;
-        case '@':
-                if (flags == 0) /* ICH */
-                        return VTE_CMD_ICH;
-                break;
-        case '`':
-                if (flags == 0) /* HPA */
-                        return VTE_CMD_HPA;
-                else if (flags == VTE_SEQ_FLAG_SPACE) /* TATE */
-                        return VTE_CMD_TATE;
-                break;
-        case '{':
-                if (flags == VTE_SEQ_FLAG_CASH) /* DECSERA */
-                        return VTE_CMD_DECSERA;
-                else if (flags == VTE_SEQ_FLAG_SQUOTE) /* DECSLE */
-                        return VTE_CMD_DECSLE;
-                break;
-        case '|':
-                if (flags == VTE_SEQ_FLAG_CASH) /* DECSCPP */
-                        return VTE_CMD_DECSCPP;
-                else if (flags == VTE_SEQ_FLAG_SQUOTE) /* DECRQLP */
-                        return VTE_CMD_DECRQLP;
-                else if (flags == VTE_SEQ_FLAG_MULT) /* DECSNLS */
-                        return VTE_CMD_DECSNLS;
-                break;
-        case '}':
-                if (flags == VTE_SEQ_FLAG_SPACE) /* DECKBD */
-                        return VTE_CMD_DECKBD;
-                else if (flags == VTE_SEQ_FLAG_CASH) /* DECSASD */
-                        return VTE_CMD_DECSASD;
-                else if (flags == VTE_SEQ_FLAG_SQUOTE) /* DECIC */
-                        return VTE_CMD_DECIC;
-                break;
-        case '~':
-                if (flags == VTE_SEQ_FLAG_SPACE) /* DECTME */
-                        return VTE_CMD_DECTME;
-                else if (flags == VTE_SEQ_FLAG_CASH) /* DECSSDT */
-                        return VTE_CMD_DECSSDT;
-                else if (flags == VTE_SEQ_FLAG_SQUOTE) /* DECDC */
-                        return VTE_CMD_DECDC;
-                break;
+        switch (_VTE_SEQ_CODE(seq->terminator, seq->intermediates)) {
+#define _VTE_SEQ(cmd,type,f,p,ni,i) \
+                case _VTE_SEQ_CODE(f, _VTE_SEQ_CODE_COMBINE(VTE_SEQ_PARAMETER_##p, 
VTE_SEQ_INTERMEDIATE_##i)): return VTE_CMD_##cmd;
+#include "parser-csi.hh"
+#undef _VTE_SEQ
+        default: return VTE_CMD_NONE;
         }
-
-        return VTE_CMD_NONE;
 }
 
 static unsigned int vte_parse_host_dcs(const struct vte_seq *seq)
 {
-        unsigned int const flags = seq->intermediates;
-
-        switch (seq->terminator) {
-        case 'p':
-                if (flags == 0) /* DECREGIS */
-                        return VTE_CMD_DECREGIS;
-                else if (flags == VTE_SEQ_FLAG_CASH) /* DECRSTS */
-                        return VTE_CMD_DECRSTS;
-                break;
-        case 'q':
-                if (flags == 0) /* DECSIXEL */
-                        return VTE_CMD_DECSIXEL;
-                else if (flags == VTE_SEQ_FLAG_CASH) /* DECRQSS */
-                        return VTE_CMD_DECRQSS;
-                break;
-        case 'r':
-                if (flags == 0) /* DECLBAN */
-                        return VTE_CMD_DECLBAN;
-                else if (flags == VTE_SEQ_FLAG_CASH) /* DECRQSS */
-                        return VTE_CMD_DECRQSS; // FIXMEchpe really??
-                break;
-        case 's':
-                if (flags == VTE_SEQ_FLAG_CASH) /* DECRQTSR */
-                        return VTE_CMD_DECRQTSR;
-                break;
-        case 't':
-                if (flags == VTE_SEQ_FLAG_CASH) /* DECRSPS */
-                        return VTE_CMD_DECRSPS;
-                break;
-        case 'u':
-                if (flags == VTE_SEQ_FLAG_BANG) /* DECAUPSS */
-                        return VTE_CMD_DECAUPSS;
-                break;
-        case 'v':
-                if (flags == 0) /* DECLANS */
-                        return VTE_CMD_DECLANS;
-                break;
-        case 'w':
-                if (flags == 0) /* DECLBD */
-                        return VTE_CMD_DECLBD;
-                break;
-        case 'x':
-                if (flags == VTE_SEQ_FLAG_DQUOTE) /* DECPFK */
-                        return VTE_CMD_DECPFK;
-                break;
-        case 'y':
-                if (flags == VTE_SEQ_FLAG_DQUOTE) /* DECPAK */
-                        return VTE_CMD_DECPAK;
-                break;
-        case 'z':
-                if (flags == VTE_SEQ_FLAG_BANG) /* DECDMAC */
-                        return VTE_CMD_DECDMAC;
-                else if (flags == VTE_SEQ_FLAG_DQUOTE) /* DECCKD */
-                        return VTE_CMD_DECCKD;
-                break;
-        case '{':
-                if (flags == 0) /* DECDLD */
-                        return VTE_CMD_DECDLD;
-                else if (flags == VTE_SEQ_FLAG_BANG) /* DECSTUI */
-                        return VTE_CMD_DECSTUI;
-                break;
-        case '|':
-                if (flags == 0) /* DECUDK */
-                        return VTE_CMD_DECUDK;
-                break;
+        switch (_VTE_SEQ_CODE(seq->terminator, seq->intermediates)) {
+#define _VTE_SEQ(cmd,type,f,p,ni,i) \
+                case _VTE_SEQ_CODE(f, _VTE_SEQ_CODE_COMBINE(VTE_SEQ_PARAMETER_##p, 
VTE_SEQ_INTERMEDIATE_##i)): return VTE_CMD_##cmd;
+#include "parser-dcs.hh"
+#undef _VTE_SEQ
+        default: return VTE_CMD_NONE;
         }
-
-        return VTE_CMD_NONE;
 }
 
 static unsigned int vte_parse_host_sci(const struct vte_seq *seq)
@@ -953,24 +528,28 @@ enum parser_state {
 };
 
 enum parser_action {
-        ACTION_NONE,            /* placeholder */
-        ACTION_CLEAR,           /* clear parameters */
-        ACTION_IGNORE,          /* ignore the character entirely */
-        ACTION_PRINT,           /* print the character on the console */
-        ACTION_EXECUTE,         /* execute single control character (C0/C1) */
-        ACTION_COLLECT,         /* collect intermediate character */
-        ACTION_PARAM,           /* collect parameter character */
-        ACTION_ESC_DISPATCH,    /* dispatch escape sequence */
-        ACTION_CSI_DISPATCH,    /* dispatch CSI sequence */
-        ACTION_DCS_START,       /* start of DCS data */
-        ACTION_DCS_CONSUME,     /* consume DCS terminator */
-        ACTION_DCS_COLLECT,     /* collect DCS data */
-        ACTION_DCS_DISPATCH,    /* dispatch DCS sequence */
-        ACTION_OSC_START,       /* clear and clear string data */
-        ACTION_OSC_COLLECT,     /* collect OSC data */
-        ACTION_OSC_DISPATCH,    /* dispatch OSC sequence */
-        ACTION_SCI_DISPATCH,    /* dispatch SCI sequence */
+        ACTION_NONE,              /* placeholder */
+        ACTION_CLEAR,             /* clear parameters */
+        ACTION_IGNORE,            /* ignore the character entirely */
+        ACTION_PRINT,             /* print the character on the console */
+        ACTION_EXECUTE,           /* execute single control character (C0/C1) */
+        ACTION_COLLECT_ESC,       /* collect intermediate character of ESCAPE sequence */
+        ACTION_COLLECT_CSI,       /* collect intermediate character of CSI or DCS sequence */
+        ACTION_COLLECT_PARAMETER, /* collect parameter character of CSI or DCS sequence */
+        ACTION_PARAM,             /* collect parameter character */
+        ACTION_ESC_DISPATCH,      /* dispatch escape sequence */
+        ACTION_CSI_DISPATCH,      /* dispatch CSI sequence */
+        ACTION_DCS_START,         /* start of DCS data */
+        ACTION_DCS_CONSUME,       /* consume DCS terminator */
+        ACTION_DCS_COLLECT,       /* collect DCS data */
+        ACTION_DCS_DISPATCH,      /* dispatch DCS sequence */
+        ACTION_OSC_START,         /* clear and clear string data */
+        ACTION_OSC_COLLECT,       /* collect OSC data */
+        ACTION_OSC_DISPATCH,      /* dispatch OSC sequence */
+        ACTION_SCI_DISPATCH,      /* dispatch SCI sequence */
         ACTION_N,
+
+        ACTION_COLLECT_DCS = ACTION_COLLECT_CSI, /* alias */
 };
 
 /**
@@ -1016,6 +595,7 @@ static inline void parser_clear(struct vte_parser *parser)
         parser->seq.command = VTE_CMD_NONE;
         parser->seq.terminator = 0;
         parser->seq.intermediates = 0;
+        parser->seq.n_intermediates = 0;
         parser->seq.charset = VTE_CHARSET_NONE;
         parser->seq.n_args = 0;
         parser->seq.n_final_args = 0;
@@ -1058,19 +638,41 @@ static int parser_execute(struct vte_parser *parser, uint32_t raw)
         return parser->seq.type;
 }
 
-static void parser_collect(struct vte_parser *parser, uint32_t raw)
+static void parser_collect_esc(struct vte_parser *parser, uint32_t raw)
 {
-        /*
-         * Usually, characters from 0x30 to 0x3f are only allowed as leading
-         * markers (or as part of the parameters), characters from 0x20 to 0x2f
-         * are only allowed as trailing markers. However, our state-machine
-         * already verifies those restrictions so we can handle them the same
-         * way here. Note that we safely allow markers to be specified multiple
-         * times.
+        assert(raw >= 0x20 && raw <= 0x2f);
+
+        /* ESCAPE sequences only have intermediates or 2/0..2/15, so there's no
+         * need for the extra shift as below for CSI/DCS sequences
          */
+        parser->seq.intermediates |= (VTE_SEQ_MAKE_INTERMEDIATE(raw) << (VTE_SEQ_INTERMEDIATE_BITS * 
parser->seq.n_intermediates++));
+}
+
+static void parser_collect_csi(struct vte_parser *parser, uint32_t raw)
+{
+        assert(raw >= 0x20 && raw <= 0x2f);
 
-        if (raw >= 0x20 && raw <= 0x3f)
-                parser->seq.intermediates |= 1 << (raw - 0x20);
+        /* In addition to 2/0..2/15 intermediates, CSI/DCS sequence
+         * can also have one parameter byte 3/12..3/15 at the
+         * start of the parameters (see parser_collect_parameter below);
+         * that's what the extra shift is for.
+         */
+        parser->seq.intermediates |= (VTE_SEQ_MAKE_INTERMEDIATE(raw) << (VTE_SEQ_PARAMETER_BITS +
+                                                                         VTE_SEQ_INTERMEDIATE_BITS * 
parser->seq.n_intermediates++));
+}
+
+static void parser_collect_parameter(struct vte_parser *parser, uint32_t raw)
+{
+        assert(raw >= 0x3c && raw <= 0x3f);
+
+        /* CSI/DCS may optionally have one parameter byte from 3/12..3/15
+         * at the start of the parameters; we put that into the lowest
+         * part of @seq.intermediates.
+         * Note that there can only be *one* such byte; the state machine
+         * already enforces that, so we do not need any additional checks
+         * here.
+         */
+        parser->seq.intermediates |= VTE_SEQ_MAKE_PARAMETER(raw);
 }
 
 static void parser_param(struct vte_parser *parser, uint32_t raw)
@@ -1238,8 +840,14 @@ static int parser_transition(struct vte_parser *parser,
                 return parser_print(parser, raw);
         case ACTION_EXECUTE:
                 return parser_execute(parser, raw);
-        case ACTION_COLLECT:
-                parser_collect(parser, raw);
+        case ACTION_COLLECT_ESC:
+                parser_collect_esc(parser, raw);
+                return VTE_SEQ_NONE;
+        case ACTION_COLLECT_CSI:
+                parser_collect_csi(parser, raw);
+                return VTE_SEQ_NONE;
+        case ACTION_COLLECT_PARAMETER:
+                parser_collect_parameter(parser, raw);
                 return VTE_SEQ_NONE;
         case ACTION_PARAM:
                 parser_param(parser, raw);
@@ -1326,7 +934,7 @@ static int parser_feed_to_state(struct vte_parser *parser, uint32_t raw)
                                                  ACTION_CLEAR);
                 case 0x20 ... 0x2f:        /* [' ' - '\'] */
                         return parser_transition(parser, raw, STATE_ESC_INT,
-                                                 ACTION_COLLECT);
+                                                 ACTION_COLLECT_ESC);
                 case 0x30 ... 0x4f:        /* ['0' - '~'] \ */
                 case 0x51 ... 0x57:        /* { 'P', 'X', 'Z' '[', ']', '^', '_' } */
                 case 0x59:
@@ -1369,7 +977,7 @@ static int parser_feed_to_state(struct vte_parser *parser, uint32_t raw)
                                                  ACTION_CLEAR);
                 case 0x20 ... 0x2f:        /* [' ' - '\'] */
                         return parser_transition(parser, raw, STATE_NONE,
-                                                 ACTION_COLLECT);
+                                                 ACTION_COLLECT_ESC);
                 case 0x30 ... 0x7e:        /* ['0' - '~'] */
                         return parser_transition(parser, raw, STATE_GROUND,
                                                  ACTION_ESC_DISPATCH);
@@ -1391,14 +999,14 @@ static int parser_feed_to_state(struct vte_parser *parser, uint32_t raw)
                                                  ACTION_CLEAR);
                 case 0x20 ... 0x2f:        /* [' ' - '\'] */
                         return parser_transition(parser, raw, STATE_CSI_INT,
-                                                 ACTION_COLLECT);
+                                                 ACTION_COLLECT_CSI);
                 case 0x30 ... 0x39:        /* ['0' - '9'] */
                 case 0x3a ... 0x3b:        /* [':' - ';'] */
                         return parser_transition(parser, raw, STATE_CSI_PARAM,
                                                  ACTION_PARAM);
                 case 0x3c ... 0x3f:        /* ['<' - '?'] */
                         return parser_transition(parser, raw, STATE_CSI_PARAM,
-                                                 ACTION_COLLECT);
+                                                 ACTION_COLLECT_PARAMETER);
                 case 0x40 ... 0x7e:        /* ['@' - '~'] */
                         return parser_transition(parser, raw, STATE_GROUND,
                                                  ACTION_CSI_DISPATCH);
@@ -1420,7 +1028,7 @@ static int parser_feed_to_state(struct vte_parser *parser, uint32_t raw)
                                                  ACTION_CLEAR);
                 case 0x20 ... 0x2f:        /* [' ' - '\'] */
                         return parser_transition(parser, raw, STATE_CSI_INT,
-                                                 ACTION_COLLECT);
+                                                 ACTION_COLLECT_CSI);
                 case 0x30 ... 0x39:        /* ['0' - '9'] */
                 case 0x3a ... 0x3b:        /* [':' - ';'] */
                         return parser_transition(parser, raw, STATE_NONE,
@@ -1449,7 +1057,7 @@ static int parser_feed_to_state(struct vte_parser *parser, uint32_t raw)
                                                  ACTION_CLEAR);
                 case 0x20 ... 0x2f:        /* [' ' - '\'] */
                         return parser_transition(parser, raw, STATE_NONE,
-                                                 ACTION_COLLECT);
+                                                 ACTION_COLLECT_CSI);
                 case 0x30 ... 0x3f:        /* ['0' - '?'] */
                         return parser_transition(parser, raw, STATE_CSI_IGNORE,
                                                  ACTION_NONE);
@@ -1496,14 +1104,14 @@ static int parser_feed_to_state(struct vte_parser *parser, uint32_t raw)
                                                  ACTION_CLEAR);
                 case 0x20 ... 0x2f:        /* [' ' - '\'] */
                         return parser_transition(parser, raw, STATE_DCS_INT,
-                                                 ACTION_COLLECT);
+                                                 ACTION_COLLECT_DCS);
                 case 0x30 ... 0x39:        /* ['0' - '9'] */
                 case 0x3a ... 0x3b:        /* [':' - ';'] */
                         return parser_transition(parser, raw, STATE_DCS_PARAM,
                                                  ACTION_PARAM);
                 case 0x3c ... 0x3f:        /* ['<' - '?'] */
                         return parser_transition(parser, raw, STATE_DCS_PARAM,
-                                                 ACTION_COLLECT);
+                                                 ACTION_COLLECT_PARAMETER);
                 case 0x40 ... 0x7e:        /* ['@' - '~'] */
                         return parser_transition(parser, raw, STATE_DCS_PASS,
                                                  ACTION_DCS_CONSUME);
@@ -1525,7 +1133,7 @@ static int parser_feed_to_state(struct vte_parser *parser, uint32_t raw)
                                                  ACTION_CLEAR);
                 case 0x20 ... 0x2f:        /* [' ' - '\'] */
                         return parser_transition(parser, raw, STATE_DCS_INT,
-                                                 ACTION_COLLECT);
+                                                 ACTION_COLLECT_DCS);
                 case 0x30 ... 0x39:        /* ['0' - '9'] */
                 case 0x3a ... 0x3b:        /* [':' - ';'] */
                         return parser_transition(parser, raw, STATE_NONE,
@@ -1554,7 +1162,7 @@ static int parser_feed_to_state(struct vte_parser *parser, uint32_t raw)
                                                  ACTION_CLEAR);
                 case 0x20 ... 0x2f:        /* [' ' - '\'] */
                         return parser_transition(parser, raw, STATE_NONE,
-                                                 ACTION_COLLECT);
+                                                 ACTION_COLLECT_DCS);
                 case 0x30 ... 0x3f:        /* ['0' - '?'] */
                         return parser_transition(parser, raw, STATE_DCS_IGNORE,
                                                  ACTION_NONE);
diff --git a/src/parser.hh b/src/parser.hh
index fdd47fe..b992d84 100644
--- a/src/parser.hh
+++ b/src/parser.hh
@@ -89,63 +89,70 @@ enum {
 };
 
 enum {
-        VTE_SEQ_INTERMEDIATE_NONE   = 0,
-
-        VTE_SEQ_INTERMEDIATE_SPACE  = ' ',  /* 02/00 */
-        VTE_SEQ_INTERMEDIATE_BANG   = '!',  /* 02/01 */
-        VTE_SEQ_INTERMEDIATE_DQUOTE = '"',  /* 02/02 */
-        VTE_SEQ_INTERMEDIATE_HASH   = '#',  /* 02/03 */
-        VTE_SEQ_INTERMEDIATE_CASH   = '$',  /* 02/04 */
-        VTE_SEQ_INTERMEDIATE_PERCENT= '%',  /* 02/05 */
-        VTE_SEQ_INTERMEDIATE_AND    = '&',  /* 02/06 */
-        VTE_SEQ_INTERMEDIATE_SQUOTE = '\'', /* 02/07 */
-        VTE_SEQ_INTERMEDIATE_POPEN  = '(',  /* 02/08 */
-        VTE_SEQ_INTERMEDIATE_PCLOSE = ')',  /* 02/09 */
-        VTE_SEQ_INTERMEDIATE_MULT   = '*',  /* 02/10 */
-        VTE_SEQ_INTERMEDIATE_PLUS   = '+',  /* 02/11 */
-        VTE_SEQ_INTERMEDIATE_COMMA  = ',',  /* 02/12 */
-        VTE_SEQ_INTERMEDIATE_MINUS  = '-',  /* 02/13 */
-        VTE_SEQ_INTERMEDIATE_DOT    = '.',  /* 02/14 */
-        VTE_SEQ_INTERMEDIATE_SLASH  = '/',  /* 02/15 */
-
-        /* 16-25 is reserved for numbers; unused */
-
-        /* COLON is reserved        = ':'   * 03/10 */
-        /* SEMICOLON is reserved    = ';'   * 03/11 */
-        VTE_SEQ_INTERMEDIATE_LT     = '<', /* 03/12 */
-        VTE_SEQ_INTERMEDIATE_EQUAL  = '=', /* 03/13 */
-        VTE_SEQ_INTERMEDIATE_GT     = '>', /* 03/14 */
-        VTE_SEQ_INTERMEDIATE_WHAT   = '?'  /* 03/15 */
+        VTE_SEQ_INTERMEDIATE_CHAR_NONE    = 0,
+
+        VTE_SEQ_INTERMEDIATE_CHAR_SPACE   = ' ',  /* 02/00 */
+        VTE_SEQ_INTERMEDIATE_CHAR_BANG    = '!',  /* 02/01 */
+        VTE_SEQ_INTERMEDIATE_CHAR_DQUOTE  = '"',  /* 02/02 */
+        VTE_SEQ_INTERMEDIATE_CHAR_HASH    = '#',  /* 02/03 */
+        VTE_SEQ_INTERMEDIATE_CHAR_CASH    = '$',  /* 02/04 */
+        VTE_SEQ_INTERMEDIATE_CHAR_PERCENT = '%',  /* 02/05 */
+        VTE_SEQ_INTERMEDIATE_CHAR_AND     = '&',  /* 02/06 */
+        VTE_SEQ_INTERMEDIATE_CHAR_SQUOTE  = '\'', /* 02/07 */
+        VTE_SEQ_INTERMEDIATE_CHAR_POPEN   = '(',  /* 02/08 */
+        VTE_SEQ_INTERMEDIATE_CHAR_PCLOSE  = ')',  /* 02/09 */
+        VTE_SEQ_INTERMEDIATE_CHAR_MULT    = '*',  /* 02/10 */
+        VTE_SEQ_INTERMEDIATE_CHAR_PLUS    = '+',  /* 02/11 */
+        VTE_SEQ_INTERMEDIATE_CHAR_COMMA   = ',',  /* 02/12 */
+        VTE_SEQ_INTERMEDIATE_CHAR_MINUS   = '-',  /* 02/13 */
+        VTE_SEQ_INTERMEDIATE_CHAR_DOT     = '.',  /* 02/14 */
+        VTE_SEQ_INTERMEDIATE_CHAR_SLASH   = '/',  /* 02/15 */
 };
 
 enum {
-        /* these must be kept compatible to (1U << (ch - 0x20)) */
-
-        VTE_SEQ_FLAG_SPACE              = (1U <<  0),        /* char:   */
-        VTE_SEQ_FLAG_BANG               = (1U <<  1),        /* char: ! */
-        VTE_SEQ_FLAG_DQUOTE             = (1U <<  2),        /* char: " */
-        VTE_SEQ_FLAG_HASH               = (1U <<  3),        /* char: # */
-        VTE_SEQ_FLAG_CASH               = (1U <<  4),        /* char: $ */
-        VTE_SEQ_FLAG_PERCENT            = (1U <<  5),        /* char: % */
-        VTE_SEQ_FLAG_AND                = (1U <<  6),        /* char: & */
-        VTE_SEQ_FLAG_SQUOTE             = (1U <<  7),        /* char: ' */
-        VTE_SEQ_FLAG_POPEN              = (1U <<  8),        /* char: ( */
-        VTE_SEQ_FLAG_PCLOSE             = (1U <<  9),        /* char: ) */
-        VTE_SEQ_FLAG_MULT               = (1U << 10),        /* char: * */
-        VTE_SEQ_FLAG_PLUS               = (1U << 11),        /* char: + */
-        VTE_SEQ_FLAG_COMMA              = (1U << 12),        /* char: , */
-        VTE_SEQ_FLAG_MINUS              = (1U << 13),        /* char: - */
-        VTE_SEQ_FLAG_DOT                = (1U << 14),        /* char: . */
-        VTE_SEQ_FLAG_SLASH              = (1U << 15),        /* char: / */
-
-        /* 16-25 is reserved for numbers; unused */
-
-        /* COLON is reserved            = (1U << 26),           char: : */
-        /* SEMICOLON is reserved        = (1U << 27),           char: ; */
-        VTE_SEQ_FLAG_LT                 = (1U << 28),        /* char: < */
-        VTE_SEQ_FLAG_EQUAL              = (1U << 29),        /* char: = */
-        VTE_SEQ_FLAG_GT                 = (1U << 30),        /* char: > */
-        VTE_SEQ_FLAG_WHAT               = (1U << 31),        /* char: ? */
+        VTE_SEQ_PARAMETER_CHAR_NONE  = 0,
+
+        /* Numbers; not used         *  03/00..03/09 */
+        /* COLON is reserved         = ':'   * 03/10 */
+        /* SEMICOLON is reserved     = ';'   * 03/11 */
+        VTE_SEQ_PARAMETER_CHAR_LT    = '<', /* 03/12 */
+        VTE_SEQ_PARAMETER_CHAR_EQUAL = '=', /* 03/13 */
+        VTE_SEQ_PARAMETER_CHAR_GT    = '>', /* 03/14 */
+        VTE_SEQ_PARAMETER_CHAR_WHAT  = '?'  /* 03/15 */
+};
+
+#define VTE_SEQ_MAKE_INTERMEDIATE(c) ((c) - ' ' + 1)
+
+enum {
+        VTE_SEQ_INTERMEDIATE_NONE      = 0,
+
+        VTE_SEQ_INTERMEDIATE_SPACE     = VTE_SEQ_MAKE_INTERMEDIATE(VTE_SEQ_INTERMEDIATE_CHAR_SPACE  ),
+        VTE_SEQ_INTERMEDIATE_BANG      = VTE_SEQ_MAKE_INTERMEDIATE(VTE_SEQ_INTERMEDIATE_CHAR_BANG   ),
+        VTE_SEQ_INTERMEDIATE_DQUOTE    = VTE_SEQ_MAKE_INTERMEDIATE(VTE_SEQ_INTERMEDIATE_CHAR_DQUOTE ),
+        VTE_SEQ_INTERMEDIATE_HASH      = VTE_SEQ_MAKE_INTERMEDIATE(VTE_SEQ_INTERMEDIATE_CHAR_HASH   ),
+        VTE_SEQ_INTERMEDIATE_CASH      = VTE_SEQ_MAKE_INTERMEDIATE(VTE_SEQ_INTERMEDIATE_CHAR_CASH   ),
+        VTE_SEQ_INTERMEDIATE_PERCENT   = VTE_SEQ_MAKE_INTERMEDIATE(VTE_SEQ_INTERMEDIATE_CHAR_PERCENT),
+        VTE_SEQ_INTERMEDIATE_AND       = VTE_SEQ_MAKE_INTERMEDIATE(VTE_SEQ_INTERMEDIATE_CHAR_AND    ),
+        VTE_SEQ_INTERMEDIATE_SQUOTE    = VTE_SEQ_MAKE_INTERMEDIATE(VTE_SEQ_INTERMEDIATE_CHAR_SQUOTE ),
+        VTE_SEQ_INTERMEDIATE_POPEN     = VTE_SEQ_MAKE_INTERMEDIATE(VTE_SEQ_INTERMEDIATE_CHAR_POPEN  ),
+        VTE_SEQ_INTERMEDIATE_PCLOSE    = VTE_SEQ_MAKE_INTERMEDIATE(VTE_SEQ_INTERMEDIATE_CHAR_PCLOSE ),
+        VTE_SEQ_INTERMEDIATE_MULT      = VTE_SEQ_MAKE_INTERMEDIATE(VTE_SEQ_INTERMEDIATE_CHAR_MULT   ),
+        VTE_SEQ_INTERMEDIATE_PLUS      = VTE_SEQ_MAKE_INTERMEDIATE(VTE_SEQ_INTERMEDIATE_CHAR_PLUS   ),
+        VTE_SEQ_INTERMEDIATE_COMMA     = VTE_SEQ_MAKE_INTERMEDIATE(VTE_SEQ_INTERMEDIATE_CHAR_COMMA  ),
+        VTE_SEQ_INTERMEDIATE_MINUS     = VTE_SEQ_MAKE_INTERMEDIATE(VTE_SEQ_INTERMEDIATE_CHAR_MINUS  ),
+        VTE_SEQ_INTERMEDIATE_DOT       = VTE_SEQ_MAKE_INTERMEDIATE(VTE_SEQ_INTERMEDIATE_CHAR_DOT    ),
+        VTE_SEQ_INTERMEDIATE_SLASH     = VTE_SEQ_MAKE_INTERMEDIATE(VTE_SEQ_INTERMEDIATE_CHAR_SLASH  ),
+};
+
+#define VTE_SEQ_MAKE_PARAMETER(c) ('?' - (c) + 1)
+
+enum {
+        VTE_SEQ_PARAMETER_NONE  = 0,
+
+        VTE_SEQ_PARAMETER_LT    = VTE_SEQ_MAKE_PARAMETER(VTE_SEQ_PARAMETER_CHAR_LT   ),
+        VTE_SEQ_PARAMETER_EQUAL = VTE_SEQ_MAKE_PARAMETER(VTE_SEQ_PARAMETER_CHAR_EQUAL),
+        VTE_SEQ_PARAMETER_GT    = VTE_SEQ_MAKE_PARAMETER(VTE_SEQ_PARAMETER_CHAR_GT   ),
+        VTE_SEQ_PARAMETER_WHAT  = VTE_SEQ_MAKE_PARAMETER(VTE_SEQ_PARAMETER_CHAR_WHAT ),
 };
 
 enum {
@@ -184,11 +191,17 @@ enum {
         VTE_OSC_N
 };
 
+#define VTE_CHARSET_CHARSET_MASK   ((1U << 16) - 1U)
+#define VTE_CHARSET_SLOT_OFFSET    (16)
+#define VTE_CHARSET_GET_CHARSET(c) ((c) & VTE_CHARSET_CHARSET_MASK)
+#define VTE_CHARSET_GET_SLOT(c)    ((c) >> VTE_CHARSET_SLOT_OFFSET)
+
 struct vte_seq {
         unsigned int type;
         unsigned int command;
         uint32_t terminator;
         unsigned int intermediates;
+        unsigned int n_intermediates;
         unsigned int charset;
         unsigned int n_args;
         unsigned int n_final_args;
diff --git a/src/vteseq.cc b/src/vteseq.cc
index 84fd340..e361583 100644
--- a/src/vteseq.cc
+++ b/src/vteseq.cc
@@ -2627,6 +2627,21 @@ VteTerminalPrivate::DECPCTERM(vte::parser::Sequence const& seq)
 }
 
 void
+VteTerminalPrivate::DECPCTERM_OR_XTERM_RPM(vte::parser::Sequence const& seq)
+{
+        /*
+         * There's a conflict between DECPCTERM and XTERM-RPM.
+         * XTERM-RPM takes a single argument, DECPCTERM takes 2.
+         * Note that since both admit default values (which may be
+         * omitted at the end of the sequence), this only an approximation.
+         */
+        if (seq.size_final() <= 1)
+                XTERM_RPM(seq);
+        else
+                DECPCTERM(seq);
+}
+
+void
 VteTerminalPrivate::DECPFK(vte::parser::Sequence const& seq)
 {
         /*
@@ -2990,8 +3005,11 @@ VteTerminalPrivate::DECRQTSR(vte::parser::Sequence const& seq)
         /*
          * DECRQTSR - request-terminal-state-report
          *
-         * Probably not worth implementing.
+         * References: VT525
          */
+
+        if (seq.collect1(0) != 1)
+                return;
 }
 
 void
@@ -4088,22 +4106,7 @@ VteTerminalPrivate::GnDm(vte::parser::Sequence const& seq)
                 break;
         }
 
-        unsigned int slot = 0;
-        if (seq.intermediates() & VTE_SEQ_FLAG_POPEN)
-                slot = 0;
-        else if (seq.intermediates() & VTE_SEQ_FLAG_PCLOSE)
-                slot = 1;
-        else if (seq.intermediates() & VTE_SEQ_FLAG_MULT)
-                slot = 2;
-        else if (seq.intermediates() & VTE_SEQ_FLAG_PLUS)
-                slot = 3;
-        else if (seq.intermediates() & VTE_SEQ_FLAG_MINUS)
-                slot = 1;
-        else if (seq.intermediates() & VTE_SEQ_FLAG_DOT)
-                slot = 2;
-        else if (seq.intermediates() & VTE_SEQ_FLAG_SLASH)
-                slot = 3;
-
+        unsigned int slot = seq.slot();
         if (slot >= G_N_ELEMENTS(m_character_replacements))
                 return;
 
@@ -4845,6 +4848,20 @@ VteTerminalPrivate::SD(vte::parser::Sequence const& seq)
 }
 
 void
+VteTerminalPrivate::SD_OR_XTERM_IHMT(vte::parser::Sequence const& seq)
+{
+        /*
+         * There's a conflict between SD and XTERM IHMT that we
+         * have to resolve by checking the parameter count.
+         * XTERM_IHMT needs exactly 5 arguments, SD takes 0 or 1.
+         */
+        if (seq.size_final() <= 1)
+                SD(seq);
+        else
+                XTERM_IHMT(seq);
+}
+
+void
 VteTerminalPrivate::SGR(vte::parser::Sequence const& seq)
 {
         /*


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]