[vte] parser: Import new parser



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

    parser: Import new parser

 doc/reference/Makefile.am |    3 +
 src/Makefile.am           |   73 +-
 src/debug.cc              |    3 +-
 src/debug.h               |   27 +-
 src/interpret-old.cc      |  302 +++++
 src/interpret.cc          |  281 ++---
 src/iso2022.h             |    1 -
 src/matcher.cc            |    2 +-
 src/parser-cmd.hh         |  193 +++
 src/parser-glue.hh        |  148 ++
 src/parser-test.cc        |  539 ++++++++
 src/parser.cc             |  115 +-
 src/parser.hh             |  218 +---
 src/table.cc              |    4 +-
 src/table.hh              |    1 +
 src/vte.cc                |  290 ++---
 src/vteinternal.hh        |  140 +--
 src/vteseq-str.hh         |  156 +++
 src/vteseq.cc             | 3257 ++++++++++++++++++++++++++++++++++++++++++---
 19 files changed, 4879 insertions(+), 874 deletions(-)
---
diff --git a/doc/reference/Makefile.am b/doc/reference/Makefile.am
index 7126f18..fe3e381 100644
--- a/doc/reference/Makefile.am
+++ b/doc/reference/Makefile.am
@@ -85,6 +85,9 @@ IGNORE_HFILES = \
        keymap.h \
        marshal.h \
        matcher.hh \
+       parser.hh \
+       parser-cmd.hh \
+       parser-glue.hh \
        ring.h \
        stamp-vtetypebuiltins.h \
        table.hh \
diff --git a/src/Makefile.am b/src/Makefile.am
index e26d9e5..ef8e44b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -48,7 +48,6 @@ libvte_@VTE_API_MAJOR_VERSION@_@VTE_API_MINOR_VERSION@_la_SOURCES = \
        attr.hh \
        buffer.h \
        caps.hh \
-       caps-list.hh \
        color-triple.hh \
        debug.cc \
        debug.h \
@@ -56,15 +55,15 @@ libvte_@VTE_API_MAJOR_VERSION@_@VTE_API_MINOR_VERSION@_la_SOURCES = \
        iso2022.h \
        keymap.cc \
        keymap.h \
-       matcher.cc \
-       matcher.hh \
+       parser.cc \
+       parser.hh \
+       parser-cmd.hh \
+       parser-glue.hh \
        pty.cc \
        reaper.cc \
        reaper.hh \
        ring.cc \
        ring.h \
-       table.cc \
-       table.hh \
        vte.cc \
        vteaccess.cc \
        vteaccess.h \
@@ -173,7 +172,7 @@ vteresources.cc: vte.gresource.xml Makefile $(shell $(GLIB_COMPILE_RESOURCES) --
 
 # Misc unit tests and utilities
 
-noinst_PROGRAMS += interpret slowcat
+noinst_PROGRAMS += interpret interpret-old slowcat test-parser
 noinst_SCRIPTS = decset osc window
 EXTRA_DIST += $(noinst_SCRIPTS)
 
@@ -194,6 +193,7 @@ dist_check_SCRIPTS = \
        $(NULL)
 
 TESTS = \
+       test-parser \
        reaper \
        test-vtetypes \
        vteconv \
@@ -230,15 +230,14 @@ reflect_vte_LDADD = libvte-$(VTE_API_VERSION).la $(VTE_LIBS)
 interpret_SOURCES = \
        buffer.h \
        caps.hh \
-       caps-list.hh \
        debug.cc \
        debug.h \
        iso2022.cc \
        iso2022.h \
-       matcher.cc \
-       matcher.hh \
-       table.cc \
-       table.hh \
+       parser.cc \
+       parser.hh \
+       parser-cmd.hh \
+       parser-glue.hh \
        vteconv.cc \
        vteconv.h \
        interpret.cc
@@ -262,6 +261,40 @@ interpret_LDADD = \
        $(GLIB_LIBS) \
        $(GOBJECT_LIBS)
 
+interpret_old_SOURCES = \
+       buffer.h \
+       caps.hh \
+       debug.cc \
+       debug.h \
+       iso2022.cc \
+       iso2022.h \
+       matcher.cc \
+       matcher.hh \
+       table.cc \
+       table.hh \
+       vteconv.cc \
+       vteconv.h \
+       interpret-old.cc
+interpret_old_CPPFLAGS = \
+       -DINTERPRET_OLD_MAIN \
+       -DVTE_API_VERSION=\"$(VTE_API_VERSION)\" \
+       -I$(builddir) \
+       -I$(srcdir) \
+       $(AM_CPPFLAGS)
+interpret_old_CFLAGS = \
+       $(GLIB_CFLAGS) \
+       $(GOBJECT_CFLAGS) \
+       $(GTK_CFLAGS) \
+       $(AM_CFLAGS)
+interpret_old_CXXFLAGS = \
+       $(GLIB_CFLAGS) \
+       $(GOBJECT_CFLAGS) \
+       $(GTK_CFLAGS) \
+       $(AM_CXXFLAGS)
+interpret_old_LDADD = \
+       $(GLIB_LIBS) \
+       $(GOBJECT_LIBS)
+
 slowcat_SOURCES = \
        slowcat.c \
        $(NULL)
@@ -269,6 +302,24 @@ slowcat_CPPFLAGS = -I$(builddir) -I$(srcdir) $(AM_CPPFLAGS)
 slowcat_CFLAGS = $(GLIB_CFLAGS) $(AM_CFLAGS)
 slowcat_LDADD = $(GLIB_LIBS)
 
+test_parser_SOURCES = \
+       parser-test.cc \
+       parser.cc \
+       parser.hh \
+       parser-cmd.hh \
+       parser-glue.hh \
+       $(NULL)
+test_parser_CPPFLAGS = \
+       -I$(builddir) \
+       -I$(srcdir) \
+       $(AM_CPPFLAGS)
+test_parser_CXXFLAGS = \
+       $(VTE_CFLAGS) \
+       $(AM_CXXFLAGS)
+test_parser_LDADD = \
+       $(VTE_LIBS) \
+       $(NULL)
+
 test_vtetypes_SOURCES = \
        vtetypes.cc \
        vtetypes.hh \
diff --git a/src/debug.cc b/src/debug.cc
index 132e805..1352f8b 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -35,7 +35,7 @@ _vte_debug_init(void)
     { "adj",          VTE_DEBUG_ADJ          },
     { "updates",      VTE_DEBUG_UPDATES      },
     { "events",       VTE_DEBUG_EVENTS       },
-    { "parse",        VTE_DEBUG_PARSE        },
+    { "parser",       VTE_DEBUG_PARSER       },
     { "signals",      VTE_DEBUG_SIGNALS      },
     { "selection",    VTE_DEBUG_SELECTION    },
     { "substitution", VTE_DEBUG_SUBSTITUTION },
@@ -44,7 +44,6 @@ _vte_debug_init(void)
     { "cursor",       VTE_DEBUG_CURSOR       },
     { "keyboard",     VTE_DEBUG_KEYBOARD     },
     { "lifecycle",    VTE_DEBUG_LIFECYCLE    },
-    { "matcher",      VTE_DEBUG_MATCHER      },
     { "work",         VTE_DEBUG_WORK         },
     { "cells",        VTE_DEBUG_CELLS        },
     { "timeout",      VTE_DEBUG_TIMEOUT      },
diff --git a/src/debug.h b/src/debug.h
index 260d6dc..e156477 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -38,7 +38,7 @@ G_BEGIN_DECLS
 
 typedef enum {
        VTE_DEBUG_MISC          = 1 << 0,
-       VTE_DEBUG_PARSE         = 1 << 1,
+       VTE_DEBUG_PARSER        = 1 << 1,
        VTE_DEBUG_IO            = 1 << 2,
        VTE_DEBUG_UPDATES       = 1 << 3,
        VTE_DEBUG_EVENTS        = 1 << 4,
@@ -50,19 +50,18 @@ typedef enum {
        VTE_DEBUG_CURSOR        = 1 << 10,
        VTE_DEBUG_KEYBOARD      = 1 << 11,
        VTE_DEBUG_LIFECYCLE     = 1 << 12,
-       VTE_DEBUG_MATCHER       = 1 << 13,
-       VTE_DEBUG_WORK          = 1 << 14,
-       VTE_DEBUG_CELLS         = 1 << 15,
-       VTE_DEBUG_TIMEOUT       = 1 << 16,
-       VTE_DEBUG_DRAW          = 1 << 17,
-       VTE_DEBUG_ALLY          = 1 << 18,
-       VTE_DEBUG_ADJ           = 1 << 19,
-       VTE_DEBUG_PANGOCAIRO    = 1 << 20,
-       VTE_DEBUG_WIDGET_SIZE   = 1 << 21,
-        VTE_DEBUG_STYLE         = 1 << 22,
-       VTE_DEBUG_RESIZE        = 1 << 23,
-        VTE_DEBUG_REGEX         = 1 << 24,
-        VTE_DEBUG_HYPERLINK     = 1 << 25,
+       VTE_DEBUG_WORK          = 1 << 13,
+       VTE_DEBUG_CELLS         = 1 << 14,
+       VTE_DEBUG_TIMEOUT       = 1 << 15,
+       VTE_DEBUG_DRAW          = 1 << 16,
+       VTE_DEBUG_ALLY          = 1 << 17,
+       VTE_DEBUG_ADJ           = 1 << 18,
+       VTE_DEBUG_PANGOCAIRO    = 1 << 19,
+       VTE_DEBUG_WIDGET_SIZE   = 1 << 20,
+        VTE_DEBUG_STYLE         = 1 << 21,
+       VTE_DEBUG_RESIZE        = 1 << 22,
+        VTE_DEBUG_REGEX         = 1 << 23,
+        VTE_DEBUG_HYPERLINK     = 1 << 24,
 } VteDebugFlags;
 
 void _vte_debug_init(void);
diff --git a/src/interpret-old.cc b/src/interpret-old.cc
new file mode 100644
index 0000000..cf1f893
--- /dev/null
+++ b/src/interpret-old.cc
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2001,2002,2003 Red Hat, Inc.
+ *
+ * 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 2.1 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 Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <config.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <locale.h>
+#include "caps.hh"
+#include "debug.h"
+#include "iso2022.h"
+#include "matcher.hh"
+
+static bool quiet = false;
+
+static void
+print_array(GValueArray* array, bool subvalues)
+{
+        GValue *value;
+        if (array != NULL) {
+                if (!subvalues && array->n_values > 0)
+                        g_print(" ");
+                for (unsigned int i = 0; i < array->n_values; i++) {
+                        value = g_value_array_get_nth(array, i);
+                        if (i > 0) {
+                                g_print(subvalues? ":" : ";");
+                        }
+                        if (G_VALUE_HOLDS_LONG(value)) {
+                                g_print("%ld", g_value_get_long(value));
+                        } else
+                        if (G_VALUE_HOLDS_STRING(value)) {
+                                g_print("\"%s\"", g_value_get_string(value));
+                        } else
+                        if (G_VALUE_HOLDS_POINTER(value)) {
+                                g_print("\"%ls\"",
+                                        (wchar_t*) g_value_get_pointer(value));
+                        } else
+                        if (G_VALUE_HOLDS_BOXED(value)) {
+                                if (!subvalues)
+                                        print_array((GValueArray *)g_value_get_boxed(value), true);
+                                else
+                                        g_print("subsubvalues!?");
+                        }
+                }
+        }
+}
+
+namespace vte { namespace parser { struct Params { GValueArray *m_values; }; } }
+
+enum {
+#define SEQUENCE_HANDLER(name) \
+        HANDLER_##name,
+#include "vteseq-list.hh"
+#undef SEQUENCE_HANDLER
+        _HANDLER_N
+};
+
+static char const* handler_to_string(int handler_id)
+{
+        static char const* handlers[_HANDLER_N] = {
+#include "vteseq-str.hh"
+        };
+
+        if (G_UNLIKELY(handler_id < 0 || handler_id >= _HANDLER_N))
+                return "XXXWTF";
+        else
+                return handlers[handler_id];
+}
+
+static void print_seq(int handler_id,
+                      const char *fname,
+                      vte::parser::Params const& params)
+{
+        g_print("%s", handler_to_string(handler_id));
+        print_array(params.m_values, false);
+        g_print("\n");
+        //        g_print("  =: %s\n", fname);
+}
+
+class VteTerminalPrivate {
+public:
+#define SEQUENCE_HANDLER(name) \
+       inline void seq_ ## name (vte::parser::Params const& params) { \
+                if (!quiet) { \
+                        print_seq(HANDLER_##name, __func__, params);     \
+                } \
+        }
+#include "vteseq-list.hh"
+#undef SEQUENCE_HANDLER
+};
+
+vte_matcher_entry_t const*
+_vte_get_matcher_entries(unsigned int* n_entries)
+{
+#include "caps-list.hh"
+        *n_entries = G_N_ELEMENTS (entries);
+        return entries;
+}
+
+int
+main(int argc, char **argv)
+{
+       struct _vte_matcher *matcher = NULL;
+       GArray *array;
+       int infile;
+       struct _vte_iso2022_state *subst;
+
+        setlocale(LC_ALL, "");
+
+       _vte_debug_init();
+
+        if (argc < 1) {
+                g_print("usage: %s [file] [--quiet]\n", argv[0]);
+               return 1;
+       }
+
+        if ((argc > 1) && (strcmp(argv[1], "-") != 0)) {
+                infile = open (argv[1], O_RDONLY);
+               if (infile == -1) {
+                        g_print("error opening %s: %s\n", argv[1],
+                               strerror(errno));
+                       exit(1);
+               }
+       } else {
+               infile = 1;
+       }
+
+        if (argc > 2)
+                quiet = g_str_equal(argv[2], "--quiet") || g_str_equal(argv[2], "-q");
+
+       g_type_init();
+
+       array = g_array_new(FALSE, FALSE, sizeof(gunichar));
+
+        matcher = _vte_matcher_new();
+
+        subst = _vte_iso2022_state_new(NULL);
+
+        VteTerminalPrivate terminal{};
+        gsize n_seq = 0;
+        gsize n_chars = 0;
+        gsize n_discarded = 0;
+
+        gsize start = 0;
+
+        gsize buf_size = 1024*1024;
+        guchar* buf = g_new0(guchar, buf_size);
+       for (;;) {
+               auto l = read (infile, buf, buf_size);
+               if (!l)
+                       break;
+               if (l == -1) {
+                       if (errno == EAGAIN)
+                               continue;
+                       break;
+               }
+               _vte_iso2022_process(subst, buf, (unsigned int) l, array);
+
+                gunichar* wbuf = &g_array_index(array, gunichar, 0);
+                gsize wcount = array->len;
+
+                bool leftovers = false;
+
+                while (start < wcount && !leftovers) {
+                        const gunichar *next;
+                        vte::parser::Params params{nullptr};
+                        sequence_handler_t handler = nullptr;
+                        auto match_result = _vte_matcher_match(matcher,
+                                                               &wbuf[start],
+                                                               wcount - start,
+                                                               &handler,
+                                                               &next,
+                                                               &params.m_values);
+                        switch (match_result) {
+                        case VTE_MATCHER_RESULT_MATCH: {
+                                (terminal.*handler)(params);
+                                if (params.m_values != nullptr)
+                                        _vte_matcher_free_params_array(matcher, params.m_values);
+
+                                /* Skip over the proper number of unicode chars. */
+                                start = (next - wbuf);
+                                n_seq++;
+                                break;
+                        }
+                        case VTE_MATCHER_RESULT_NO_MATCH: {
+                                auto c = wbuf[start];
+                                /* If it's a control character, permute the order, per
+                                 * vttest. */
+                                if ((c != *next) &&
+                                    ((*next & 0x1f) == *next) &&
+                                    //FIXMEchpe what about C1 controls
+                                    (gssize(start + 1) < next - wbuf)) {
+                                        const gunichar *tnext = nullptr;
+                                        gunichar ctrl;
+                                        /* We don't want to permute it if it's another
+                                         * control sequence, so check if it is. */
+                                        sequence_handler_t thandler;
+                                        _vte_matcher_match(matcher,
+                                                           next,
+                                                           wcount - (next - wbuf),
+                                                           &thandler,
+                                                           &tnext,
+                                                           nullptr);
+                                        /* We only do this for non-control-sequence
+                                         * characters and random garbage. */
+                                        if (tnext == next + 1) {
+                                                /* Save the control character. */
+                                                ctrl = *next;
+                                                /* Move everything before it up a
+                                                 * slot.  */
+                                                // FIXMEchpe memmove!
+                                                gsize i;
+                                                for (i = next - wbuf; i > start; i--) {
+                                                        wbuf[i] = wbuf[i - 1];
+                                                }
+                                                /* Move the control character to the
+                                                 * front. */
+                                                wbuf[i] = ctrl;
+                                                goto next_match;
+                                        }
+                                }
+                                n_chars++;
+                                if (!quiet) {
+                                        char cbuf[7];
+                                        cbuf[g_unichar_to_utf8(c, cbuf)] = 0;
+                                        g_print("%s U+%04X [%s]\n", "GRAPHIC",
+                                                c,
+                                                g_unichar_isprint(c) ? cbuf : "�");
+                                }
+                                start++;
+                                break;
+                        }
+                        case VTE_MATCHER_RESULT_PARTIAL: {
+                                if (wbuf + wcount > next) {
+                                        if (!quiet)
+                                                g_print("Invalid control "
+                                                        "sequence, discarding %ld "
+                                                        "characters.\n",
+                                                        (long)(next - (wbuf + start)));
+                                        /* Discard. */
+                                        start = next - wbuf + 1;
+                                        n_discarded += next - &wbuf[start];
+                                } else {
+                                        /* Pause processing here and wait for more
+                                         * data before continuing. */
+                                        leftovers = true;
+                                }
+                                break;
+                        }
+                        }
+
+               }
+
+        next_match:
+                if (start < wcount) {
+                        g_array_remove_range(array, 0, start);
+                        start = wcount - start;
+                } else {
+                        g_array_set_size(array, 0);
+                        start = 0;
+                }
+       }
+        if (!quiet)
+                g_printerr("End of data.\n");
+
+        g_printerr ("Characters inserted:  %" G_GSIZE_FORMAT "\n"
+                    "Sequences recognised: %" G_GSIZE_FORMAT "\n"
+                    "Bytes discarded:      %" G_GSIZE_FORMAT "\n",
+                    n_chars, n_seq, n_discarded);
+
+       close (infile);
+
+       _vte_iso2022_state_free(subst);
+       g_array_free(array, TRUE);
+       _vte_matcher_free(matcher);
+        g_free(buf);
+       return 0;
+}
diff --git a/src/interpret.cc b/src/interpret.cc
index dc66836..3c4fd64 100644
--- a/src/interpret.cc
+++ b/src/interpret.cc
@@ -33,7 +33,8 @@
 #include "caps.hh"
 #include "debug.h"
 #include "iso2022.h"
-#include "matcher.hh"
+#include "parser.hh"
+#include "assert.h"
 
 static bool quiet = false;
 
@@ -66,207 +67,165 @@ print_array(GValueArray* array)
         }
 }
 
-namespace vte { namespace parser { struct Params { GValueArray *m_values; }; } }
+static char const*
+seq_to_str(unsigned int type)
+{
+        switch (type) {
+        case VTE_SEQ_NONE: return "NONE";
+        case VTE_SEQ_IGNORE: return "IGNORE";
+        case VTE_SEQ_GRAPHIC: return "GRAPHIC";
+        case VTE_SEQ_CONTROL: return "CONTROL";
+        case VTE_SEQ_ESCAPE: return "ESCAPE";
+        case VTE_SEQ_CSI: return "CSI";
+        case VTE_SEQ_DCS: return "DCS";
+        case VTE_SEQ_OSC: return "OSC";
+        default:
+                assert(false);
+        }
+}
 
-class VteTerminalPrivate {
-public:
-#define SEQUENCE_HANDLER(name) \
-       inline void seq_ ## name (vte::parser::Params const& params) { \
-                if (!quiet) { \
-                        g_print (G_STRINGIFY(name)); \
-                        print_array(params.m_values); \
-                        g_print("\n"); \
-                } \
+static char const*
+cmd_to_str(unsigned int command)
+{
+        switch (command) {
+#define _VTE_CMD(cmd) case VTE_CMD_##cmd: return #cmd;
+#include "parser-cmd.hh"
+#undef _VTE_CMD
+        default:
+                static char buf[32];
+                snprintf(buf, sizeof(buf), "UNKOWN(%u)", command);
+                return buf;
         }
-#include "vteseq-list.hh"
-#undef SEQUENCE_HANDLER
-};
+}
 
-vte_matcher_entry_t const*
-_vte_get_matcher_entries(unsigned int* n_entries)
+static  void print_seq(const struct vte_seq *seq)
 {
-#include "caps-list.hh"
-        *n_entries = G_N_ELEMENTS (entries);
-        return entries;
+        auto c = seq->terminator;
+        if (seq->command == VTE_CMD_GRAPHIC) {
+                char buf[7];
+                buf[g_unichar_to_utf8(c, buf)] = 0;
+                g_print("%s U+%04X [%s]\n", cmd_to_str(seq->command),
+                        c,
+                        g_unichar_isprint(c) ? buf : "�");
+        } else {
+                g_print("%s", cmd_to_str(seq->command));
+                if (seq->n_args) {
+                        g_print(" ");
+                        for (unsigned int i = 0; i < seq->n_args; i++) {
+                                if (i > 0)
+                                        g_print(";");
+                        g_print("%d", seq->args[i]);
+                        }
+                }
+                g_print("\n");
+        }
 }
 
 int
 main(int argc, char **argv)
 {
-       struct _vte_matcher *matcher = NULL;
-       GArray *array;
-       unsigned char buf[4096];
-       int infile;
-       struct _vte_iso2022_state *subst;
+        GArray *array;
+        int infile;
+        struct _vte_iso2022_state *subst;
 
         setlocale(LC_ALL, "");
 
-       _vte_debug_init();
+        _vte_debug_init();
 
         if (argc < 1) {
                 g_print("usage: %s [file] [--quiet]\n", argv[0]);
-               return 1;
-       }
+                return 1;
+        }
 
         if ((argc > 1) && (strcmp(argv[1], "-") != 0)) {
                 infile = open (argv[1], O_RDONLY);
-               if (infile == -1) {
+                if (infile == -1) {
                         g_print("error opening %s: %s\n", argv[1],
-                               strerror(errno));
-                       exit(1);
-               }
-       } else {
-               infile = 1;
-       }
+                                strerror(errno));
+                        exit(1);
+                }
+        } else {
+                infile = 1;
+        }
 
         if (argc > 2)
                 quiet = g_str_equal(argv[2], "--quiet") || g_str_equal(argv[2], "-q");
 
-       g_type_init();
+        g_type_init();
 
-       array = g_array_new(FALSE, FALSE, sizeof(gunichar));
+        array = g_array_new(FALSE, FALSE, sizeof(gunichar));
 
-        matcher = _vte_matcher_new();
+        struct vte_parser *parser;
+        if (vte_parser_new(&parser) != 0)
+                return 1;
 
         subst = _vte_iso2022_state_new(NULL);
 
-        VteTerminalPrivate terminal{};
-        gsize n_seq = 0;
-        gsize n_chars = 0;
-        gsize n_discarded = 0;
+        gsize buf_size = 1024*1024;
+        guchar* buf = g_new0(guchar, buf_size);
 
-        gsize start = 0;
+        gsize* seq_stats = g_new0(gsize, VTE_SEQ_N);
+        gsize* cmd_stats = g_new0(gsize, VTE_CMD_N);
 
-       for (;;) {
-               auto l = read (infile, buf, sizeof (buf));
-               if (!l)
-                       break;
-               if (l == -1) {
-                       if (errno == EAGAIN)
-                               continue;
-                       break;
-               }
-               _vte_iso2022_process(subst, buf, (unsigned int) l, array);
+        for (;;) {
+                auto l = read (infile, buf, buf_size);
+                if (!l)
+                        break;
+                if (l == -1) {
+                        if (errno == EAGAIN)
+                                continue;
+                        break;
+                }
+                _vte_iso2022_process(subst, buf, (unsigned int) l, array);
 
                 gunichar* wbuf = &g_array_index(array, gunichar, 0);
                 gsize wcount = array->len;
 
-                bool leftovers = false;
+                struct vte_seq *seq;
+                for (gsize i = 0; i < wcount; i++) {
+                        auto ret = vte_parser_feed(parser,
+                                                   &seq,
+                                                   wbuf[i]);
+                        if (ret < 0) {
+                                if (!quiet)
+                                        g_print("Parser error\n");
+                                goto done;
+                        }
 
-                while (start < wcount && !leftovers) {
-                        const gunichar *next;
-                        vte::parser::Params params{nullptr};
-                        sequence_handler_t handler = nullptr;
-                        auto match_result = _vte_matcher_match(matcher,
-                                                               &wbuf[start],
-                                                               wcount - start,
-                                                               &handler,
-                                                               &next,
-                                                               &params.m_values);
-                        switch (match_result) {
-                        case VTE_MATCHER_RESULT_MATCH: {
-                                (terminal.*handler)(params);
-                                if (params.m_values != nullptr)
-                                        _vte_matcher_free_params_array(matcher, params.m_values);
+                        seq_stats[ret]++;
+                        if (ret != VTE_SEQ_NONE) {
+                                cmd_stats[seq->command]++;
 
-                                /* Skip over the proper number of unicode chars. */
-                                start = (next - wbuf);
-                                n_seq++;
-                                break;
-                        }
-                        case VTE_MATCHER_RESULT_NO_MATCH: {
-                                auto c = wbuf[start];
-                                /* If it's a control character, permute the order, per
-                                 * vttest. */
-                                if ((c != *next) &&
-                                    ((*next & 0x1f) == *next) &&
-                                    //FIXMEchpe what about C1 controls
-                                    (gssize(start + 1) < next - wbuf)) {
-                                        const gunichar *tnext = nullptr;
-                                        gunichar ctrl;
-                                        /* We don't want to permute it if it's another
-                                         * control sequence, so check if it is. */
-                                        sequence_handler_t thandler;
-                                        _vte_matcher_match(matcher,
-                                                           next,
-                                                           wcount - (next - wbuf),
-                                                           &thandler,
-                                                           &tnext,
-                                                           nullptr);
-                                        /* We only do this for non-control-sequence
-                                         * characters and random garbage. */
-                                        if (tnext == next + 1) {
-                                                /* Save the control character. */
-                                                ctrl = *next;
-                                                /* Move everything before it up a
-                                                 * slot.  */
-                                                // FIXMEchpe memmove!
-                                                gsize i;
-                                                for (i = next - wbuf; i > start; i--) {
-                                                        wbuf[i] = wbuf[i - 1];
-                                                }
-                                                /* Move the control character to the
-                                                 * front. */
-                                                wbuf[i] = ctrl;
-                                                goto next_match;
-                                        }
-                                }
-                                n_chars++;
-                                if (!quiet) {
-                                        if (c < 32) {
-                                                g_print("`^%c'\n", c + 64);
-                                        } else
-                                                if (c < 127) {
-                                                        g_print("`%c'\n", c);
-                                                } else {
-                                                        g_print("`0x%x'\n", c);
-                                                }
-                                }
-                                start++;
-                                break;
-                        }
-                        case VTE_MATCHER_RESULT_PARTIAL: {
-                                if (wbuf + wcount > next) {
-                                        if (!quiet)
-                                                g_print("Invalid control "
-                                                        "sequence, discarding %ld "
-                                                        "characters.\n",
-                                                        (long)(next - (wbuf + start)));
-                                        /* Discard. */
-                                        start = next - wbuf + 1;
-                                        n_discarded += next - &wbuf[start];
-                                } else {
-                                        /* Pause processing here and wait for more
-                                         * data before continuing. */
-                                        leftovers = true;
-                                }
-                                break;
-                        }
+                                if (!quiet)
+                                        print_seq(seq);
                         }
+                }
 
-               }
+                g_array_set_size(array, 0);
+        }
+done:
+        if (!quiet)
+                g_printerr("End of data.\n");
+
+        for (unsigned int s = VTE_SEQ_NONE + 1; s < VTE_SEQ_N; s++) {
+                g_printerr("%-7s: %" G_GSIZE_FORMAT "\n", seq_to_str(s), seq_stats[s]);
+        }
 
-        next_match:
-                if (start < wcount) {
-                        g_array_remove_range(array, 0, start);
-                        start = wcount - start;
-                } else {
-                        g_array_set_size(array, 0);
-                        start = 0;
+        g_printerr("\n");
+        for (unsigned int s = 0; s < VTE_CMD_N; s++) {
+                if (cmd_stats[s] > 0) {
+                        g_printerr("%-12s: %" G_GSIZE_FORMAT "\n", cmd_to_str(s), cmd_stats[s]);
                 }
-       }
-        if (!quiet)
-                g_print("End of data.\n");
+        }
 
-        g_printerr ("Characters inserted:  %" G_GSIZE_FORMAT "\n"
-                    "Sequences recognised: %" G_GSIZE_FORMAT "\n"
-                    "Bytes discarded:      %" G_GSIZE_FORMAT "\n",
-                    n_chars, n_seq, n_discarded);
+        g_free(seq_stats);
+        g_free(cmd_stats);
 
-       close (infile);
+        close (infile);
 
-       _vte_iso2022_state_free(subst);
-       g_array_free(array, TRUE);
-       _vte_matcher_free(matcher);
-       return 0;
+        _vte_iso2022_state_free(subst);
+        g_array_free(array, TRUE);
+        vte_parser_free(parser);
+        g_free(buf);
+        return 0;
 }
diff --git a/src/iso2022.h b/src/iso2022.h
index 78c71e7..4b28edc 100644
--- a/src/iso2022.h
+++ b/src/iso2022.h
@@ -25,7 +25,6 @@
 #include <glib.h>
 #include <glib-object.h>
 #include "buffer.h"
-#include "matcher.hh"
 
 G_BEGIN_DECLS
 
diff --git a/src/matcher.cc b/src/matcher.cc
index 8148d84..b4172d6 100644
--- a/src/matcher.cc
+++ b/src/matcher.cc
@@ -100,7 +100,7 @@ _vte_matcher_init(struct _vte_matcher *matcher)
                 }
         }
 
-       _VTE_DEBUG_IF(VTE_DEBUG_MATCHER) {
+       _VTE_DEBUG_IF(VTE_DEBUG_PARSER) {
                g_printerr("Matcher contents:\n");
                _vte_matcher_print(matcher);
                g_printerr("\n");
diff --git a/src/parser-cmd.hh b/src/parser-cmd.hh
new file mode 100644
index 0000000..8f8d640
--- /dev/null
+++ b/src/parser-cmd.hh
@@ -0,0 +1,193 @@
+/*
+ * Copyright © 2015 David Herrmann <dh herrmann gmail com>
+ *
+ * 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_CMD(NONE) /* placeholder */
+_VTE_CMD(GRAPHIC) /* graphics character */
+_VTE_CMD(BEL) /* bell */
+_VTE_CMD(BS) /* backspace */
+_VTE_CMD(CBT) /* cursor-backward-tabulation */
+_VTE_CMD(CHA) /* cursor-horizontal-absolute */
+_VTE_CMD(CHT) /* cursor-horizontal-forward-tabulation */
+_VTE_CMD(CNL) /* cursor-next-line */
+_VTE_CMD(CPL) /* cursor-previous-line */
+_VTE_CMD(CR) /* carriage-return */
+_VTE_CMD(CUB) /* cursor-backward */
+_VTE_CMD(CUD) /* cursor-down */
+_VTE_CMD(CUF) /* cursor-forward */
+_VTE_CMD(CUP) /* cursor-position */
+_VTE_CMD(CUU) /* cursor-up */
+_VTE_CMD(DA1) /* primary-device-attributes */
+_VTE_CMD(DA2) /* secondary-device-attributes */
+_VTE_CMD(DA3) /* tertiary-device-attributes */
+_VTE_CMD(DC1) /* device-control-1 or XON */
+_VTE_CMD(DC3) /* device-control-3 or XOFF */
+_VTE_CMD(DCH) /* delete-character */
+_VTE_CMD(DECALN) /* screen-alignment-pattern */
+_VTE_CMD(DECANM) /* ansi-mode */
+_VTE_CMD(DECBI) /* back-index */
+_VTE_CMD(DECCARA) /* change-attributes-in-rectangular-area */
+_VTE_CMD(DECCRA) /* copy-rectangular-area */
+_VTE_CMD(DECDC) /* delete-column */
+_VTE_CMD(DECDHL_BH) /* double-width-double-height-line: bottom half */
+_VTE_CMD(DECDHL_TH) /* double-width-double-height-line: top half */
+_VTE_CMD(DECDWL) /* double-width-single-height-line */
+_VTE_CMD(DECEFR) /* enable-filter-rectangle */
+_VTE_CMD(DECELF) /* enable-local-functions */
+_VTE_CMD(DECELR) /* enable-locator-reporting */
+_VTE_CMD(DECERA) /* erase-rectangular-area */
+_VTE_CMD(DECFI) /* forward-index */
+_VTE_CMD(DECFRA) /* fill-rectangular-area */
+_VTE_CMD(DECIC) /* insert-column */
+_VTE_CMD(DECID) /* return-terminal-id */
+_VTE_CMD(DECINVM) /* invoke-macro */
+_VTE_CMD(DECKBD) /* keyboard-language-selection */
+_VTE_CMD(DECKPAM) /* keypad-application-mode */
+_VTE_CMD(DECKPNM) /* keypad-numeric-mode */
+_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(DECPKA) /* program-key-action */
+_VTE_CMD(DECPKFMR) /* program-key-free-memory-report */
+_VTE_CMD(DECRARA) /* reverse-attributes-in-rectangular-area */
+_VTE_CMD(DECRC) /* restore-cursor */
+_VTE_CMD(DECREQTPARM) /* request-terminal-parameters */
+_VTE_CMD(DECRPKT) /* report-key-type */
+_VTE_CMD(DECRQCRA) /* request-checksum-of-rectangular-area */
+_VTE_CMD(DECRQDE) /* request-display-extent */
+_VTE_CMD(DECRQKT) /* request-key-type */
+_VTE_CMD(DECRQLP) /* request-locator-position */
+_VTE_CMD(DECRQM_ANSI) /* request-mode-ansi */
+_VTE_CMD(DECRQM_DEC) /* request-mode-dec */
+_VTE_CMD(DECRQPKFM) /* request-program-key-free-memory */
+_VTE_CMD(DECRQPSR) /* request-presentation-state-report */
+_VTE_CMD(DECRQTSR) /* request-terminal-state-report */
+_VTE_CMD(DECRQUPSS) /* request-user-preferred-supplemental-set */
+_VTE_CMD(DECSACE) /* select-attribute-change-extent */
+_VTE_CMD(DECSASD) /* select-active-status-display */
+_VTE_CMD(DECSC) /* save-cursor */
+_VTE_CMD(DECSCA) /* select-character-protection-attribute */
+_VTE_CMD(DECSCL) /* select-conformance-level */
+_VTE_CMD(DECSCP) /* select-communication-port */
+_VTE_CMD(DECSCPP) /* select-columns-per-page */
+_VTE_CMD(DECSCS) /* select-communication-speed */
+_VTE_CMD(DECSCUSR) /* set-cursor-style */
+_VTE_CMD(DECSDDT) /* select-disconnect-delay-time */
+_VTE_CMD(DECSDPT) /* select-digital-printed-data-type */
+_VTE_CMD(DECSED) /* selective-erase-in-display */
+_VTE_CMD(DECSEL) /* selective-erase-in-line */
+_VTE_CMD(DECSERA) /* selective-erase-rectangular-area */
+_VTE_CMD(DECSFC) /* select-flow-control */
+_VTE_CMD(DECSKCV) /* set-key-click-volume */
+_VTE_CMD(DECSLCK) /* set-lock-key-style */
+_VTE_CMD(DECSLE) /* select-locator-events */
+_VTE_CMD(DECSLPP) /* set-lines-per-page */
+_VTE_CMD(DECSLRM_OR_SC) /* set-left-and-right-margins or save-cursor */
+_VTE_CMD(DECSMBV) /* set-margin-bell-volume */
+_VTE_CMD(DECSMKR) /* select-modifier-key-reporting */
+_VTE_CMD(DECSNLS) /* set-lines-per-screen */
+_VTE_CMD(DECSPP) /* set-port-parameter */
+_VTE_CMD(DECSPPCS) /* select-pro-printer-character-set */
+_VTE_CMD(DECSPRTT) /* select-printer-type */
+_VTE_CMD(DECSR) /* secure-reset */
+_VTE_CMD(DECSRFR) /* select-refresh-rate */
+_VTE_CMD(DECSSCLS) /* set-scroll-speed */
+_VTE_CMD(DECSSDT) /* select-status-display-line-type */
+_VTE_CMD(DECSSL) /* select-setup-language */
+_VTE_CMD(DECST8C) /* set-tab-at-every-8-columns */
+_VTE_CMD(DECSTBM) /* set-top-and-bottom-margins */
+_VTE_CMD(DECSTR) /* soft-terminal-reset */
+_VTE_CMD(DECSTRL) /* set-transmit-rate-limit */
+_VTE_CMD(DECSWBV) /* set-warning-bell-volume */
+_VTE_CMD(DECSWL) /* single-width-single-height-line */
+_VTE_CMD(DECTID) /* select-terminal-id */
+_VTE_CMD(DECTME) /* terminal-mode-emulation */
+_VTE_CMD(DECTST) /* invoke-confidence-test */
+_VTE_CMD(DL) /* delete-line */
+_VTE_CMD(DSR_ANSI) /* device-status-report-ansi */
+_VTE_CMD(DSR_DEC) /* device-status-report-dec */
+_VTE_CMD(ECH) /* erase-character */
+_VTE_CMD(ED) /* erase-in-display */
+_VTE_CMD(EL) /* erase-in-line */
+_VTE_CMD(ENQ) /* enquiry */
+_VTE_CMD(EPA) /* end-of-guarded-area */
+_VTE_CMD(FF) /* form-feed */
+_VTE_CMD(HPA) /* horizontal-position-absolute */
+_VTE_CMD(HPR) /* horizontal-position-relative */
+_VTE_CMD(HT) /* horizontal-tab */
+_VTE_CMD(HTS) /* horizontal-tab-set */
+_VTE_CMD(HVP) /* horizontal-and-vertical-position */
+_VTE_CMD(ICH) /* insert-character */
+_VTE_CMD(IL) /* insert-line */
+_VTE_CMD(IND) /* index */
+_VTE_CMD(LF) /* line-feed */
+_VTE_CMD(LS1R) /* locking-shift-1-right */
+_VTE_CMD(LS2) /* locking-shift-2 */
+_VTE_CMD(LS2R) /* locking-shift-2-right */
+_VTE_CMD(LS3) /* locking-shift-3 */
+_VTE_CMD(LS3R) /* locking-shift-3-right */
+_VTE_CMD(MC_ANSI) /* media-copy-ansi */
+_VTE_CMD(MC_DEC) /* media-copy-dec */
+_VTE_CMD(NEL) /* next-line */
+_VTE_CMD(NP) /* next-page */
+_VTE_CMD(NUL) /* nul */
+_VTE_CMD(PP) /* preceding-page */
+_VTE_CMD(PPA) /* page-position-absolute */
+_VTE_CMD(PPB) /* page-position-backward */
+_VTE_CMD(PPR) /* page-position-relative */
+_VTE_CMD(RC) /* restore-cursor */
+_VTE_CMD(REP) /* repeat */
+_VTE_CMD(RI) /* reverse-index */
+_VTE_CMD(RIS) /* reset-to-initial-state */
+_VTE_CMD(RM_ANSI) /* reset-mode-ansi */
+_VTE_CMD(RM_DEC) /* reset-mode-dec */
+_VTE_CMD(S7C1T) /* set-7bit-c1-terminal */
+_VTE_CMD(S8C1T) /* set-8bit-c1-terminal */
+_VTE_CMD(SCS) /* select-character-set */
+_VTE_CMD(SD) /* scroll-down */
+_VTE_CMD(SGR) /* select-graphics-rendition */
+_VTE_CMD(SI) /* shift-in */
+_VTE_CMD(SM_ANSI) /* set-mode-ansi */
+_VTE_CMD(SM_DEC) /* set-mode-dec */
+_VTE_CMD(SO) /* shift-out */
+_VTE_CMD(SPA) /* start-of-protected-area */
+_VTE_CMD(SS2) /* single-shift-2 */
+_VTE_CMD(SS3) /* single-shift-3 */
+_VTE_CMD(ST) /* string-terminator */
+_VTE_CMD(SU) /* scroll-up */
+_VTE_CMD(SUB) /* substitute */
+_VTE_CMD(TBC) /* tab-clear */
+_VTE_CMD(VPA) /* vertical-line-position-absolute */
+_VTE_CMD(VPR) /* vertical-line-position-relative */
+_VTE_CMD(VT) /* vertical-tab */
+_VTE_CMD(XTERM_CLLHP) /* xterm-cursor-lower-left-hp-bugfix */
+_VTE_CMD(XTERM_IHMT) /* xterm-initiate-highlight-mouse-tracking */
+_VTE_CMD(XTERM_MLHP) /* xterm-memory-lock-hp-bugfix */
+_VTE_CMD(XTERM_MUHP) /* xterm-memory-unlock-hp-bugfix */
+_VTE_CMD(XTERM_RPM) /* xterm-restore-private-mode */
+_VTE_CMD(XTERM_RRV) /* xterm-reset-resource-value */
+_VTE_CMD(XTERM_RTM) /* xterm-reset-title-mode */
+_VTE_CMD(XTERM_SACL1) /* xterm-set-ansi-conformance-level-1 */
+_VTE_CMD(XTERM_SACL2) /* xterm-set-ansi-conformance-level-2 */
+_VTE_CMD(XTERM_SACL3) /* xterm-set-ansi-conformance-level-3 */
+_VTE_CMD(XTERM_SDCS) /* xterm-set-default-character-set */
+_VTE_CMD(XTERM_SGFX) /* xterm-sixel-graphics */
+_VTE_CMD(XTERM_SPM) /* xterm-set-private-mode */
+_VTE_CMD(XTERM_SRV) /* xterm-set-resource-value */
+_VTE_CMD(XTERM_STM) /* xterm-set-title-mode */
+_VTE_CMD(XTERM_SUCS) /* xterm-set-utf8-character-set */
+_VTE_CMD(XTERM_WM) /* xterm-window-management */
diff --git a/src/parser-glue.hh b/src/parser-glue.hh
new file mode 100644
index 0000000..7614d46
--- /dev/null
+++ b/src/parser-glue.hh
@@ -0,0 +1,148 @@
+/*
+ * Copyright © 2017 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 <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "parser.hh"
+
+namespace vte {
+
+namespace parser {
+
+class Sequence {
+public:
+
+        typedef int number;
+
+        char* ucs4_to_utf8(gunichar const* str) const;
+
+        void print() const;
+
+        inline unsigned int type() const { return m_seq->type; }
+
+        inline unsigned int command() const { return m_seq->command; }
+
+        inline uint32_t terminator() const { return m_seq->terminator; }
+
+        inline unsigned int size() const
+        {
+                g_assert_nonnull(m_seq);
+                return m_seq->n_args;
+        }
+
+        inline int operator[](int position) const
+        {
+                return G_LIKELY(position < (int)size()) ? m_seq->args[position] : -1;
+        }
+
+        inline bool has_number_at_unchecked(unsigned int position) const
+        {
+                return true;
+        }
+
+        inline bool number_at_unchecked(unsigned int position, number& v) const
+        {
+                v = m_seq->args[position];
+                return true;
+        }
+
+        inline bool number_at(unsigned int position, number& v) const
+        {
+                if (G_UNLIKELY(position >= size()))
+                        return false;
+
+                return number_at_unchecked(position, v);
+        }
+
+        inline number number_or_default_at_unchecked(unsigned int position, number default_v = 0) const
+        {
+                number v;
+                if (G_UNLIKELY(!number_at_unchecked(position, v)))
+                        v = default_v;
+                return v;
+        }
+
+
+        inline number number_or_default_at(unsigned int position, number default_v = 0) const
+        {
+                number v;
+                if (G_UNLIKELY(!number_at(position, v)))
+                        v = default_v;
+                return v;
+        }
+
+        inline bool string_at_unchecked(unsigned int position, char*& str) const
+        {
+#if 0
+                auto value = value_at_unchecked(position);
+                if (G_LIKELY(G_VALUE_HOLDS_POINTER(value))) {
+                        str = ucs4_to_utf8((gunichar const*)g_value_get_pointer (value));
+                        return str != nullptr;
+                }
+                if (G_VALUE_HOLDS_STRING(value)) {
+                        /* Copy the string into the buffer. */
+                        str = g_value_dup_string(value);
+                        return str != nullptr;
+                }
+                if (G_VALUE_HOLDS_LONG(value)) {
+                        /* Convert the long to a string. */
+                        str = g_strdup_printf("%ld", g_value_get_long(value));
+                        return true;
+                }
+#endif
+                str = nullptr;
+                return false;
+        }
+
+        inline bool string_at(unsigned int position, char*& str) const
+        {
+#if 0
+                if (G_UNLIKELY(position >= size()))
+                        return false;
+
+                return string_at_unchecked(position, str);
+#endif
+                str = nullptr;
+                return false;
+        }
+
+        inline bool has_subparams_at_unchecked(unsigned int position) const
+        {
+                return false;
+        }
+
+        inline Sequence subparams_at_unchecked(unsigned int position) const
+        {
+                return Sequence{};
+        }
+
+        struct vte_seq** seq_ptr() { return &m_seq; }
+
+        inline explicit operator bool() const { return m_seq != nullptr; }
+
+private:
+        struct vte_seq *m_seq{nullptr};
+
+        char const* type_string() const;
+        char const* command_string() const;
+};
+
+typedef Sequence Params;
+
+} // namespace parser
+
+} // namespace vte
diff --git a/src/parser-test.cc b/src/parser-test.cc
new file mode 100644
index 0000000..6cd2e65
--- /dev/null
+++ b/src/parser-test.cc
@@ -0,0 +1,539 @@
+/*
+ * Copyright © 2017, 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/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <string>
+
+#include <glib.h>
+
+#include "parser.hh"
+
+static struct vte_parser* parser;
+
+#if 0
+static char const*
+seq_to_str(unsigned int type)
+{
+        switch (type) {
+        case VTE_SEQ_NONE: return "NONE";
+        case VTE_SEQ_IGNORE: return "IGNORE";
+        case VTE_SEQ_GRAPHIC: return "GRAPHIC";
+        case VTE_SEQ_CONTROL: return "CONTROL";
+        case VTE_SEQ_ESCAPE: return "ESCAPE";
+        case VTE_SEQ_CSI: return "CSI";
+        case VTE_SEQ_DCS: return "DCS";
+        case VTE_SEQ_OSC: return "OSC";
+        default:
+                g_assert_not_reached();
+        }
+}
+
+static char const*
+cmd_to_str(unsigned int command)
+{
+        switch (command) {
+#define _VTE_CMD(cmd) case VTE_CMD_##cmd: return #cmd;
+#include "parser-cmd.hh"
+#undef _VTE_CMD
+        default:
+                static char buf[32];
+                snprintf(buf, sizeof(buf), "UNKOWN(%u)", command);
+                return buf;
+        }
+}
+#endif
+
+static const char c0str[][6] = {
+        "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
+        "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
+        "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
+        "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US",
+        "SPACE"
+};
+
+static const char c1str[][5] = {
+        "DEL",
+        "0x80", "0x81", "BPH", "NBH", "0x84", "NEL", "SSA", "ESA",
+        "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3",
+        "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA",
+        "SOS", "0x99", "SCI", "CSI", "ST", "OSC", "PM", "APC"
+};
+
+static void
+print_escaped(std::u32string const& s)
+{
+        for (auto it : s) {
+                uint32_t c = (char32_t)it;
+
+                if (c <= 0x20)
+                        g_print("%s ", c0str[c]);
+                else if (c < 0x7f)
+                        g_print("%c ", c);
+                else if (c < 0xa0)
+                        g_print("%s ", c1str[c - 0x7f]);
+                else
+                        g_print("U+%04X", c);
+        }
+        g_print("\n");
+}
+
+#if 0
+static void
+print_seq(const struct vte_seq *seq)
+{
+        auto c = seq->terminator;
+        if (seq->command == VTE_CMD_GRAPHIC) {
+                char buf[7];
+                buf[g_unichar_to_utf8(c, buf)] = 0;
+                g_print("%s U+%04X [%s]\n", cmd_to_str(seq->command),
+                        c,
+                        g_unichar_isprint(c) ? buf : "�");
+        } else {
+                g_print("%s", cmd_to_str(seq->command));
+                if (seq->n_args) {
+                        g_print(" ");
+                        for (unsigned int i = 0; i < seq->n_args; i++) {
+                                if (i > 0)
+                                        g_print(";");
+                        g_print("%d", seq->args[i]);
+                        }
+                }
+                g_print("\n");
+        }
+}
+#endif
+
+class vte_seq_builder {
+public:
+        vte_seq_builder(unsigned int type,
+                        uint32_t f) {
+                memset(&m_seq, 0, sizeof(m_seq));
+                m_seq.type = type;
+                set_final(f);
+        }
+
+        ~vte_seq_builder() = default;
+
+        void set_final(uint32_t raw) { m_seq.terminator = raw; }
+        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;
+        }
+
+        void set_params(int params[16])
+        {
+                memcpy(&m_seq.args, params, 16*sizeof(params[0]));
+        }
+
+        void set_n_params(unsigned int n)
+        {
+                m_seq.n_args = n;
+        }
+
+        void set_param_byte(uint32_t p)
+        {
+                m_p = p;
+                if (p != 0) {
+                        m_seq.intermediates |= (1u << (p - 0x20));
+                }
+        }
+
+        void to_string(std::u32string& s,
+                       bool c1 = false);
+
+        void assert_equal(struct vte_seq* seq);
+        void assert_equal_full(struct vte_seq* seq);
+
+        void print(bool c1 = false);
+
+private:
+        uint32_t m_i[4]{0, 0, 0, 0};
+        uint32_t m_p;
+        unsigned int m_ni{0};
+        struct vte_seq m_seq;
+
+};
+
+void
+vte_seq_builder::to_string(std::u32string& s,
+                           bool c1)
+{
+        switch (m_seq.type) {
+        case VTE_SEQ_ESCAPE:
+                s.push_back(0x1B); // ESC
+                break;
+        case VTE_SEQ_CSI: {
+                if (c1) {
+                        s.push_back(0x9B); // CSI
+                } else {
+                        s.push_back(0x1B); // ESC
+                        s.push_back(0x5B); // [
+                }
+
+                if (m_p != 0)
+                        s.push_back(m_p);
+                auto n_args = m_seq.n_args;
+                for (unsigned int n = 0; n < n_args; n++) {
+                        auto arg = m_seq.args[n];
+                        if (n > 0)
+                                s.push_back(0x3B); // semicolon
+                        if (arg >= 0) {
+                                char buf[16];
+                                int l = g_snprintf(buf, sizeof(buf), "%d", arg);
+                                for (int j = 0; j < l; j++)
+                                        s.push_back(buf[j]);
+                        }
+                }
+                break;
+        }
+        default:
+                return;
+        }
+
+        for (unsigned int n = 0; n < m_ni; n++)
+                s.push_back(m_i[n]);
+
+        s.push_back(m_seq.terminator);
+}
+
+void
+vte_seq_builder::print(bool c1)
+{
+        std::u32string s;
+        to_string(s, c1);
+        print_escaped(s);
+}
+
+void
+vte_seq_builder::assert_equal(struct vte_seq* seq)
+{
+        g_assert_cmpuint(m_seq.type, ==, seq->type);
+        g_assert_cmpuint(m_seq.terminator, ==, seq->terminator);
+}
+
+void
+vte_seq_builder::assert_equal_full(struct vte_seq* seq)
+{
+        assert_equal(seq);
+        /* We may get one arg less back, if it's at default */
+        if (m_seq.n_args != seq->n_args) {
+                g_assert_cmpuint(m_seq.n_args, ==, seq->n_args + 1);
+                g_assert_cmpuint(m_seq.args[m_seq.n_args - 1], ==, -1);
+        }
+        for (unsigned int n = 0; n < seq->n_args; n++)
+                g_assert_cmpint(std::min(m_seq.args[n], 0xffff), ==, seq->args[n]);
+}
+
+static int
+feed_parser(vte_seq_builder& b,
+            struct vte_seq** seq,
+            bool c1 = false)
+{
+        std::u32string s;
+        b.to_string(s, c1);
+
+        //        print_escaped(s);
+
+        int rv = VTE_SEQ_NONE;
+        for (auto it : s) {
+                rv = vte_parser_feed(parser, seq, (uint32_t)(char32_t)it);
+                if (rv < 0)
+                        break;
+        }
+        return rv;
+}
+
+static void
+test_seq_control(void)
+{
+        static struct {
+                uint32_t c;
+                unsigned int type;
+                unsigned int cmd;
+        } const controls [] = {
+                { 0x0,  VTE_SEQ_CONTROL, VTE_CMD_NUL     },
+                { 0x1,  VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x2,  VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x3,  VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x4,  VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x5,  VTE_SEQ_CONTROL, VTE_CMD_ENQ     },
+                { 0x6,  VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x7,  VTE_SEQ_CONTROL, VTE_CMD_BEL     },
+                { 0x8,  VTE_SEQ_CONTROL, VTE_CMD_BS      },
+                { 0x9,  VTE_SEQ_CONTROL, VTE_CMD_HT      },
+                { 0xa,  VTE_SEQ_CONTROL, VTE_CMD_LF      },
+                { 0xb,  VTE_SEQ_CONTROL, VTE_CMD_VT      },
+                { 0xc,  VTE_SEQ_CONTROL, VTE_CMD_FF      },
+                { 0xd,  VTE_SEQ_CONTROL, VTE_CMD_CR      },
+                { 0xe,  VTE_SEQ_CONTROL, VTE_CMD_SO      },
+                { 0xf,  VTE_SEQ_CONTROL, VTE_CMD_SI      },
+                { 0x10, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x11, VTE_SEQ_CONTROL, VTE_CMD_DC1     },
+                { 0x12, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x13, VTE_SEQ_CONTROL, VTE_CMD_DC3     },
+                { 0x14, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x15, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x16, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x17, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x18, VTE_SEQ_IGNORE,  VTE_CMD_NONE    },
+                { 0x19, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x1a, VTE_SEQ_CONTROL, VTE_CMD_SUB     },
+                { 0x1b, VTE_SEQ_IGNORE,  VTE_CMD_NONE    },
+                { 0x1c, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x1d, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x1e, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x1f, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x7f, VTE_SEQ_GRAPHIC, VTE_CMD_GRAPHIC }, // FIXMEchpe
+                { 0x80, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x81, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x82, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x83, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x84, VTE_SEQ_CONTROL, VTE_CMD_IND     },
+                { 0x85, VTE_SEQ_CONTROL, VTE_CMD_NEL     },
+                { 0x86, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x87, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x88, VTE_SEQ_CONTROL, VTE_CMD_HTS     },
+                { 0x89, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x8a, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x8b, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x8c, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x8d, VTE_SEQ_CONTROL, VTE_CMD_RI      },
+                { 0x8e, VTE_SEQ_CONTROL, VTE_CMD_SS2     },
+                { 0x8f, VTE_SEQ_CONTROL, VTE_CMD_SS3     },
+                { 0x90, VTE_SEQ_IGNORE,  VTE_CMD_NONE    },
+                { 0x91, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x92, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x93, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x94, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x95, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x96, VTE_SEQ_CONTROL, VTE_CMD_SPA     },
+                { 0x97, VTE_SEQ_CONTROL, VTE_CMD_EPA     },
+                { 0x98, VTE_SEQ_IGNORE,  VTE_CMD_NONE    },
+                { 0x99, VTE_SEQ_CONTROL, VTE_CMD_NONE    },
+                { 0x9a, VTE_SEQ_CONTROL, VTE_CMD_DECID   },
+                { 0x9b, VTE_SEQ_IGNORE,  VTE_CMD_NONE    },
+                { 0x9c, VTE_SEQ_IGNORE,  VTE_CMD_NONE    },
+                { 0x9d, VTE_SEQ_IGNORE,  VTE_CMD_NONE    },
+                { 0x9e, VTE_SEQ_IGNORE,  VTE_CMD_NONE    },
+                { 0x9f, VTE_SEQ_IGNORE,  VTE_CMD_NONE    },
+        };
+
+        for (unsigned int i = 0; i < G_N_ELEMENTS(controls); i++) {
+                vte_parser_reset(parser);
+                struct vte_seq* seq;
+                auto rv = vte_parser_feed(parser, &seq, controls[i].c);
+                g_assert_cmpuint(rv, >=, 0);
+                g_assert_cmpuint(controls[i].type, ==, seq->type);
+                g_assert_cmpuint(controls[i].cmd, ==, seq->command);
+        }
+}
+
+static void
+test_seq_esc_invalid(void)
+{
+        /* Tests invalid ESC 0/n and ESC 1/n sequences, which should never result in
+         * an VTE_SEQ_ESCAPE type sequence, but instead always in the C0 control.
+         */
+        for (uint32_t f = 0x0; f < 0x20; f++) {
+                vte_parser_reset(parser);
+
+                vte_seq_builder b{VTE_SEQ_ESCAPE, f};
+                struct vte_seq* seq;
+                auto rv = feed_parser(b, &seq);
+                g_assert_cmpint(rv, !=, VTE_SEQ_ESCAPE);
+        }
+}
+
+static void
+test_seq_esc(uint32_t f,
+             uint32_t i[],
+             unsigned int ni)
+{
+        vte_seq_builder b{VTE_SEQ_ESCAPE, f};
+        b.set_intermediates(i, ni);
+
+        vte_parser_reset(parser);
+        struct vte_seq* seq;
+        auto rv = feed_parser(b, &seq);
+        if (rv == VTE_SEQ_ESCAPE)
+                b.assert_equal(seq);
+}
+
+static void
+test_seq_esc_nF(void)
+{
+        /* Tests nF sequences, that is ESC 2/n [2/m..] F with F being 3/0..7/14.
+         * They could have any number of itermediates, but we only test up to 4.
+         */
+
+        uint32_t i[4];
+        for (uint32_t f = 0x30; f < 0x7f; f++) {
+                test_seq_esc(f, i, 0);
+                for (i[0] = 0x20; i[0] < 0x30; i[0]++) {
+                        test_seq_esc(f, i, 1);
+                        for (i[1] = 0x20; i[1] < 0x30; i[1]++) {
+                                test_seq_esc(f, i, 2);
+                                for (i[2] = 0x20; i[2] < 0x30; i[2]++) {
+                                        test_seq_esc(f, i, 3);
+                                        for (i[3] = 0x20; i[3] < 0x30; i[3]++) {
+                                                test_seq_esc(f, i, 4);
+                                        }
+                                }
+                        }
+                }
+        }
+}
+
+static void
+test_seq_esc_Fpes(void)
+{
+        /* Tests Fp, Fe and Ft sequences, that is ESC 3/n .. ESC 7/14 */
+
+        for (uint32_t f = 0x30; f < 0x7f; f++) {
+                vte_parser_reset(parser);
+
+                vte_seq_builder b{VTE_SEQ_ESCAPE, f};
+
+                struct vte_seq* seq;
+                auto rv = feed_parser(b, &seq);
+                int expected_rv;
+                switch (f) {
+                case 'P': /* DCS */
+                case 'X': /* SOS */
+                case '_': /* APC */
+                case '[': /* CSI */
+                case ']': /* OSC */
+                case '^': /* PM */
+                        expected_rv = VTE_SEQ_NONE;
+                        break;
+                default:
+                        expected_rv = VTE_SEQ_ESCAPE;
+                        break;
+                }
+                g_assert_cmpint(rv, ==, expected_rv);
+                if (rv != VTE_SEQ_NONE)
+                        b.assert_equal(seq);
+        }
+}
+
+static void
+test_seq_csi(uint32_t f,
+             uint32_t p,
+             int params[16],
+             uint32_t i[4],
+             unsigned int ni)
+{
+        vte_seq_builder b{VTE_SEQ_CSI, f};
+        b.set_intermediates(i, ni);
+        b.set_param_byte(p);
+        b.set_params(params);
+
+        int expected_rv = (f & 0xF0) == 0x30 ? VTE_SEQ_NONE : VTE_SEQ_CSI;
+
+        for (unsigned int n = 0; n <= 16; n++) {
+                b.set_n_params(n);
+
+                vte_parser_reset(parser);
+                struct vte_seq* seq;
+                /* First with C0 CSI */
+                auto rv = feed_parser(b, &seq, false);
+                g_assert_cmpint(rv, ==, expected_rv);
+                if (rv != VTE_SEQ_NONE)
+                        b.assert_equal_full(seq);
+
+                /* Now with C1 CSI */
+                rv = feed_parser(b, &seq, true);
+                if (rv != VTE_SEQ_NONE)
+                        b.assert_equal_full(seq);
+        }
+}
+
+static void
+test_seq_csi(uint32_t p,
+             int params[16])
+{
+        uint32_t i[4];
+        for (uint32_t f = 0x30; f < 0x7f; f++) {
+                test_seq_csi(f, p, params, i, 0);
+                for (i[0] = 0x20; i[0] < 0x30; i[0]++) {
+                        test_seq_csi(f, p, params, i, 1);
+                        for (i[1] = 0x20; i[1] < 0x30; i[1]++) {
+                                test_seq_csi(f, p, params, i, 2);
+                        }
+                }
+        }
+}
+
+static void
+test_seq_csi(int params[16])
+{
+        test_seq_csi(0, params);
+        for (uint32_t p = 0x3c; p <= 0x3f; p++)
+                test_seq_csi(p, params);
+}
+
+static void
+test_seq_csi(void)
+{
+        /* Tests CSI sequences, that is sequences of the form
+         * CSI P...P I...I F
+         * with parameter bytes P from 3/0..3/15, intermediate bytes I from 2/0..2/15 and
+         * final byte F from 4/0..7/14.
+         * There could be any number of intermediate bytes, but we only test up to 2.
+         * There could be any number of extra params bytes, but we only test up to 1.
+         * CSI can be either the C1 control itself, or ESC [
+         */
+        int params1[16]{ -1, 0, 1, 9, 10, 99, 100, 999, 1000, 9999, 10000, 65534, 65535, 65536, -1, -1 };
+        test_seq_csi(params1);
+
+        int params2[16]{ 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1 };
+        test_seq_csi(params2);
+}
+
+int
+main(int argc,
+     char* argv[])
+{
+        g_test_init(&argc, &argv, nullptr);
+
+        if (vte_parser_new(&parser) < 0)
+                return 1;
+
+        g_test_add_func("/vte/parser/sequences/control", test_seq_control);
+        g_test_add_func("/vte/parser/sequences/escape/invalid", test_seq_esc_invalid);
+        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/csi", test_seq_csi);
+
+        auto rv = g_test_run();
+
+        parser = vte_parser_free(parser);
+        return rv;
+}
diff --git a/src/parser.cc b/src/parser.cc
index c06d51d..0f2d088 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -1,23 +1,30 @@
 /*
  * Copyright © 2015 David Herrmann <dh herrmann gmail com>
  *
- * vte 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 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/>.
  */
 
 #include "config.h"
 
+#include "parser.hh"
+
 #include <cstdio>
 #include <cstring>
 #include <cstdlib>
 #include <cerrno>
 
-//#include <linux/bitops.h>
-//#include <linux/kernel.h>
-//#include <linux/slab.h>
-#include "parser.hh"
+#include <glib.h>
 
 #define WARN(num,str) do { } while (0)
 #define hweight32(v) (__builtin_popcount(v))
@@ -52,7 +59,7 @@ static unsigned int vte_parse_host_control(const struct vte_seq *seq)
 {
         switch (seq->terminator) {
         case 0x00: /* NUL */
-                return VTE_CMD_NULL;
+                return VTE_CMD_NUL;
         case 0x05: /* ENQ */
                 return VTE_CMD_ENQ;
         case 0x07: /* BEL */
@@ -131,11 +138,11 @@ static unsigned int vte_parse_host_control(const struct vte_seq *seq)
         return VTE_CMD_NONE;
 }
 
-static int vte_charset_from_cmd(u32 raw, unsigned int flags, bool require_96)
+static int vte_charset_from_cmd(uint32_t raw, unsigned int flags, bool require_96)
 {
 #if 0
         static const struct {
-                u32 raw;
+                uint32_t raw;
                 unsigned int flags;
         } charset_cmds[] = {
                 /* 96-compat charsets */
@@ -903,49 +910,49 @@ static unsigned int vte_parse_host_csi(const struct vte_seq *seq)
  * State Machine
  * This parser controls the parser-state and returns any detected sequence to
  * the caller. The parser is based on this state-diagram from Paul Williams:
- *   http://vt100.net/emu/
+ *   https://vt100.net/emu/
  * It was written from scratch and extended where needed.
  * This parser is fully compatible up to the vt500 series. We expect UCS-4 as
  * input. It's the callers responsibility to do any UTF-8 parsing.
  */
 
 enum parser_state {
-        STATE_NONE,                /* placeholder */
-        STATE_GROUND,                /* initial state and ground */
-        STATE_ESC,                /* ESC sequence was started */
-        STATE_ESC_INT,                /* intermediate escape characters */
+        STATE_NONE,             /* placeholder */
+        STATE_GROUND,           /* initial state and ground */
+        STATE_ESC,              /* ESC sequence was started */
+        STATE_ESC_INT,          /* intermediate escape characters */
         STATE_CSI_ENTRY,        /* starting CSI sequence */
         STATE_CSI_PARAM,        /* CSI parameters */
-        STATE_CSI_INT,                /* intermediate CSI characters */
-        STATE_CSI_IGNORE,        /* CSI error; ignore this CSI sequence */
+        STATE_CSI_INT,          /* intermediate CSI characters */
+        STATE_CSI_IGNORE,       /* CSI error; ignore this CSI sequence */
         STATE_DCS_ENTRY,        /* starting DCS sequence */
         STATE_DCS_PARAM,        /* DCS parameters */
-        STATE_DCS_INT,                /* intermediate DCS characters */
-        STATE_DCS_PASS,                /* DCS data passthrough */
-        STATE_DCS_IGNORE,        /* DCS error; ignore this DCS sequence */
-        STATE_OSC_STRING,        /* parsing OSC sequence */
+        STATE_DCS_INT,          /* intermediate DCS characters */
+        STATE_DCS_PASS,         /* DCS data passthrough */
+        STATE_DCS_IGNORE,       /* DCS error; ignore this DCS sequence */
+        STATE_OSC_STRING,       /* parsing OSC sequence */
         STATE_ST_IGNORE,        /* unimplemented seq; ignore until ST */
         STATE_N,
 };
 
 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_COLLECT,        /* collect DCS data */
-        ACTION_DCS_CONSUME,        /* consume DCS terminator */
-        ACTION_DCS_DISPATCH,        /* dispatch dcs sequence */
-        ACTION_OSC_START,        /* start of OSC data */
-        ACTION_OSC_COLLECT,        /* collect OSC data */
-        ACTION_OSC_CONSUME,        /* consume OSC terminator */
-        ACTION_OSC_DISPATCH,        /* dispatch osc 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,         /* 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_COLLECT,     /* collect DCS data */
+        ACTION_DCS_CONSUME,     /* consume DCS terminator */
+        ACTION_DCS_DISPATCH,    /* dispatch DCS sequence */
+        ACTION_OSC_START,       /* start of OSC data */
+        ACTION_OSC_COLLECT,     /* collect OSC data */
+        ACTION_OSC_CONSUME,     /* consume OSC terminator */
+        ACTION_OSC_DISPATCH,    /* dispatch OSC sequence */
         ACTION_N,
 };
 
@@ -1006,7 +1013,7 @@ static inline void parser_clear(struct vte_parser *parser)
         parser->seq.st[0] = 0;
 }
 
-static int parser_ignore(struct vte_parser *parser, u32 raw)
+static int parser_ignore(struct vte_parser *parser, uint32_t raw)
 {
         parser_clear(parser);
         parser->seq.type = VTE_SEQ_IGNORE;
@@ -1017,7 +1024,7 @@ static int parser_ignore(struct vte_parser *parser, u32 raw)
         return parser->seq.type;
 }
 
-static int parser_print(struct vte_parser *parser, u32 raw)
+static int parser_print(struct vte_parser *parser, uint32_t raw)
 {
         parser_clear(parser);
         parser->seq.type = VTE_SEQ_GRAPHIC;
@@ -1028,7 +1035,7 @@ static int parser_print(struct vte_parser *parser, u32 raw)
         return parser->seq.type;
 }
 
-static int parser_execute(struct vte_parser *parser, u32 raw)
+static int parser_execute(struct vte_parser *parser, uint32_t raw)
 {
         parser_clear(parser);
         parser->seq.type = VTE_SEQ_CONTROL;
@@ -1040,7 +1047,7 @@ static int parser_execute(struct vte_parser *parser, u32 raw)
         return parser->seq.type;
 }
 
-static void parser_collect(struct vte_parser *parser, u32 raw)
+static void parser_collect(struct vte_parser *parser, uint32_t raw)
 {
         /*
          * Usually, characters from 0x30 to 0x3f are only allowed as leading
@@ -1055,7 +1062,7 @@ static void parser_collect(struct vte_parser *parser, u32 raw)
                 parser->seq.intermediates |= 1 << (raw - 0x20);
 }
 
-static void parser_param(struct vte_parser *parser, u32 raw)
+static void parser_param(struct vte_parser *parser, uint32_t raw)
 {
         if (raw == ';') {
                 if (parser->seq.n_args < VTE_PARSER_ARG_MAX)
@@ -1086,7 +1093,7 @@ static void parser_param(struct vte_parser *parser, u32 raw)
         }
 }
 
-static int parser_esc(struct vte_parser *parser, u32 raw)
+static int parser_esc(struct vte_parser *parser, uint32_t raw)
 {
         parser->seq.type = VTE_SEQ_ESCAPE;
         parser->seq.command = VTE_CMD_NONE;
@@ -1098,7 +1105,7 @@ static int parser_esc(struct vte_parser *parser, u32 raw)
         return parser->seq.type;
 }
 
-static int parser_csi(struct vte_parser *parser, u32 raw)
+static int parser_csi(struct vte_parser *parser, uint32_t raw)
 {
         /* parser->seq is cleared during CSI-ENTER state, thus there's no need
          * to clear invalid fields here. */
@@ -1120,7 +1127,7 @@ static int parser_csi(struct vte_parser *parser, u32 raw)
 
 /* perform state transition and dispatch related actions */
 static int parser_transition(struct vte_parser *parser,
-                             u32 raw,
+                             uint32_t raw,
                              unsigned int state,
                              unsigned int action)
 {
@@ -1179,7 +1186,7 @@ static int parser_transition(struct vte_parser *parser,
         }
 }
 
-static int parser_feed_to_state(struct vte_parser *parser, u32 raw)
+static int parser_feed_to_state(struct vte_parser *parser, uint32_t raw)
 {
         switch (parser->state) {
         case STATE_NONE:
@@ -1513,8 +1520,8 @@ static int parser_feed_to_state(struct vte_parser *parser, u32 raw)
 }
 
 int vte_parser_feed(struct vte_parser *parser,
-                       const struct vte_seq **seq_out,
-                       u32 raw)
+                    /* const */ struct vte_seq **seq_out,
+                    uint32_t raw)
 {
         int ret;
 
@@ -1569,10 +1576,16 @@ int vte_parser_feed(struct vte_parser *parser,
                 break;
         }
 
-        if (ret <= 0)
+        if (G_UNLIKELY(ret < 0))
                 *seq_out = NULL;
         else
                 *seq_out = &parser->seq;
 
         return ret;
 }
+
+void vte_parser_reset(struct vte_parser *parser)
+{
+        /* const */ struct vte_seq *seq;
+        vte_parser_feed(parser, &seq, 0x18 /* CAN */);
+}
diff --git a/src/parser.hh b/src/parser.hh
index 55e162b..ed357ba 100644
--- a/src/parser.hh
+++ b/src/parser.hh
@@ -1,19 +1,24 @@
 /*
  * Copyright © 2015 David Herrmann <dh herrmann gmail com>
  *
- * vte 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 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/>.
  */
 
 #pragma once
 
 #include <cstdint>
-
-typedef uint8_t u8;
-typedef uint32_t u32;
-typedef uint64_t u64;
+#include <cstdio>
 
 struct vte_parser;
 struct vte_seq;
@@ -40,16 +45,16 @@ extern vte_charset vte_dec_special_graphics;
  */
 
 struct vte_utf8 {
-        u32 chars[5];
-        u32 ucs4;
+        uint32_t chars[5];
+        uint32_t ucs4;
 
         unsigned int i_bytes : 3;
         unsigned int n_bytes : 3;
         unsigned int valid : 1;
 };
 
-size_t vte_utf8_decode(struct vte_utf8 *p, const u32 **out_buf, char c);
-size_t vte_utf8_encode(char *out_utf8, u32 g);
+size_t vte_utf8_decode(struct vte_utf8 *p, const uint32_t **out_buf, char c);
+size_t vte_utf8_encode(char *out_utf8, uint32_t g);
 
 /*
  * Parsers
@@ -107,185 +112,11 @@ enum {
 };
 
 enum {
-        VTE_CMD_NONE,                /* placeholder */
-        VTE_CMD_GRAPHIC,                /* graphics character */
-
-        VTE_CMD_BEL,                        /* bell */
-        VTE_CMD_BS,                        /* backspace */
-        VTE_CMD_CBT,                        /* cursor-backward-tabulation */
-        VTE_CMD_CHA,                        /* cursor-horizontal-absolute */
-        VTE_CMD_CHT,                        /* cursor-horizontal-forward-tabulation */
-        VTE_CMD_CNL,                        /* cursor-next-line */
-        VTE_CMD_CPL,                        /* cursor-previous-line */
-        VTE_CMD_CR,                        /* carriage-return */
-        VTE_CMD_CUB,                        /* cursor-backward */
-        VTE_CMD_CUD,                        /* cursor-down */
-        VTE_CMD_CUF,                        /* cursor-forward */
-        VTE_CMD_CUP,                        /* cursor-position */
-        VTE_CMD_CUU,                        /* cursor-up */
-        VTE_CMD_DA1,                        /* primary-device-attributes */
-        VTE_CMD_DA2,                        /* secondary-device-attributes */
-        VTE_CMD_DA3,                        /* tertiary-device-attributes */
-        VTE_CMD_DC1,                        /* device-control-1 or XON */
-        VTE_CMD_DC3,                        /* device-control-3 or XOFF */
-        VTE_CMD_DCH,                        /* delete-character */
-        VTE_CMD_DECALN,                /* screen-alignment-pattern */
-        VTE_CMD_DECANM,                /* ansi-mode */
-        VTE_CMD_DECBI,                /* back-index */
-        VTE_CMD_DECCARA,                /* change-attributes-in-rectangular-area */
-        VTE_CMD_DECCRA,                /* copy-rectangular-area */
-        VTE_CMD_DECDC,                /* delete-column */
-        VTE_CMD_DECDHL_BH,                /* double-width-double-height-line: bottom half */
-        VTE_CMD_DECDHL_TH,                /* double-width-double-height-line: top half */
-        VTE_CMD_DECDWL,                /* double-width-single-height-line */
-        VTE_CMD_DECEFR,                /* enable-filter-rectangle */
-        VTE_CMD_DECELF,                /* enable-local-functions */
-        VTE_CMD_DECELR,                /* enable-locator-reporting */
-        VTE_CMD_DECERA,                /* erase-rectangular-area */
-        VTE_CMD_DECFI,                /* forward-index */
-        VTE_CMD_DECFRA,                /* fill-rectangular-area */
-        VTE_CMD_DECIC,                /* insert-column */
-        VTE_CMD_DECID,                /* return-terminal-id */
-        VTE_CMD_DECINVM,                /* invoke-macro */
-        VTE_CMD_DECKBD,                /* keyboard-language-selection */
-        VTE_CMD_DECKPAM,                /* keypad-application-mode */
-        VTE_CMD_DECKPNM,                /* keypad-numeric-mode */
-        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_DECPKA,                /* program-key-action */
-        VTE_CMD_DECPKFMR,                /* program-key-free-memory-report */
-        VTE_CMD_DECRARA,                /* reverse-attributes-in-rectangular-area */
-        VTE_CMD_DECRC,                /* restore-cursor */
-        VTE_CMD_DECREQTPARM,                /* request-terminal-parameters */
-        VTE_CMD_DECRPKT,                /* report-key-type */
-        VTE_CMD_DECRQCRA,                /* request-checksum-of-rectangular-area */
-        VTE_CMD_DECRQDE,                /* request-display-extent */
-        VTE_CMD_DECRQKT,                /* request-key-type */
-        VTE_CMD_DECRQLP,                /* request-locator-position */
-        VTE_CMD_DECRQM_ANSI,                /* request-mode-ansi */
-        VTE_CMD_DECRQM_DEC,                /* request-mode-dec */
-        VTE_CMD_DECRQPKFM,                /* request-program-key-free-memory */
-        VTE_CMD_DECRQPSR,                /* request-presentation-state-report */
-        VTE_CMD_DECRQTSR,                /* request-terminal-state-report */
-        VTE_CMD_DECRQUPSS,                /* request-user-preferred-supplemental-set */
-        VTE_CMD_DECSACE,                /* select-attribute-change-extent */
-        VTE_CMD_DECSASD,                /* select-active-status-display */
-        VTE_CMD_DECSC,                /* save-cursor */
-        VTE_CMD_DECSCA,                /* select-character-protection-attribute */
-        VTE_CMD_DECSCL,                /* select-conformance-level */
-        VTE_CMD_DECSCP,                /* select-communication-port */
-        VTE_CMD_DECSCPP,                /* select-columns-per-page */
-        VTE_CMD_DECSCS,                /* select-communication-speed */
-        VTE_CMD_DECSCUSR,                /* set-cursor-style */
-        VTE_CMD_DECSDDT,                /* select-disconnect-delay-time */
-        VTE_CMD_DECSDPT,                /* select-digital-printed-data-type */
-        VTE_CMD_DECSED,                /* selective-erase-in-display */
-        VTE_CMD_DECSEL,                /* selective-erase-in-line */
-        VTE_CMD_DECSERA,                /* selective-erase-rectangular-area */
-        VTE_CMD_DECSFC,                /* select-flow-control */
-        VTE_CMD_DECSKCV,                /* set-key-click-volume */
-        VTE_CMD_DECSLCK,                /* set-lock-key-style */
-        VTE_CMD_DECSLE,                /* select-locator-events */
-        VTE_CMD_DECSLPP,                /* set-lines-per-page */
-        VTE_CMD_DECSLRM_OR_SC,        /* set-left-and-right-margins or save-cursor */
-        VTE_CMD_DECSMBV,                /* set-margin-bell-volume */
-        VTE_CMD_DECSMKR,                /* select-modifier-key-reporting */
-        VTE_CMD_DECSNLS,                /* set-lines-per-screen */
-        VTE_CMD_DECSPP,                /* set-port-parameter */
-        VTE_CMD_DECSPPCS,                /* select-pro-printer-character-set */
-        VTE_CMD_DECSPRTT,                /* select-printer-type */
-        VTE_CMD_DECSR,                /* secure-reset */
-        VTE_CMD_DECSRFR,                /* select-refresh-rate */
-        VTE_CMD_DECSSCLS,                /* set-scroll-speed */
-        VTE_CMD_DECSSDT,                /* select-status-display-line-type */
-        VTE_CMD_DECSSL,                /* select-setup-language */
-        VTE_CMD_DECST8C,                /* set-tab-at-every-8-columns */
-        VTE_CMD_DECSTBM,                /* set-top-and-bottom-margins */
-        VTE_CMD_DECSTR,                /* soft-terminal-reset */
-        VTE_CMD_DECSTRL,                /* set-transmit-rate-limit */
-        VTE_CMD_DECSWBV,                /* set-warning-bell-volume */
-        VTE_CMD_DECSWL,                /* single-width-single-height-line */
-        VTE_CMD_DECTID,                /* select-terminal-id */
-        VTE_CMD_DECTME,                /* terminal-mode-emulation */
-        VTE_CMD_DECTST,                /* invoke-confidence-test */
-        VTE_CMD_DL,                        /* delete-line */
-        VTE_CMD_DSR_ANSI,                /* device-status-report-ansi */
-        VTE_CMD_DSR_DEC,                /* device-status-report-dec */
-        VTE_CMD_ECH,                        /* erase-character */
-        VTE_CMD_ED,                        /* erase-in-display */
-        VTE_CMD_EL,                        /* erase-in-line */
-        VTE_CMD_ENQ,                        /* enquiry */
-        VTE_CMD_EPA,                        /* end-of-guarded-area */
-        VTE_CMD_FF,                        /* form-feed */
-        VTE_CMD_HPA,                        /* horizontal-position-absolute */
-        VTE_CMD_HPR,                        /* horizontal-position-relative */
-        VTE_CMD_HT,                        /* horizontal-tab */
-        VTE_CMD_HTS,                        /* horizontal-tab-set */
-        VTE_CMD_HVP,                        /* horizontal-and-vertical-position */
-        VTE_CMD_ICH,                        /* insert-character */
-        VTE_CMD_IL,                        /* insert-line */
-        VTE_CMD_IND,                        /* index */
-        VTE_CMD_LF,                        /* line-feed */
-        VTE_CMD_LS1R,                /* locking-shift-1-right */
-        VTE_CMD_LS2,                        /* locking-shift-2 */
-        VTE_CMD_LS2R,                /* locking-shift-2-right */
-        VTE_CMD_LS3,                        /* locking-shift-3 */
-        VTE_CMD_LS3R,                /* locking-shift-3-right */
-        VTE_CMD_MC_ANSI,                /* media-copy-ansi */
-        VTE_CMD_MC_DEC,                /* media-copy-dec */
-        VTE_CMD_NEL,                        /* next-line */
-        VTE_CMD_NP,                        /* next-page */
-        VTE_CMD_NULL,                /* null */
-        VTE_CMD_PP,                        /* preceding-page */
-        VTE_CMD_PPA,                        /* page-position-absolute */
-        VTE_CMD_PPB,                        /* page-position-backward */
-        VTE_CMD_PPR,                        /* page-position-relative */
-        VTE_CMD_RC,                        /* restore-cursor */
-        VTE_CMD_REP,                        /* repeat */
-        VTE_CMD_RI,                        /* reverse-index */
-        VTE_CMD_RIS,                        /* reset-to-initial-state */
-        VTE_CMD_RM_ANSI,                /* reset-mode-ansi */
-        VTE_CMD_RM_DEC,                /* reset-mode-dec */
-        VTE_CMD_S7C1T,                /* set-7bit-c1-terminal */
-        VTE_CMD_S8C1T,                /* set-8bit-c1-terminal */
-        VTE_CMD_SCS,                        /* select-character-set */
-        VTE_CMD_SD,                        /* scroll-down */
-        VTE_CMD_SGR,                        /* select-graphics-rendition */
-        VTE_CMD_SI,                        /* shift-in */
-        VTE_CMD_SM_ANSI,                /* set-mode-ansi */
-        VTE_CMD_SM_DEC,                /* set-mode-dec */
-        VTE_CMD_SO,                        /* shift-out */
-        VTE_CMD_SPA,                        /* start-of-protected-area */
-        VTE_CMD_SS2,                        /* single-shift-2 */
-        VTE_CMD_SS3,                        /* single-shift-3 */
-        VTE_CMD_ST,                        /* string-terminator */
-        VTE_CMD_SU,                        /* scroll-up */
-        VTE_CMD_SUB,                        /* substitute */
-        VTE_CMD_TBC,                        /* tab-clear */
-        VTE_CMD_VPA,                        /* vertical-line-position-absolute */
-        VTE_CMD_VPR,                        /* vertical-line-position-relative */
-        VTE_CMD_VT,                        /* vertical-tab */
-        VTE_CMD_XTERM_CLLHP,                /* xterm-cursor-lower-left-hp-bugfix */
-        VTE_CMD_XTERM_IHMT,                /* xterm-initiate-highlight-mouse-tracking */
-        VTE_CMD_XTERM_MLHP,                /* xterm-memory-lock-hp-bugfix */
-        VTE_CMD_XTERM_MUHP,                /* xterm-memory-unlock-hp-bugfix */
-        VTE_CMD_XTERM_RPM,                /* xterm-restore-private-mode */
-        VTE_CMD_XTERM_RRV,                /* xterm-reset-resource-value */
-        VTE_CMD_XTERM_RTM,                /* xterm-reset-title-mode */
-        VTE_CMD_XTERM_SACL1,                /* xterm-set-ansi-conformance-level-1 */
-        VTE_CMD_XTERM_SACL2,                /* xterm-set-ansi-conformance-level-2 */
-        VTE_CMD_XTERM_SACL3,                /* xterm-set-ansi-conformance-level-3 */
-        VTE_CMD_XTERM_SDCS,                /* xterm-set-default-character-set */
-        VTE_CMD_XTERM_SGFX,                /* xterm-sixel-graphics */
-        VTE_CMD_XTERM_SPM,                /* xterm-set-private-mode */
-        VTE_CMD_XTERM_SRV,                /* xterm-set-resource-value */
-        VTE_CMD_XTERM_STM,                /* xterm-set-title-mode */
-        VTE_CMD_XTERM_SUCS,                /* xterm-set-utf8-character-set */
-        VTE_CMD_XTERM_WM,                /* xterm-window-management */
+#define _VTE_CMD(cmd) VTE_CMD_##cmd,
+#include "parser-cmd.hh"
+#undef _VTE_CMD
 
-        VTE_CMD_N,
+        VTE_CMD_N
 };
 
 enum {
@@ -346,7 +177,7 @@ enum {
 struct vte_seq {
         unsigned int type;
         unsigned int command;
-        u32 terminator;
+        uint32_t terminator;
         unsigned int intermediates;
         unsigned int charset;
         unsigned int n_args;
@@ -358,5 +189,6 @@ struct vte_seq {
 int vte_parser_new(struct vte_parser **out);
 struct vte_parser *vte_parser_free(struct vte_parser *parser);
 int vte_parser_feed(struct vte_parser *parser,
-                    const struct vte_seq **seq_out,
-                    u32 raw);
+                    /* const */ struct vte_seq **seq_out,
+                    uint32_t raw);
+void vte_parser_reset(struct vte_parser *parser);
diff --git a/src/table.cc b/src/table.cc
index 9621dfe..aca5c54 100644
--- a/src/table.cc
+++ b/src/table.cc
@@ -209,7 +209,7 @@ _vte_table_addi(struct _vte_table *table,
        /* If this is the terminal node, set the result. */
        if (length == 0) {
                if (table->handler)
-                        _VTE_DEBUG_IF (VTE_DEBUG_PARSE) {
+                        _VTE_DEBUG_IF (VTE_DEBUG_PARSER) {
                                 g_printerr ("'%s'",
                                             _vte_debug_sequence_to_string ((const char *)table->original,
                                                                            table->original_length));
@@ -678,7 +678,7 @@ _vte_table_match(struct _vte_table *table,
                                                                  arginfo);
                                        p++;
                                } else {
-                                       _vte_debug_print (VTE_DEBUG_PARSE,
+                                       _vte_debug_print (VTE_DEBUG_PARSER,
                                                           "Invalid sequence %s\n",
                                                          original);
                                }
diff --git a/src/table.hh b/src/table.hh
index 3e9171d..bb6fa22 100644
--- a/src/table.hh
+++ b/src/table.hh
@@ -21,6 +21,7 @@
 #pragma once
 
 #include <glib-object.h>
+#include "matcher.hh"
 
 struct _vte_table;
 
diff --git a/src/vte.cc b/src/vte.cc
index 30ade8f..7836a07 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -62,7 +62,6 @@
 #include "iso2022.h"
 #include "keymap.h"
 #include "marshal.h"
-#include "matcher.hh"
 #include "vteaccess.h"
 #include "vtepty.h"
 #include "vtepty-private.h"
@@ -2924,7 +2923,7 @@ VteTerminalPrivate::save_cursor(VteScreen *screen__)
 }
 
 /* Insert a single character into the stored data array. */
-bool
+void
 VteTerminalPrivate::insert_char(gunichar c,
                                 bool insert,
                                 bool invalidate_now)
@@ -2937,7 +2936,7 @@ VteTerminalPrivate::insert_char(gunichar c,
         gunichar c_unmapped = c;
 
         /* DEC Special Character and Line Drawing Set.  VT100 and higher (per XTerm docs). */
-        static gunichar line_drawing_map[31] = {
+        static const gunichar line_drawing_map[31] = {
                 0x25c6,  /* ` => diamond */
                 0x2592,  /* a => checkerboard */
                 0x2409,  /* b => HT symbol */
@@ -3008,13 +3007,17 @@ VteTerminalPrivate::insert_char(gunichar c,
                line_wrapped = true;
        }
 
-       _vte_debug_print(VTE_DEBUG_PARSE,
-                       "Inserting %ld '%c' (colors %" G_GUINT64_FORMAT ") (%ld+%d, %ld), delta = %ld; ",
-                       (long)c, c < 256 ? c : ' ',
+       _vte_debug_print(VTE_DEBUG_PARSER,
+                       "Inserting U+%04X '%lc' (colors %" G_GUINT64_FORMAT ") (%ld+%d, %ld), delta = %ld; ",
+                         (unsigned int)c, g_unichar_isprint(c) ? c : 0xfffd,
                          m_color_defaults.attr.colors(),
                         col, columns, (long)m_screen->cursor.row,
                        (long)m_screen->insert_delta);
 
+        //FIXMEchpe
+        if (G_UNLIKELY(c == 0))
+                goto not_inserted;
+
        if (G_UNLIKELY (columns == 0)) {
 
                /* It's a combining mark */
@@ -3022,7 +3025,7 @@ VteTerminalPrivate::insert_char(gunichar c,
                long row_num;
                VteCell *cell;
 
-               _vte_debug_print(VTE_DEBUG_PARSE, "combining U+%04X", c);
+               _vte_debug_print(VTE_DEBUG_PARSER, "combining U+%04X", c);
 
                 row_num = m_screen->cursor.row;
                row = NULL;
@@ -3135,10 +3138,11 @@ done:
        m_text_inserted_flag = TRUE;
 
 not_inserted:
-       _vte_debug_print(VTE_DEBUG_ADJ|VTE_DEBUG_PARSE,
+       _vte_debug_print(VTE_DEBUG_ADJ|VTE_DEBUG_PARSER,
                        "insertion delta => %ld.\n",
                        (long)m_screen->insert_delta);
-       return line_wrapped;
+
+        m_line_wrapped = line_wrapped;
 }
 
 static void
@@ -3491,9 +3495,9 @@ VteTerminalPrivate::process_incoming()
        gboolean saved_cursor_visible;
         VteCursorStyle saved_cursor_style;
        GdkPoint bbox_topleft, bbox_bottomright;
-       gunichar *wbuf, c;
-       long wcount, start;
-       gboolean leftovers, modified, bottom, again;
+       gunichar *wbuf;
+       gsize wcount;
+       gboolean modified, bottom;
        gboolean invalidated_text;
        gboolean in_scroll_region;
        GArray *unichars;
@@ -3593,151 +3597,60 @@ skip_chunk:
        wbuf = &g_array_index(unichars, gunichar, 0);
        wcount = unichars->len;
 
-       /* Try initial substrings. */
-       start = 0;
-       modified = leftovers = again = FALSE;
+       modified = FALSE;
        invalidated_text = FALSE;
 
        bbox_bottomright.x = bbox_bottomright.y = -G_MAXINT;
        bbox_topleft.x = bbox_topleft.y = G_MAXINT;
 
-       while (start < wcount && !leftovers) {
-               const gunichar *next;
-                vte::parser::Params params{nullptr};
-
-               /* Try to match any control sequences. */
-                sequence_handler_t handler = nullptr;
-                auto match_result = _vte_matcher_match(m_matcher,
-                                                       &wbuf[start],
-                                                       wcount - start,
-                                                       &handler,
-                                                       &next,
-                                                       &params.m_values);
-                switch (match_result) {
-               /* We're in one of three possible situations now.
-                * First, the match returned a handler, and next
-                * points to the first character which isn't part of this
-                * sequence. */
-                case VTE_MATCHER_RESULT_MATCH: {
-                        _VTE_DEBUG_IF(VTE_DEBUG_PARSE)
-                                params.print();
-
-                       /* Call the sequence handler */
-                        (this->*handler)(params);
+        vte::parser::Sequence seq{};
 
-                        m_last_graphic_character = 0;
-
-                       /* Skip over the proper number of unicode chars. */
-                       start = (next - wbuf);
-                       modified = TRUE;
+        m_line_wrapped = false;
 
-                        // FIXME m_screen may be != previous_screen, check for that!
+        auto const *wp = wbuf;
+        auto const* wend = wbuf + wcount;
+        for ( ; wp < wend; ++wp) {
 
-                        gboolean new_in_scroll_region = m_scrolling_restricted
-                            && (m_screen->cursor.row >= (m_screen->insert_delta + m_scrolling_region.start))
-                            && (m_screen->cursor.row <= (m_screen->insert_delta + m_scrolling_region.end));
-
-                        /* delta may have changed from sequence. */
-                        top_row = first_displayed_row();
-                        bottom_row = last_displayed_row();
-
-                       /* if we have moved greatly during the sequence handler, or moved
-                         * into a scroll_region from outside it, restart the bbox.
-                         */
-                       if (invalidated_text &&
-                                       ((new_in_scroll_region && !in_scroll_region) ||
-                                         (m_screen->cursor.col > bbox_bottomright.x + VTE_CELL_BBOX_SLACK ||
-                                          m_screen->cursor.col < bbox_topleft.x - VTE_CELL_BBOX_SLACK     ||
-                                          m_screen->cursor.row > bbox_bottomright.y + VTE_CELL_BBOX_SLACK ||
-                                          m_screen->cursor.row < bbox_topleft.y - VTE_CELL_BBOX_SLACK))) {
-                               /* Clip off any part of the box which isn't already on-screen. */
-                               bbox_topleft.x = MAX(bbox_topleft.x, 0);
-                                bbox_topleft.y = MAX(bbox_topleft.y, top_row);
-                               bbox_bottomright.x = MIN(bbox_bottomright.x,
-                                               m_column_count);
-                               /* lazily apply the +1 to the cursor_row */
-                               bbox_bottomright.y = MIN(bbox_bottomright.y + 1,
-                                                bottom_row + 1);
+                auto rv = vte_parser_feed(m_parser, seq.seq_ptr(), *wp);
+                if (G_UNLIKELY(rv < 0)) {
+                        char c_buf[7];
+                        g_snprintf(c_buf, sizeof(c_buf), "%lc", *wp);
+                        char const* wp_str = g_unichar_isprint(*wp) ? c_buf : 
_vte_debug_sequence_to_string(c_buf, -1);
+                        _vte_debug_print(VTE_DEBUG_PARSER, "Parser error on U+%04X [%s]!\n",
+                                         *wp, wp_str);
+                        break;
+                }
 
-                               invalidate_cells(
-                                               bbox_topleft.x,
-                                               bbox_bottomright.x - bbox_topleft.x,
-                                               bbox_topleft.y,
-                                               bbox_bottomright.y - bbox_topleft.y);
+                if (rv != VTE_SEQ_NONE)
+                        g_assert((bool)seq);
 
-                               invalidated_text = FALSE;
-                               bbox_bottomright.x = bbox_bottomright.y = -G_MAXINT;
-                               bbox_topleft.x = bbox_topleft.y = G_MAXINT;
-                       }
+                _VTE_DEBUG_IF(VTE_DEBUG_PARSER) {
+                        if (rv != VTE_SEQ_NONE) {
+                                seq.print();
+                        }
+                }
 
-                       in_scroll_region = new_in_scroll_region;
+                // FIXMEchpe this assumes that the only handler inserting
+                // a character is GRAPHIC, which isn't true (at least ICH, REP, SUB
+                // also do, and invalidate directly for now)...
 
-                        break;
-               }
-               /* Second, we have no match, and next points to the very
-                * next character in the buffer.  Insert the character which
-                * we're currently examining into the screen. */
-               case VTE_MATCHER_RESULT_NO_MATCH: {
-                       c = wbuf[start];
-                       /* If it's a control character, permute the order, per
-                        * vttest. */
-                       if ((c != *next) &&
-                           ((*next & 0x1f) == *next) &&
-                            //FIXMEchpe what about C1 controls
-                           (start + 1 < next - wbuf)) {
-                               const gunichar *tnext = NULL;
-                               gunichar ctrl;
-                               int i;
-                               /* We don't want to permute it if it's another
-                                * control sequence, so check if it is. */
-                                sequence_handler_t thandler;
-                               _vte_matcher_match(m_matcher,
-                                                  next,
-                                                  wcount - (next - wbuf),
-                                                   &thandler,
-                                                  &tnext,
-                                                  NULL);
-                               /* We only do this for non-control-sequence
-                                * characters and random garbage. */
-                               if (tnext == next + 1) {
-                                       /* Save the control character. */
-                                       ctrl = *next;
-                                       /* Move everything before it up a
-                                        * slot.  */
-                                        // FIXMEchpe memmove!
-                                       for (i = next - wbuf; i > start; i--) {
-                                               wbuf[i] = wbuf[i - 1];
-                                       }
-                                       /* Move the control character to the
-                                        * front. */
-                                       wbuf[i] = ctrl;
-                                       goto next_match;
-                               }
-                       }
-                       _VTE_DEBUG_IF(VTE_DEBUG_PARSE) {
-                                if (c > 255) {
-                                        g_printerr("U+%04lx\n", (long) c);
-                               } else {
-                                        if (c > 127) {
-                                               g_printerr("%ld = ",
-                                                                (long) c);
-                                       }
-                                        if (c < 32) {
-                                               g_printerr("^%c\n", c + 64);
-                                       } else {
-                                               g_printerr("`%c'\n", c);
-                                       }
-                               }
-                       }
+                switch (rv) {
+                case VTE_SEQ_GRAPHIC: {
 
                        bbox_topleft.x = MIN(bbox_topleft.x,
                                              m_screen->cursor.col);
                        bbox_topleft.y = MIN(bbox_topleft.y,
                                              m_screen->cursor.row);
 
-                       /* Insert the character. */
-                        // FIXMEchpe should not use UNLIKELY here
-                       if (G_UNLIKELY(insert_char(c, false, false))) {
+                       // does insert_char(c, false, false)
+                        GRAPHIC(seq);
+                        _vte_debug_print(VTE_DEBUG_PARSER,
+                                         "Last graphic is now U+%04X %lc\n",
+                                         m_last_graphic_character,
+                                         g_unichar_isprint(m_last_graphic_character) ? 
m_last_graphic_character : 0xfffd);
+
+                        if (m_line_wrapped) {
+                                m_line_wrapped = false;
                                /* line wrapped, correct bbox */
                                if (invalidated_text &&
                                                 (m_screen->cursor.col > bbox_bottomright.x + 
VTE_CELL_BBOX_SLACK       ||
@@ -3777,30 +3690,68 @@ skip_chunk:
 
                        /* We *don't* emit flush pending signals here. */
                        modified = TRUE;
-                       start++;
 
                         break;
-               }
-                case VTE_MATCHER_RESULT_PARTIAL: {
-                       /* Case three: the read broke in the middle of a
-                        * control sequence, so we're undecided with no more
-                        * data to consult. If we have data following the
-                        * middle of the sequence, then it's just garbage data,
-                        * and for compatibility, we should discard it. */
-                       if (wbuf + wcount > next) {
-                               _vte_debug_print(VTE_DEBUG_PARSE,
-                                               "Invalid control "
-                                               "sequence, discarding %ld "
-                                               "characters.\n",
-                                               (long)(next - (wbuf + start)));
-                               /* Discard. */
-                               start = next - wbuf + 1;
-                       } else {
-                               /* Pause processing here and wait for more
-                                * data before continuing. */
-                               leftovers = TRUE;
+                }
+                case VTE_SEQ_NONE:
+                case VTE_SEQ_IGNORE:
+                        break;
+                default: {
+                        switch (seq.command()) {
+#define _VTE_CMD(cmd)   case VTE_CMD_##cmd: cmd(seq); break;
+#include "parser-cmd.hh"
+#undef _VTE_CMD
+                        default:
+                                _vte_debug_print(VTE_DEBUG_PARSER,
+                                                 "Unknown parser command %d\n", seq.command());
+                                break;
+                        }
+
+                        m_last_graphic_character = 0;
+
+                       modified = TRUE;
+
+                        // FIXME m_screen may be != previous_screen, check for that!
+
+                        gboolean new_in_scroll_region = m_scrolling_restricted
+                            && (m_screen->cursor.row >= (m_screen->insert_delta + m_scrolling_region.start))
+                            && (m_screen->cursor.row <= (m_screen->insert_delta + m_scrolling_region.end));
+
+                        /* delta may have changed from sequence. */
+                        top_row = first_displayed_row();
+                        bottom_row = last_displayed_row();
+
+                       /* if we have moved greatly during the sequence handler, or moved
+                         * into a scroll_region from outside it, restart the bbox.
+                         */
+                       if (invalidated_text &&
+                                       ((new_in_scroll_region && !in_scroll_region) ||
+                                         (m_screen->cursor.col > bbox_bottomright.x + VTE_CELL_BBOX_SLACK ||
+                                          m_screen->cursor.col < bbox_topleft.x - VTE_CELL_BBOX_SLACK     ||
+                                          m_screen->cursor.row > bbox_bottomright.y + VTE_CELL_BBOX_SLACK ||
+                                          m_screen->cursor.row < bbox_topleft.y - VTE_CELL_BBOX_SLACK))) {
+                               /* Clip off any part of the box which isn't already on-screen. */
+                               bbox_topleft.x = MAX(bbox_topleft.x, 0);
+                                bbox_topleft.y = MAX(bbox_topleft.y, top_row);
+                               bbox_bottomright.x = MIN(bbox_bottomright.x,
+                                               m_column_count);
+                               /* lazily apply the +1 to the cursor_row */
+                               bbox_bottomright.y = MIN(bbox_bottomright.y + 1,
+                                                bottom_row + 1);
+
+                               invalidate_cells(
+                                               bbox_topleft.x,
+                                               bbox_bottomright.x - bbox_topleft.x,
+                                               bbox_topleft.y,
+                                               bbox_bottomright.y - bbox_topleft.y);
+
+                               invalidated_text = FALSE;
+                               bbox_bottomright.x = bbox_bottomright.y = -G_MAXINT;
+                               bbox_topleft.x = bbox_topleft.y = G_MAXINT;
                        }
 
+                       in_scroll_region = new_in_scroll_region;
+
                         break;
                }
                 }
@@ -3814,15 +3765,11 @@ skip_chunk:
                 * part of the display buffer. */
                 g_assert_cmpint(m_screen->cursor.row, >=, m_screen->insert_delta);
 #endif
-
-next_match:
-                /* Free any parameters we don't care about any more. */
-                params.recycle(m_matcher);
        }
 
        /* Remove most of the processed characters. */
-       if (start < wcount) {
-               g_array_remove_range(m_pending, 0, start);
+       if (wp < wend) {
+               g_array_remove_range(m_pending, 0, wp - wbuf);
        } else {
                g_array_set_size(m_pending, 0);
                /* If we're out of data, we needn't pause to let the
@@ -8114,7 +8061,9 @@ VteTerminalPrivate::VteTerminalPrivate(VteTerminal *t) :
         m_autowrap = TRUE;
         m_sendrecv_mode = TRUE;
        m_dec_saved = g_hash_table_new(NULL, NULL);
-        m_matcher = _vte_matcher_new();
+
+        if (vte_parser_new(&m_parser) != 0)
+                g_assert_not_reached();
 
        /* Setting the terminal type and size requires the PTY master to
         * be set up properly first. */
@@ -8628,9 +8577,8 @@ VteTerminalPrivate::~VteTerminalPrivate()
        }
 
        /* Clean up emulation structures. */
-       if (m_matcher != NULL) {
-               _vte_matcher_free(m_matcher);
-       }
+        m_parser = vte_parser_free(m_parser);
+        g_assert_null(m_parser);
 
        remove_update_timeout(this);
 
@@ -10573,7 +10521,11 @@ VteTerminalPrivate::reset(bool clear_tabstops,
         m_iso2022 = _vte_iso2022_state_new(nullptr);
        _vte_iso2022_state_set_codeset(m_iso2022,
                                       m_encoding);
+
+        /* Reset parser */
+        vte_parser_reset(m_parser);
         m_last_graphic_character = 0;
+
        /* Reset keypad/cursor key modes. */
        m_keypad_mode = VTE_KEYMODE_NORMAL;
        m_cursor_mode = VTE_KEYMODE_NORMAL;
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index b174038..d529376 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -26,7 +26,8 @@
 #include "ring.h"
 #include "vteconv.h"
 #include "buffer.h"
-#include "matcher.hh"
+#include "parser.hh"
+#include "parser-glue.hh"
 
 #include "vtepcre2.h"
 #include "vteregexinternal.hh"
@@ -257,119 +258,6 @@ private:
         Request *m_request;
 };
 
-namespace vte {
-namespace parser {
-
-struct Params {
-
-        typedef long number;
-
-        char* ucs4_to_utf8(gunichar const* str) const;
-
-        void print() const;
-
-        inline unsigned int size() const
-        {
-                return G_LIKELY(m_values != nullptr) ? m_values->n_values : 0;
-        }
-
-        inline GValue* value_at_unchecked(unsigned int position) const
-        {
-                return g_value_array_get_nth(m_values, position);
-        }
-
-        inline bool has_number_at_unchecked(unsigned int position) const
-        {
-                return G_UNLIKELY(G_VALUE_HOLDS_LONG(value_at_unchecked(position)));
-        }
-
-        inline bool number_at_unchecked(unsigned int position, number& v) const
-        {
-                auto value = value_at_unchecked(position);
-                if (G_UNLIKELY(!G_VALUE_HOLDS(value, G_TYPE_LONG)))
-                        return false;
-
-                v = g_value_get_long(value);
-                return true;
-        }
-
-        inline bool number_at(unsigned int position, number& v) const
-        {
-                if (G_UNLIKELY(position >= size()))
-                        return false;
-
-                return number_at_unchecked(position, v);
-        }
-
-        inline number number_or_default_at_unchecked(unsigned int position, number default_v = 0) const
-        {
-                number v;
-                if (G_UNLIKELY(!number_at_unchecked(position, v)))
-                        v = default_v;
-                return v;
-        }
-
-
-        inline number number_or_default_at(unsigned int position, number default_v = 0) const
-        {
-                number v;
-                if (G_UNLIKELY(!number_at(position, v)))
-                        v = default_v;
-                return v;
-        }
-
-        inline bool string_at_unchecked(unsigned int position, char*& str) const
-        {
-                auto value = value_at_unchecked(position);
-                if (G_LIKELY(G_VALUE_HOLDS_POINTER(value))) {
-                        str = ucs4_to_utf8((gunichar const*)g_value_get_pointer (value));
-                        return str != nullptr;
-                }
-                if (G_VALUE_HOLDS_STRING(value)) {
-                        /* Copy the string into the buffer. */
-                        str = g_value_dup_string(value);
-                        return str != nullptr;
-                }
-                if (G_VALUE_HOLDS_LONG(value)) {
-                        /* Convert the long to a string. */
-                        str = g_strdup_printf("%ld", g_value_get_long(value));
-                        return true;
-                }
-                return false;
-        }
-
-        inline bool string_at(unsigned int position, char*& str) const
-        {
-                if (G_UNLIKELY(position >= size()))
-                        return false;
-
-                return string_at_unchecked(position, str);
-
-        }
-
-        inline bool has_subparams_at_unchecked(unsigned int position) const
-        {
-                return G_UNLIKELY(G_VALUE_HOLDS_BOXED(value_at_unchecked(position)));
-        }
-
-        inline Params subparams_at_unchecked(unsigned int position) const
-        {
-                return {(GValueArray*)g_value_get_boxed(value_at_unchecked(position))};
-        }
-
-        inline void recycle(struct _vte_matcher *matcher)
-        {
-                if (G_LIKELY(m_values != nullptr))
-                    _vte_matcher_free_params_array(matcher, m_values);
-        }
-
-        GValueArray *m_values;
-};
-
-} // namespace parser
-} // namespace vte
-
-
 /* Terminal private data. */
 class VteTerminalPrivate {
 public:
@@ -388,7 +276,8 @@ public:
         vte::grid::column_t m_column_count;
 
        /* Emulation setup data. */
-        struct _vte_matcher *m_matcher;   /* control sequence matcher */
+        struct vte_parser* m_parser; /* control sequence state machine */
+
         gboolean m_autowrap;              /* auto wraparound at right margin */
         int m_keypad_mode, m_cursor_mode; /* these would be VteKeymodes, but we
                                           need to guarantee its type */
@@ -720,7 +609,7 @@ public:
         void restore_cursor(VteScreen *screen__);
         void save_cursor(VteScreen *screen__);
 
-        bool insert_char(gunichar c,
+        void insert_char(gunichar c,
                          bool insert,
                          bool invalidate_now);
 
@@ -1336,8 +1225,8 @@ public:
         inline void line_feed();
         inline void set_current_hyperlink(char* hyperlink_params /* adopted */, char* uri /* adopted */);
         inline void set_keypad_mode(VteKeymode mode);
-        inline void erase_in_display(long param);
-        inline void erase_in_line(long param);
+        inline void erase_in_display(vte::parser::Sequence const& seq);
+        inline void erase_in_line(vte::parser::Sequence const& seq);
         inline void insert_lines(vte::grid::row_t param);
         inline void delete_lines(vte::grid::row_t param);
         inline void change_special_color(vte::parser::Params const& params,
@@ -1354,10 +1243,21 @@ public:
         void select_empty(vte::grid::column_t col,
                           vte::grid::row_t row);
 
-#define SEQUENCE_HANDLER(name) \
-       inline void seq_ ## name (vte::parser::Params const& params);
+        /* Sequence handlers */
+
+        /* old style */
+#define SEQUENCE_HANDLER(name)                                          \
+      inline void seq_ ## name (vte::parser::Params const& params);
 #include "vteseq-list.hh"
 #undef SEQUENCE_HANDLER
+
+        /* new parser */
+        bool m_line_wrapped; // signals line wrapped from character insertion
+        // Note: inlining the handlers seems to worsen the performance, so we don't do that
+#define _VTE_CMD(cmd) \
+       /* inline */ void cmd (vte::parser::Sequence const& seq);
+#include "parser-cmd.hh"
+#undef _VTE_CMD
 };
 
 extern GTimer *process_timer;
diff --git a/src/vteseq-str.hh b/src/vteseq-str.hh
new file mode 100644
index 0000000..cf56752
--- /dev/null
+++ b/src/vteseq-str.hh
@@ -0,0 +1,156 @@
+"ansi_conformance_level_1",
+"ansi_conformance_level_2",
+"ansi_conformance_level_3",
+"DECKPAM",
+"BS",
+"BEL",
+"CR",
+"change_background_color_bel",
+"change_background_color_st",
+"change_color_bel",
+"change_color_st",
+"change_cursor_background_color_bel",
+"change_cursor_background_color_st",
+"change_font_name",
+"change_font_number",
+"change_foreground_color_bel",
+"change_foreground_color_st",
+"change_highlight_background_color_bel",
+"change_highlight_background_color_st",
+"change_highlight_foreground_color_bel",
+"change_highlight_foreground_color_st",
+"change_logfile",
+"change_mouse_cursor_background_color_bel",
+"change_mouse_cursor_background_color_st",
+"change_mouse_cursor_foreground_color_bel",
+"change_mouse_cursor_foreground_color_st",
+"change_tek_background_color_bel",
+"change_tek_background_color_st",
+"change_tek_cursor_color_bel",
+"change_tek_cursor_color_st",
+"change_tek_foreground_color_bel",
+"change_tek_foreground_color_st",
+"SGR",
+"HPA",
+"CBT",
+"CUB",
+"CHA",
+"CUD",
+"CUF",
+"CHT",
+"cursor_lower_left",
+"CNL",
+"CUP",
+"CUP",
+"CPL",
+"CUU",
+"DSR_DEC",
+"dec_media_copy",
+"RM_DEC",
+"SM_DEC",
+"default_character_set",
+"DCH",
+"DL",
+"SCS",
+"SCS",
+"SCS",
+"SCS",
+"SCS",
+"SCS",
+"device_control_string",
+"DSR_ANSI",
+"double_height_bottom_half",
+"double_height_top_half",
+"double_width",
+"eight_bit_controls",
+"enable_filter_rectangle",
+"enable_locator_reporting",
+"end_of_guarded_area",
+"ECH",
+"ED",
+"EL",
+"FF",
+"RIS",
+"IND",
+"initiate_hilite_mouse_tracking",
+"ICH",
+"IL",
+"invoke_g1_character_set_as_gr",
+"invoke_g2_character_set",
+"invoke_g2_character_set_as_gr",
+"invoke_g3_character_set",
+"invoke_g3_character_set_as_gr",
+"iterm2_133",
+"iterm2_1337",
+"LF",
+"VPA",
+"linux_console_cursor_attributes",
+"media_copy",
+"memory_lock",
+"memory_unlock",
+"NEL",
+"nop",
+"DECKPNM",
+"REP",
+"request_locator_position",
+"DECREQTPARM",
+"reset_background_color",
+"reset_color",
+"reset_cursor_background_color",
+"reset_foreground_color",
+"reset_highlight_background_color",
+"reset_highlight_foreground_color",
+"RM_ANSI",
+"reset_mouse_cursor_background_color",
+"reset_mouse_cursor_foreground_color",
+"reset_tek_background_color",
+"reset_tek_cursor_color",
+"reset_tek_foreground_color",
+"DECRC",
+"XTERM_RPM",
+"DECID",
+"ENQ",
+"reverse_IND",
+"DECSC",
+"XTERM_SPM",
+"DECALN",
+"SD",
+"SU",
+"select_character_protection",
+"select_locator_events",
+"selective_ED",
+"selective_EL",
+"DA1",
+"DA2",
+"send_tertiary_device_attributes",
+"set_conformance_level",
+"set_current_directory_uri",
+"set_current_file_uri",
+"set_current_hyperlink",
+"DECSCUSR",
+"set_icon_and_window_title",
+"set_icon_title",
+"SM_ANSI",
+"DECSTBM",
+"DECSTBM",
+"DECSTBM",
+"set_text_property_21",
+"set_text_property_2L",
+"set_window_title",
+"set_xproperty",
+"seven_bit_controls",
+"SI",
+"SO",
+"single_shift_g2",
+"single_shift_g3",
+"single_width",
+"DECSTR",
+"start_of_guarded_area",
+"start_or_end_of_string",
+"HT",
+"TBC",
+"HT_set",
+"urxvt_777",
+"utf_8_character_set",
+"vertical_HT",
+"XTERM_WM",
diff --git a/src/vteseq.cc b/src/vteseq.cc
index 4da48c4..bea3ee8 100644
--- a/src/vteseq.cc
+++ b/src/vteseq.cc
@@ -1,10 +1,12 @@
 /*
- * Copyright (C) 2001-2004 Red Hat, Inc.
+ * Copyright © 2001-2004 Red Hat, Inc.
+ * Copyright © 2015 David Herrmann <dh herrmann gmail com>
+ * Copyright © 2008-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 2.1 of the License, or (at your option) any later version.
+ * 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
@@ -35,40 +37,71 @@
 #include "caps.hh"
 #include "debug.h"
 
-#define BEL "\007"
-#define ST _VTE_CAP_ST
+#define BEL_C0 "\007"
+#define ST_C0 _VTE_CAP_ST
 
 #include <algorithm>
 
 void
-vte::parser::Params::print() const
+vte::parser::Sequence::print() const
 {
 #ifdef VTE_DEBUG
-        g_printerr("(");
-        auto n_params = size();
-        for (unsigned int i = 0; i < n_params; i++) {
-                auto value = value_at_unchecked(i);
-                if (i > 0) {
-                        g_printerr(", ");
-                }
-                if (G_VALUE_HOLDS_LONG(value)) {
-                        auto l = g_value_get_long(value);
-                        g_printerr("LONG(%ld)", l);
-                } else if (G_VALUE_HOLDS_STRING(value)) {
-                        auto const s = g_value_get_string(value);
-                        g_printerr("STRING(\"%s\")", s);
-                } else if (G_VALUE_HOLDS_POINTER(value)) {
-                        auto w = (const gunichar *)g_value_get_pointer(value);
-                        g_printerr("WSTRING(\"%ls\")", (const wchar_t*) w);
-                } else if (G_VALUE_HOLDS_BOXED(value)) {
-                        vte::parser::Params subparams{(GValueArray*)g_value_get_boxed(value)};
-                        subparams.print();
+        auto c = m_seq != nullptr ? terminator() : 0;
+        char c_buf[7];
+        g_snprintf(c_buf, sizeof(c_buf), "%lc", c);
+        g_printerr("%s:%s [%s]", type_string(), command_string(),
+                   g_unichar_isprint(c) ? c_buf : _vte_debug_sequence_to_string(c_buf, -1));
+        if (m_seq != nullptr && m_seq->n_args > 0) {
+                g_printerr("[ ");
+                for (unsigned int i = 0; i < m_seq->n_args; i++) {
+                        if (i > 0)
+                                g_print(", ");
+                        g_printerr("%d", m_seq->args[i]);
                 }
-       }
-       g_printerr(")\n");
+                g_printerr(" ]");
+        }
+        g_printerr("\n");
 #endif
 }
 
+char const*
+vte::parser::Sequence::type_string() const
+{
+        if (G_UNLIKELY(m_seq == nullptr))
+                return "(nil)";
+
+        switch (type()) {
+        case VTE_SEQ_NONE:    return "NONE";
+        case VTE_SEQ_IGNORE:  return "IGNORE";
+        case VTE_SEQ_GRAPHIC: return "GRAPHIC";
+        case VTE_SEQ_CONTROL: return "CONTROL";
+        case VTE_SEQ_ESCAPE:  return "ESCAPE";
+        case VTE_SEQ_CSI:     return "CSI";
+        case VTE_SEQ_DCS:     return "DCS";
+        case VTE_SEQ_OSC:     return "OSC";
+        default:
+                g_assert(false);
+                return nullptr;
+        }
+}
+
+char const*
+vte::parser::Sequence::command_string() const
+{
+        if (G_UNLIKELY(m_seq == nullptr))
+                return "(nil)";
+
+        switch (command()) {
+#define _VTE_CMD(cmd) case VTE_CMD_##cmd: return #cmd;
+#include "parser-cmd.hh"
+#undef _VTE_CMD
+        default:
+                static char buf[32];
+                snprintf(buf, sizeof(buf), "UNKOWN(%u)", command());
+                return buf;
+        }
+}
+
 /* A couple are duplicated from vte.c, to keep them static... */
 
 /* Check how long a string of unichars is.  Slow version. */
@@ -85,7 +118,7 @@ vte_unichar_strlen(gunichar const* c)
  * length instead of walking the input twice.
  */
 char*
-vte::parser::Params::ucs4_to_utf8(gunichar const* str) const
+vte::parser::Sequence::ucs4_to_utf8(gunichar const* str) const
 {
         auto len = vte_unichar_strlen(str);
         auto outlen = (len * VTE_UTF8_BPC) + 1;
@@ -462,7 +495,7 @@ VteTerminalPrivate::set_mode(vte::parser::Params const& params,
                 return;
 
        for (unsigned int i = 0; i < n_params; i++) {
-                long setting;
+                int setting;
                 if (!params.number_at_unchecked(i, setting))
                         continue;
 
@@ -523,7 +556,7 @@ VteTerminalPrivate::decset(vte::parser::Params const& params,
 
         auto n_params = params.size();
         for (unsigned int i = 0; i < n_params; i++) {
-                long setting;
+                int setting;
 
                 if (!params.number_at(i, setting))
                         continue;
@@ -743,7 +776,7 @@ VteTerminalPrivate::decset(long setting,
                        p = g_hash_table_lookup(m_dec_saved,
                                                GINT_TO_POINTER(setting));
                        set = (p != NULL);
-                       _vte_debug_print(VTE_DEBUG_PARSE,
+                       _vte_debug_print(VTE_DEBUG_PARSER,
                                        "Setting %ld was %s.\n",
                                        setting, set ? "set" : "unset");
                }
@@ -758,7 +791,7 @@ VteTerminalPrivate::decset(long setting,
                        if (pvalue) {
                                set = *(pvalue) == ptvalue;
                        }
-                       _vte_debug_print(VTE_DEBUG_PARSE,
+                       _vte_debug_print(VTE_DEBUG_PARSER,
                                        "Setting %ld is %s, saving.\n",
                                        setting, set ? "set" : "unset");
                        g_hash_table_insert(m_dec_saved,
@@ -767,7 +800,7 @@ VteTerminalPrivate::decset(long setting,
                }
                /* Change the current setting to match the new/saved value. */
                if (!save) {
-                       _vte_debug_print(VTE_DEBUG_PARSE,
+                       _vte_debug_print(VTE_DEBUG_PARSER,
                                        "Setting %ld to %s.\n",
                                        setting, set ? "set" : "unset");
                        if (key.set && set) {
@@ -948,7 +981,7 @@ VteTerminalPrivate::seq_cursor_back_tab(vte::parser::Params const& params)
        }
 
        /* Warp the cursor. */
-       _vte_debug_print(VTE_DEBUG_PARSE,
+       _vte_debug_print(VTE_DEBUG_PARSER,
                        "Moving cursor to column %ld.\n", (long)newcol);
         set_cursor_column(newcol);
 }
@@ -1193,8 +1226,8 @@ void
 VteTerminalPrivate::seq_set_scrolling_region(vte::parser::Params const& params)
 {
        /* We require two parameters.  Anything less is a reset. */
-        if (params.size() < 2)
-                return reset_scrolling_region();
+        //        if (params.size() < 2)
+        //                return reset_scrolling_region();
 
         auto start = params.number_or_default_at_unchecked(0) - 1;
         auto end = params.number_or_default_at_unchecked(1) - 1;
@@ -1213,7 +1246,9 @@ VteTerminalPrivate::set_scrolling_region(vte::grid::row_t start /* relative */,
                 end = m_row_count - 1;
         }
         /* Bail out on garbage, require at least 2 rows, as per xterm. */
+        // FIXMEchpe
         if (start < 0 || start >= m_row_count - 1 || end < start + 1) {
+                reset_scrolling_region();
                 return;
         }
         if (end >= m_row_count) {
@@ -1307,8 +1342,8 @@ void
 VteTerminalPrivate::seq_delete_characters(vte::parser::Params const& params)
 {
         auto val = std::max(std::min(params.number_or_default_at(0, 1),
-                                     m_column_count - m_screen->cursor.col),
-                            long(1));
+                                     int(m_column_count - m_screen->cursor.col)),
+                            int(1));
         for (auto i = 0; i < val; i++)
                 delete_character();
 }
@@ -1346,7 +1381,7 @@ void
 VteTerminalPrivate::seq_erase_characters(vte::parser::Params const& params)
 {
        /* If we got a parameter, use it. */
-        auto count = std::min(params.number_or_default_at(0, 1), long(65535));
+        auto count = std::min(params.number_or_default_at(0, 1), int(65535));
         erase_characters(count);
 }
 
@@ -1413,8 +1448,8 @@ void
 VteTerminalPrivate::seq_insert_blank_characters(vte::parser::Params const& params)
 {
         auto val = std::max(std::min(params.number_or_default_at(0, 1),
-                                     m_column_count - m_screen->cursor.col),
-                            long(1));
+                                     int(m_column_count - m_screen->cursor.col)),
+                            int(1));
         for (auto i = 0; i < val; i++)
                 insert_blank_character();
 }
@@ -1424,7 +1459,7 @@ void
 VteTerminalPrivate::seq_repeat(vte::parser::Params const& params)
 {
         auto val = std::min(params.number_or_default_at(0, 1),
-                            long(65535)); // FIXMEchpe maybe limit more, to m_column_count - 
m_screen->cursor.col ?
+                            int(65535)); // FIXMEchpe maybe limit more, to m_column_count - 
m_screen->cursor.col ?
         for (auto i = 0; i < val; i++) {
                 // FIXMEchpe can't we move that check out of the loop?
                 if (m_last_graphic_character == 0)
@@ -1506,7 +1541,7 @@ void
 VteTerminalPrivate::seq_scroll_down(vte::parser::Params const& params)
 {
         /* No ensure_cursor_is_onscreen() here as per xterm */
-        auto val = std::max(params.number_or_default_at(0, 1), long(1));
+        auto val = std::max(params.number_or_default_at(0, 1), int(1));
         scroll_text(val);
 }
 
@@ -1561,14 +1596,14 @@ VteTerminalPrivate::change_color(vte::parser::Params const& params,
 void
 VteTerminalPrivate::seq_change_color_bel(vte::parser::Params const& params)
 {
-       change_color(params, BEL);
+       change_color(params, BEL_C0);
 }
 
-/* Change color in the palette, ST terminated */
+/* Change color in the palette, ST_C0 terminated */
 void
 VteTerminalPrivate::seq_change_color_st(vte::parser::Params const& params)
 {
-       change_color(params, ST);
+       change_color(params, ST_C0);
 }
 
 /* Reset color in the palette */
@@ -1578,7 +1613,7 @@ VteTerminalPrivate::seq_reset_color(vte::parser::Params const& params)
         auto n_params = params.size();
         if (n_params) {
                 for (unsigned int i = 0; i < n_params; i++) {
-                        long value;
+                        int value;
                         if (!params.number_at_unchecked(i, value))
                                 continue;
 
@@ -1600,7 +1635,7 @@ VteTerminalPrivate::seq_scroll_up(vte::parser::Params const& params)
 {
         /* No ensure_cursor_is_onscreen() here as per xterm */
 
-        auto val = std::max(params.number_or_default_at(0, 1), long(1));
+        auto val = std::max(params.number_or_default_at(0, 1), int(1));
         scroll_text(-val);
 }
 
@@ -1745,8 +1780,8 @@ void
 VteTerminalPrivate::seq_cursor_forward_tabulation(vte::parser::Params const& params)
 {
         auto val = std::max(std::min(params.number_or_default_at(0, 1),
-                                     m_column_count - m_screen->cursor.col),
-                            long(1));
+                                     int(m_column_count - m_screen->cursor.col)),
+                            int(1));
         for (auto i = 0; i < val; i++)
                 move_cursor_tab();
 }
@@ -1817,7 +1852,7 @@ VteTerminalPrivate::parse_sgr_38_48_parameters(vte::parser::Params const& params
 {
         auto n_params = params.size();
         if (*index < n_params) {
-                long param0;
+                int param0;
                 if (G_UNLIKELY(!params.number_at_unchecked(*index, param0)))
                         return -1;
 
@@ -1828,7 +1863,7 @@ VteTerminalPrivate::parse_sgr_38_48_parameters(vte::parser::Params const& params
                         if (might_contain_color_space_id && *index + 5 <= n_params)
                                *index += 1;
 
-                        long param1, param2, param3;
+                        int param1, param2, param3;
                         if (G_UNLIKELY(!params.number_at_unchecked(*index + 1, param1) ||
                                        !params.number_at_unchecked(*index + 2, param2) ||
                                        !params.number_at_unchecked(*index + 3, param3)))
@@ -1841,7 +1876,7 @@ VteTerminalPrivate::parse_sgr_38_48_parameters(vte::parser::Params const& params
                        return VTE_RGB_COLOR(redbits, greenbits, bluebits, param1, param2, param3);
                 }
                 case 5: {
-                        long param1;
+                        int param1;
                         if (G_UNLIKELY(!params.number_at(*index + 1, param1)))
                                 return -1;
 
@@ -1870,7 +1905,7 @@ VteTerminalPrivate::seq_character_attributes(vte::parser::Params const& params)
                if (G_UNLIKELY(params.has_subparams_at_unchecked(i))) {
                         auto subparams = params.subparams_at_unchecked(i);
 
-                        long param0, param1;
+                        int param0, param1;
                         if (G_UNLIKELY(!subparams.number_at(0, param0)))
                                 continue;
 
@@ -1905,11 +1940,12 @@ VteTerminalPrivate::seq_character_attributes(vte::parser::Params const& params)
                        continue;
                }
                /* If this parameter is not a number either, skip it. */
-                long param;
+                int param;
                 if (!params.number_at_unchecked(i, param))
                         continue;
 
                switch (param) {
+                case -1:
                case 0:
                         reset_default_attributes(false);
                        break;
@@ -2100,6 +2136,7 @@ VteTerminalPrivate::seq_return_terminal_status(vte::parser::Params const& params
 void
 VteTerminalPrivate::seq_send_primary_device_attributes(vte::parser::Params const& params)
 {
+        // FIXMEchpe only send anything when param==0 as per ECMA48
        /* Claim to be a VT220 with only national character set support. */
         feed_child("\e[?62;c", -1);
 }
@@ -2318,23 +2355,6 @@ VteTerminalPrivate::set_keypad_mode(VteKeymode mode)
         m_keypad_mode = mode;
 }
 
-/* Set the application or normal keypad. */
-void
-VteTerminalPrivate::seq_application_keypad(vte::parser::Params const& params)
-{
-       _vte_debug_print(VTE_DEBUG_KEYBOARD,
-                       "Entering application keypad mode.\n");
-       set_keypad_mode(VTE_KEYMODE_APPLICATION);
-}
-
-void
-VteTerminalPrivate::seq_normal_keypad(vte::parser::Params const& params)
-{
-       _vte_debug_print(VTE_DEBUG_KEYBOARD,
-                       "Leaving application keypad mode.\n");
-       set_keypad_mode(VTE_KEYMODE_NORMAL);
-}
-
 /* Same as cursor_character_absolute, not widely supported. */
 void
 VteTerminalPrivate::seq_character_position_absolute(vte::parser::Params const& params)
@@ -2374,24 +2394,17 @@ VteTerminalPrivate::seq_decreset(vte::parser::Params const& params)
 void
 VteTerminalPrivate::seq_erase_in_display(vte::parser::Params const& params)
 {
-       /* The default parameter is 0. */
-       long param = 0;
-        /* Pull out the first parameter. */
-        // FIXMEchpe why this weird taking of the first number param, not the actual first param?
-        auto n_params = params.size();
-        for (unsigned int i = 0; i < n_params; i++) {
-                if (params.number_at_unchecked(i, param))
-                        break;
-        }
-
-        erase_in_display(param);
 }
 
 void
-VteTerminalPrivate::erase_in_display(long param)
+VteTerminalPrivate::erase_in_display(vte::parser::Sequence const& seq)
 {
-       /* Clear the right area. */
-       switch (param) {
+        /* We don't implement the protected attribute, so we can ignore selective:
+         * bool selective = (seq.command() == VTE_CMD_DECSED);
+         */
+
+       switch (seq[0]) {
+        case -1: /* default */
        case 0:
                /* Clear below the current line. */
                 clear_below_current();
@@ -2418,28 +2431,20 @@ VteTerminalPrivate::erase_in_display(long param)
         m_text_deleted_flag = TRUE;
 }
 
-/* Erase certain parts of the current line in the display. */
 void
 VteTerminalPrivate::seq_erase_in_line(vte::parser::Params const& params)
 {
-       /* The default parameter is 0. */
-       long param = 0;
-        /* Pull out the first parameter. */
-        // FIXMEchpe why this weird taking of the first number param, not the actual first param?
-        auto n_params = params.size();
-        for (unsigned int i = 0; i < n_params; i++) {
-                if (params.number_at_unchecked(i, param))
-                        break;
-        }
-
-        erase_in_line(param);
 }
 
 void
-VteTerminalPrivate::erase_in_line(long param)
+VteTerminalPrivate::erase_in_line(vte::parser::Sequence const& seq)
 {
-       /* Clear the right area. */
-       switch (param) {
+        /* We don't implement the protected attribute, so we can ignore selective:
+         * bool selective = (seq.command() == VTE_CMD_DECSEL);
+         */
+
+       switch (seq[0]) {
+        case -1: /* default */
        case 0:
                /* Clear to end of the line. */
                 clear_to_eol();
@@ -2558,7 +2563,7 @@ VteTerminalPrivate::delete_lines(vte::grid::row_t param)
 void
 VteTerminalPrivate::seq_device_status_report(vte::parser::Params const& params)
 {
-        long param;
+        int param;
         if (!params.number_at(0, param))
                 return;
 
@@ -2597,7 +2602,7 @@ VteTerminalPrivate::seq_device_status_report(vte::parser::Params const& params)
 void
 VteTerminalPrivate::seq_dec_device_status_report(vte::parser::Params const& params)
 {
-        long param;
+        int param;
         if (!params.number_at(0, param))
                 return;
 
@@ -2697,7 +2702,7 @@ VteTerminalPrivate::seq_set_cursor_style(vte::parser::Params const& params)
         if (n_params > 1)
                 return;
 
-        long style;
+        int style;
         if (n_params == 0) {
                 /* no parameters means default (according to vt100.net) */
                 style = VTE_CURSOR_STYLE_TERMINAL_DEFAULT;
@@ -2730,12 +2735,12 @@ VteTerminalPrivate::seq_window_manipulation(vte::parser::Params const& params)
         if (n_params < 1)
                 return;
 
-        long param;
+        int  param;
         if (!params.number_at_unchecked(0, param))
                 return;
 
-        long arg1 = -1;
-        long arg2 = -1;
+        int arg1 = -1;
+        int arg2 = -1;
         if (n_params >= 2)
                 params.number_at_unchecked(1, arg1);
         if (n_params >= 3)
@@ -2747,28 +2752,28 @@ VteTerminalPrivate::seq_window_manipulation(vte::parser::Params const& params)
 
         switch (param) {
         case 1:
-                _vte_debug_print(VTE_DEBUG_PARSE,
+                _vte_debug_print(VTE_DEBUG_PARSER,
                                  "Deiconifying window.\n");
                 emit_deiconify_window();
                 break;
         case 2:
-                _vte_debug_print(VTE_DEBUG_PARSE,
+                _vte_debug_print(VTE_DEBUG_PARSER,
                                  "Iconifying window.\n");
                 emit_iconify_window();
                 break;
         case 3:
                 if ((arg1 != -1) && (arg2 != -1)) {
-                        _vte_debug_print(VTE_DEBUG_PARSE,
+                        _vte_debug_print(VTE_DEBUG_PARSER,
                                          "Moving window to "
-                                         "%ld,%ld.\n", arg1, arg2);
+                                         "%d,%d.\n", arg1, arg2);
                         emit_move_window(arg1, arg2);
                 }
                 break;
         case 4:
                 if ((arg1 != -1) && (arg2 != -1)) {
-                        _vte_debug_print(VTE_DEBUG_PARSE,
+                        _vte_debug_print(VTE_DEBUG_PARSER,
                                          "Resizing window "
-                                         "(to %ldx%ld pixels, grid size %ldx%ld).\n",
+                                         "(to %dx%d pixels, grid size %ldx%ld).\n",
                                          arg2, arg1,
                                          arg2 / m_cell_width,
                                          arg1 / m_cell_height);
@@ -2777,24 +2782,24 @@ VteTerminalPrivate::seq_window_manipulation(vte::parser::Params const& params)
                 }
                 break;
         case 5:
-                _vte_debug_print(VTE_DEBUG_PARSE, "Raising window.\n");
+                _vte_debug_print(VTE_DEBUG_PARSER, "Raising window.\n");
                 emit_raise_window();
                 break;
         case 6:
-                _vte_debug_print(VTE_DEBUG_PARSE, "Lowering window.\n");
+                _vte_debug_print(VTE_DEBUG_PARSER, "Lowering window.\n");
                 emit_lower_window();
                 break;
         case 7:
-                _vte_debug_print(VTE_DEBUG_PARSE,
+                _vte_debug_print(VTE_DEBUG_PARSER,
                                  "Refreshing window.\n");
                 invalidate_all();
                 emit_refresh_window();
                 break;
         case 8:
                 if ((arg1 != -1) && (arg2 != -1)) {
-                        _vte_debug_print(VTE_DEBUG_PARSE,
+                        _vte_debug_print(VTE_DEBUG_PARSER,
                                          "Resizing window "
-                                         "(to %ld columns, %ld rows).\n",
+                                         "(to %d columns, %d rows).\n",
                                          arg2, arg1);
                         emit_resize_window(arg2, arg1);
                 }
@@ -2802,12 +2807,12 @@ VteTerminalPrivate::seq_window_manipulation(vte::parser::Params const& params)
         case 9:
                 switch (arg1) {
                 case 0:
-                        _vte_debug_print(VTE_DEBUG_PARSE,
+                        _vte_debug_print(VTE_DEBUG_PARSER,
                                          "Restoring window.\n");
                         emit_restore_window();
                         break;
                 case 1:
-                        _vte_debug_print(VTE_DEBUG_PARSE,
+                        _vte_debug_print(VTE_DEBUG_PARSER,
                                          "Maximizing window.\n");
                         emit_maximize_window();
                         break;
@@ -2820,7 +2825,7 @@ VteTerminalPrivate::seq_window_manipulation(vte::parser::Params const& params)
                 g_snprintf(buf, sizeof(buf),
                            _VTE_CAP_CSI "%dt",
                            1 + !gtk_widget_get_mapped(m_widget));
-                _vte_debug_print(VTE_DEBUG_PARSE,
+                _vte_debug_print(VTE_DEBUG_PARSER,
                                  "Reporting window state %s.\n",
                                  gtk_widget_get_mapped(m_widget) ?
                                  "non-iconified" : "iconified");
@@ -2834,7 +2839,7 @@ VteTerminalPrivate::seq_window_manipulation(vte::parser::Params const& params)
                            _VTE_CAP_CSI "3;%d;%dt",
                            width + m_padding.left,
                            height + m_padding.top);
-                _vte_debug_print(VTE_DEBUG_PARSE,
+                _vte_debug_print(VTE_DEBUG_PARSER,
                                  "Reporting window location"
                                  "(%d++,%d++).\n",
                                  width, height);
@@ -2846,7 +2851,7 @@ VteTerminalPrivate::seq_window_manipulation(vte::parser::Params const& params)
                            _VTE_CAP_CSI "4;%d;%dt",
                            (int)(m_row_count * m_cell_height),
                            (int)(m_column_count * m_cell_width));
-                _vte_debug_print(VTE_DEBUG_PARSE,
+                _vte_debug_print(VTE_DEBUG_PARSER,
                                  "Reporting window size "
                                  "(%dx%d)\n",
                                  (int)(m_row_count * m_cell_height),
@@ -2856,7 +2861,7 @@ VteTerminalPrivate::seq_window_manipulation(vte::parser::Params const& params)
                 break;
         case 18:
                 /* Send widget size, in cells. */
-                _vte_debug_print(VTE_DEBUG_PARSE,
+                _vte_debug_print(VTE_DEBUG_PARSER,
                                  "Reporting widget size.\n");
                 g_snprintf(buf, sizeof(buf),
                            _VTE_CAP_CSI "8;%ld;%ldt",
@@ -2865,7 +2870,7 @@ VteTerminalPrivate::seq_window_manipulation(vte::parser::Params const& params)
                 feed_child(buf, -1);
                 break;
         case 19:
-                _vte_debug_print(VTE_DEBUG_PARSE,
+                _vte_debug_print(VTE_DEBUG_PARSER,
                                  "Reporting screen size.\n");
                 gscreen = gtk_widget_get_screen(m_widget);
                 height = gdk_screen_get_height(gscreen);
@@ -2882,7 +2887,7 @@ VteTerminalPrivate::seq_window_manipulation(vte::parser::Params const& params)
                    creates a security vulnerability.  See
                    http://marc.info/?l=bugtraq&m=104612710031920&w=2
                    and CVE-2003-0070. */
-                _vte_debug_print(VTE_DEBUG_PARSE,
+                _vte_debug_print(VTE_DEBUG_PARSER,
                                  "Reporting fake icon title.\n");
                 /* never use m_icon_title here! */
                 g_snprintf (buf, sizeof (buf),
@@ -2895,7 +2900,7 @@ VteTerminalPrivate::seq_window_manipulation(vte::parser::Params const& params)
                    creates a security vulnerability.  See
                    http://marc.info/?l=bugtraq&m=104612710031920&w=2
                    and CVE-2003-0070. */
-                _vte_debug_print(VTE_DEBUG_PARSE,
+                _vte_debug_print(VTE_DEBUG_PARSER,
                                  "Reporting fake window title.\n");
                 /* never use m_window_title here! */
                 g_snprintf (buf, sizeof (buf),
@@ -2904,8 +2909,8 @@ VteTerminalPrivate::seq_window_manipulation(vte::parser::Params const& params)
                 break;
         default:
                 if (param >= 24) {
-                        _vte_debug_print(VTE_DEBUG_PARSE,
-                                         "Resizing to %ld rows.\n",
+                        _vte_debug_print(VTE_DEBUG_PARSER,
+                                         "Resizing to %d rows.\n",
                                          param);
                         /* Resize to the specified number of
                          * rows. */
@@ -2949,14 +2954,14 @@ VteTerminalPrivate::change_special_color(vte::parser::Params const& params,
 void
 VteTerminalPrivate::seq_change_foreground_color_bel(vte::parser::Params const& params)
 {
-        change_special_color(params, VTE_DEFAULT_FG, -1, 10, BEL);
+        change_special_color(params, VTE_DEFAULT_FG, -1, 10, BEL_C0);
 }
 
-/* Change the default foreground cursor, ST terminated */
+/* Change the default foreground cursor, ST_C0 terminated */
 void
 VteTerminalPrivate::seq_change_foreground_color_st(vte::parser::Params const& params)
 {
-        change_special_color(params, VTE_DEFAULT_FG, -1, 10, ST);
+        change_special_color(params, VTE_DEFAULT_FG, -1, 10, ST_C0);
 }
 
 /* Reset the default foreground color */
@@ -2970,14 +2975,14 @@ VteTerminalPrivate::seq_reset_foreground_color(vte::parser::Params const& params
 void
 VteTerminalPrivate::seq_change_background_color_bel(vte::parser::Params const& params)
 {
-        change_special_color(params, VTE_DEFAULT_BG, -1, 11, BEL);
+        change_special_color(params, VTE_DEFAULT_BG, -1, 11, BEL_C0);
 }
 
-/* Change the default background cursor, ST terminated */
+/* Change the default background cursor, ST_C0 terminated */
 void
 VteTerminalPrivate::seq_change_background_color_st(vte::parser::Params const& params)
 {
-        change_special_color(params, VTE_DEFAULT_BG, -1, 11, ST);
+        change_special_color(params, VTE_DEFAULT_BG, -1, 11, ST_C0);
 }
 
 /* Reset the default background color */
@@ -2991,14 +2996,14 @@ VteTerminalPrivate::seq_reset_background_color(vte::parser::Params const& params
 void
 VteTerminalPrivate::seq_change_cursor_background_color_bel(vte::parser::Params const& params)
 {
-        change_special_color(params, VTE_CURSOR_BG, VTE_DEFAULT_FG, 12, BEL);
+        change_special_color(params, VTE_CURSOR_BG, VTE_DEFAULT_FG, 12, BEL_C0);
 }
 
-/* Change the color of the cursor background, ST terminated */
+/* Change the color of the cursor background, ST_C0 terminated */
 void
 VteTerminalPrivate::seq_change_cursor_background_color_st(vte::parser::Params const& params)
 {
-        change_special_color(params, VTE_CURSOR_BG, VTE_DEFAULT_FG, 12, ST);
+        change_special_color(params, VTE_CURSOR_BG, VTE_DEFAULT_FG, 12, ST_C0);
 }
 
 /* Reset the color of the cursor */
@@ -3012,14 +3017,14 @@ VteTerminalPrivate::seq_reset_cursor_background_color(vte::parser::Params const&
 void
 VteTerminalPrivate::seq_change_highlight_background_color_bel(vte::parser::Params const& params)
 {
-        change_special_color(params, VTE_HIGHLIGHT_BG, VTE_DEFAULT_FG, 17, BEL);
+        change_special_color(params, VTE_HIGHLIGHT_BG, VTE_DEFAULT_FG, 17, BEL_C0);
 }
 
-/* Change the highlight background color, ST terminated */
+/* Change the highlight background color, ST_C0 terminated */
 void
 VteTerminalPrivate::seq_change_highlight_background_color_st(vte::parser::Params const& params)
 {
-        change_special_color(params, VTE_HIGHLIGHT_BG, VTE_DEFAULT_FG, 17, ST);
+        change_special_color(params, VTE_HIGHLIGHT_BG, VTE_DEFAULT_FG, 17, ST_C0);
 }
 
 /* Reset the highlight background color */
@@ -3033,14 +3038,14 @@ VteTerminalPrivate::seq_reset_highlight_background_color(vte::parser::Params con
 void
 VteTerminalPrivate::seq_change_highlight_foreground_color_bel(vte::parser::Params const& params)
 {
-        change_special_color(params, VTE_HIGHLIGHT_FG, VTE_DEFAULT_BG, 19, BEL);
+        change_special_color(params, VTE_HIGHLIGHT_FG, VTE_DEFAULT_BG, 19, BEL_C0);
 }
 
-/* Change the highlight foreground color, ST terminated */
+/* Change the highlight foreground color, ST_C0 terminated */
 void
 VteTerminalPrivate::seq_change_highlight_foreground_color_st(vte::parser::Params const& params)
 {
-        change_special_color(params, VTE_HIGHLIGHT_FG, VTE_DEFAULT_BG, 19, ST);
+        change_special_color(params, VTE_HIGHLIGHT_FG, VTE_DEFAULT_BG, 19, ST_C0);
 }
 
 /* Reset the highlight foreground color */
@@ -3084,7 +3089,7 @@ VteTerminalPrivate::seq_iterm2_1337(vte::parser::Params const& params)
         { \
                 static bool warned = false; \
                 if (!warned) { \
-                        _vte_debug_print(VTE_DEBUG_PARSE, \
+                        _vte_debug_print(VTE_DEBUG_PARSER, \
                                          "Unimplemented handler for control sequence `%s'.\n", \
                                          "name"); \
                         warned = true; \
@@ -3153,10 +3158,2964 @@ UNIMPLEMENTED_SEQUENCE_HANDLER(utf_8_character_set)
 
 #undef UNIMPLEMENTED_UNIMPLEMENTED_SEQUENCE_HANDLER
 
-vte_matcher_entry_t const*
-_vte_get_matcher_entries(unsigned int* n_entries)
+/// FIXME
+
+
+/*
+ * Copyright (C) 2015 David Herrmann <dh herrmann gmail com>
+ *
+ * vte 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 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+enum {
+        /* 7bit mode (default: on) */
+        VTE_FLAG_7BIT_MODE                = (1U << 0),
+        /* hide cursor caret (default: off) */
+        VTE_FLAG_HIDE_CURSOR                = (1U << 1),
+        /* do not send TPARM unrequested (default: off) */
+        VTE_FLAG_INHIBIT_TPARM        = (1U << 2),
+        /* perform carriage-return on line-feeds (default: off) */
+        VTE_FLAG_NEWLINE_MODE        = (1U << 3),
+        /* wrap-around is pending */
+        VTE_FLAG_PENDING_WRAP        = (1U << 4),
+        /* application-keypad mode (default: off) */
+        VTE_FLAG_KEYPAD_MODE                = (1U << 5),
+        /* enable application cursor-keys (default: off) */
+        VTE_FLAG_CURSOR_KEYS                = (1U << 6),
+};
+
+enum {
+        VTE_CONFORMANCE_LEVEL_VT52,
+        VTE_CONFORMANCE_LEVEL_VT100,
+        VTE_CONFORMANCE_LEVEL_VT400,
+        VTE_CONFORMANCE_LEVEL_N,
+};
+/*
+ * Command Handlers
+ * This is the unofficial documentation of all the VTE_CMD_* definitions.
+ * Each handled command has a separate function with an extensive comment on
+ * the semantics of the command.
+ * Note that many semantics are unknown and need to be verified. This is mostly
+ * about error-handling, though. Applications rarely rely on those features.
+ */
+
+void
+VteTerminalPrivate::NONE(vte::parser::Sequence const& seq)
+{
+}
+
+void
+VteTerminalPrivate::GRAPHIC(vte::parser::Sequence const& seq)
+{
+#if 0
+        struct vte_char ch = VTE_CHAR_NULL;
+
+        if (screen->state.cursor_x + 1 == screen->page->width
+            && screen->flags & VTE_FLAG_PENDING_WRAP
+            && screen->state.auto_wrap) {
+                screen_cursor_down(screen, 1, true);
+                screen_cursor_set(screen, 0, screen->state.cursor_y);
+        }
+
+        screen_cursor_clear_wrap(screen);
+
+        ch = vte_char_merge(ch, screen_map(screen, seq->terminator));
+        vte_page_write(screen->page,
+                          screen->state.cursor_x,
+                          screen->state.cursor_y,
+                          ch,
+                          1,
+                          &screen->state.attr,
+                          screen->age,
+                          false);
+
+        if (screen->state.cursor_x + 1 == screen->page->width)
+                screen->flags |= VTE_FLAG_PENDING_WRAP;
+        else
+                screen_cursor_right(screen, 1);
+
+        return 0;
+#endif
+
+        insert_char(seq.terminator(), false, false);
+}
+
+void
+VteTerminalPrivate::BEL(vte::parser::Sequence const& seq)
+{
+        /*
+         * BEL - sound bell tone
+         * This command should trigger an acoustic bell. Usually, this is
+         * forwarded directly to the pcspkr. However, bells have become quite
+         * uncommon and annoying, so we're not implementing them here. Instead,
+         * it's one of the commands we forward to the caller.
+         */
+
+#if 0
+        screen_forward(screen, VTE_CMD_BEL, seq);
+#endif
+
+        seq_bell(seq);
+}
+
+void
+VteTerminalPrivate::BS(vte::parser::Sequence const& seq)
+{
+        /*
+         * BS - backspace
+         * Move cursor one cell to the left. If already at the left margin,
+         * nothing happens.
+         */
+
+#if 0
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_left(screen, 1);
+#endif
+
+        seq_backspace(seq);
+}
+
+void
+VteTerminalPrivate::CBT(vte::parser::Sequence const& seq)
+{
+        /*
+         * CBT - cursor-backward-tabulation
+         * Move the cursor @args[0] tabs backwards (to the left). The
+         * current cursor cell, in case it's a tab, is not counted.
+         * Furthermore, the cursor cannot be moved beyond position 0 and
+         * it will stop there.
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_left_tab(screen, num);
+#endif
+
+        seq_cursor_back_tab(seq);
+}
+
+void
+VteTerminalPrivate::CHA(vte::parser::Sequence const& seq)
+{
+        /*
+         * CHA - cursor-horizontal-absolute
+         * Move the cursor to position @args[0] in the current line. The
+         * cursor cannot be moved beyond the rightmost cell and will stop
+         * there.
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+
+#if 0
+        unsigned int pos = 1;
+
+        if (seq->args[0] > 0)
+                pos = seq->args[0];
+
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_set(screen, pos - 1, screen->state.cursor_y);
+#endif
+
+        seq_cursor_character_absolute(seq);
+}
+
+void
+VteTerminalPrivate::CHT(vte::parser::Sequence const& seq)
+{
+        /*
+         * CHT - cursor-horizontal-forward-tabulation
+         * Move the cursor @args[0] tabs forward (to the right). The
+         * current cursor cell, in case it's a tab, is not counted.
+         * Furthermore, the cursor cannot be moved beyond the rightmost cell
+         * and will stop there.
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_right_tab(screen, num);
+#endif
+
+        seq_cursor_forward_tabulation(seq);
+}
+
+void
+VteTerminalPrivate::CNL(vte::parser::Sequence const& seq)
+{
+        /*
+         * CNL - cursor-next-line
+         * Move the cursor @args[0] lines down.
+         *
+         * TODO: Does this stop at the bottom or cause a scroll-up?
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_down(screen, num, false);
+#endif
+
+        seq_cursor_next_line(seq);
+}
+
+void
+VteTerminalPrivate::CPL(vte::parser::Sequence const& seq)
+{
+        /*
+         * CPL - cursor-preceding-line
+         * Move the cursor @args[0] lines up.
+         *
+         * TODO: Does this stop at the top or cause a scroll-up?
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_up(screen, num, false);
+#endif
+
+        seq_cursor_preceding_line(seq);
+}
+
+void
+VteTerminalPrivate::CR(vte::parser::Sequence const& seq)
+{
+        /*
+         * CR - carriage-return
+         * Move the cursor to the left margin on the current line.
+         */
+#if 0
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_set(screen, 0, screen->state.cursor_y);
+#endif
+
+        seq_carriage_return(seq);
+}
+
+void
+VteTerminalPrivate::CUB(vte::parser::Sequence const& seq)
+{
+        /*
+         * CUB - cursor-backward
+         * Move the cursor @args[0] positions to the left. The cursor stops
+         * at the left-most position.
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_left(screen, num);
+#endif
+
+        seq_cursor_backward(seq);
+}
+
+void
+VteTerminalPrivate::CUD(vte::parser::Sequence const& seq)
+{
+        /*
+         * CUD - cursor-down
+         * Move the cursor @args[0] positions down. The cursor stops at the
+         * bottom margin. If it was already moved further, it stops at the
+         * bottom line.
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_down(screen, num, false);
+#endif
+
+        seq_cursor_down(seq);
+}
+
+void
+VteTerminalPrivate::CUF(vte::parser::Sequence const& seq)
+{
+        /*
+         * CUF -cursor-forward
+         * Move the cursor @args[0] positions to the right. The cursor stops
+         * at the right-most position.
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_right(screen, num);
+#endif
+
+        seq_cursor_forward(seq);
+}
+
+void
+VteTerminalPrivate::CUP(vte::parser::Sequence const& seq)
+{
+        /*
+         * CUP - cursor-position
+         * Moves the cursor to position @args[1] x @args[0]. If either is 0, it
+         * is treated as 1. The positions are subject to the origin-mode and
+         * clamped to the addressable with/height.
+         *
+         * Defaults:
+         *   args[0]: 1
+         *   args[1]: 1
+         */
+#if 0
+        unsigned int x = 1, y = 1;
+
+        if (seq->args[0] > 0)
+                y = seq->args[0];
+        if (seq->args[1] > 0)
+                x = seq->args[1];
+
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_set_rel(screen, x - 1, y - 1);
+#endif
+
+        seq_cursor_position(seq);
+}
+
+void
+VteTerminalPrivate::CUU(vte::parser::Sequence const& seq)
+{
+        /*
+         * CUU - cursor-up
+         * Move the cursor @args[0] positions up. The cursor stops at the
+         * top margin. If it was already moved further, it stops at the
+         * top line.
+         *
+         * Defaults:
+         *   args[0]: 1
+         *
+         */
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_up(screen, num, false);
+#endif
+
+        seq_cursor_up(seq);
+}
+
+void
+VteTerminalPrivate::DA1(vte::parser::Sequence const& seq)
+{
+        /*
+         * DA1 - primary-device-attributes
+         * The primary DA asks for basic terminal features. We simply return
+         * a hard-coded list of features we implement.
+         * Note that the primary DA asks for supported features, not currently
+         * enabled features.
+         *
+         * The terminal's answer is:
+         *   ^[ ? 64 ; ARGS c
+         * The first argument, 64, is fixed and denotes a VT420, the last
+         * DEC-term that extended this number.
+         * All following arguments denote supported features. Note
+         * that at most 15 features can be sent (max CSI args). It is safe to
+         * send more, but clients might not be able to parse them. This is a
+         * client's problem and we shouldn't care. There is no other way to
+         * send those feature lists, so we have to extend them beyond 15 in
+         * those cases.
+         *
+         * Known modes:
+         *    1: 132 column mode
+         *       The 132 column mode is supported by the terminal.
+         *    2: printer port
+         *       A priner-port is supported and can be addressed via
+         *       control-codes.
+         *    3: ReGIS graphics
+         *       Support for ReGIS graphics is available. The ReGIS routines
+         *       provide the "remote graphics instruction set" and allow basic
+         *       vector-rendering.
+         *    4: sixel
+         *       Support of Sixel graphics is available. This provides access
+         *       to the sixel bitmap routines.
+         *    6: selective erase
+         *       The terminal supports DECSCA and related selective-erase
+         *       functions. This allows to protect specific cells from being
+         *       erased, if specified.
+         *    7: soft character set (DRCS)
+         *       TODO: ?
+         *    8: user-defined keys (UDKs)
+         *       TODO: ?
+         *    9: national-replacement character sets (NRCS)
+         *       National-replacement character-sets are available.
+         *   12: Yugoslavian (SCS)
+         *       TODO: ?
+         *   15: technical character set
+         *       The DEC technical-character-set is available.
+         *   18: windowing capability
+         *       TODO: ?
+         *   21: horizontal scrolling
+         *       TODO: ?
+         *   22: ANSII color
+         *       TODO: ?
+         *   23: Greek
+         *       TODO: ?
+         *   24: Turkish
+         *       TODO: ?
+         *   29: ANSI text locator
+         *       TODO: ?
+         *   42: ISO Latin-2 character set
+         *       TODO: ?
+         *   44: PCTerm
+         *       TODO: ?
+         *   45: soft keymap
+         *       TODO: ?
+         *   46: ASCII emulation
+         *       TODO: ?
+         */
+#if 0
+        SEQ_WRITE(screen, C0_CSI, C1_CSI, "?64;1;6;9;15c");
+#endif
+
+        seq_send_primary_device_attributes(seq);
+}
+
+void
+VteTerminalPrivate::DA2(vte::parser::Sequence const& seq)
+{
+        /*
+         * DA2 - secondary-device-attributes
+         * The secondary DA asks for the terminal-ID, firmware versions and
+         * other non-primary attributes. All these values are
+         * informational-only and should not be used by the host to detect
+         * terminal features.
+         *
+         * The terminal's response is:
+         *   ^[ > 61 ; FIRMWARE ; KEYBOARD c
+         * whereas 65 is fixed for VT525 terminals, the last terminal-line that
+         * increased this number. FIRMWARE is the firmware
+         * version encoded as major/minor (20 == 2.0) and KEYBOARD is 0 for STD
+         * keyboard and 1 for PC keyboards.
+         *
+         * We replace the firmware-version with the systemd-version so clients
+         * can decode it again.
+         */
+#if 0
+        return SEQ_WRITE(screen, C0_CSI, C1_CSI,
+                         ">65;" __stringify(LINUX_VERSION_CODE) ";1c");
+#endif
+
+        seq_send_secondary_device_attributes(seq);
+}
+
+void
+VteTerminalPrivate::DA3(vte::parser::Sequence const& seq)
+{
+        /*
+         * DA3 - tertiary-device-attributes
+         * The tertiary DA is used to query the terminal-ID.
+         *
+         * The terminal's response is:
+         *   ^P ! | XX AA BB CC ^\
+         * whereas all four parameters are hexadecimal-encoded pairs. XX
+         * denotes the manufacturing site, AA BB CC is the terminal's ID.
+         */
+
+        /* we do not support tertiary DAs */
+#if 0
+#endif
+}
+
+void
+VteTerminalPrivate::DC1(vte::parser::Sequence const& seq)
+{
+        /*
+         * DC1 - device-control-1 or XON
+         * This clears any previous XOFF and resumes terminal-transmission.
+         */
+
+        /* we do not support XON */
+}
+
+void
+VteTerminalPrivate::DC3(vte::parser::Sequence const& seq)
+{
+        /*
+         * DC3 - device-control-3 or XOFF
+         * Stops terminal transmission. No further characters are sent until
+         * an XON is received.
+         */
+
+        /* we do not support XOFF */
+}
+
+void
+VteTerminalPrivate::DCH(vte::parser::Sequence const& seq)
+{
+        /*
+         * DCH - delete-character
+         * This deletes @argv[0] characters at the current cursor position.
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        screen_cursor_clear_wrap(screen);
+        vte_page_delete_cells(screen->page,
+                                 screen->state.cursor_x,
+                                 screen->state.cursor_y,
+                                 num,
+                                 &screen->state.attr,
+                                 screen->age);
+#endif
+
+        seq_delete_characters(seq);
+}
+
+void
+VteTerminalPrivate::DECALN(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECALN - screen-alignment-pattern
+         *
+         * Probably not worth implementing.
+         */
+
+        seq_screen_alignment_test(seq);
+}
+
+void
+VteTerminalPrivate::DECANM(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECANM - ansi-mode
+         * Set the terminal into VT52 compatibility mode. Control sequences
+         * overlap with regular sequences so we have to detect them early before
+         * dispatching them.
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECBI(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECBI - back-index
+         * This control function moves the cursor backward one column. If the
+         * cursor is at the left margin, then all screen data within the margin
+         * moves one column to the right. The column that shifted past the right
+         * margin is lost.
+         * DECBI adds a new column at the left margin with no visual attributes.
+         * DECBI does not affect the margins. If the cursor is beyond the
+         * left-margin at the left border, then the terminal ignores DECBI.
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECCARA(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECCARA - change-attributes-in-rectangular-area
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECCRA(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECCRA - copy-rectangular-area
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECDC(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECDC - delete-column
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECDHL_BH(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECDHL_BH - double-width-double-height-line: bottom half
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECDHL_TH(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECDHL_TH - double-width-double-height-line: top half
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECDWL(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECDWL - double-width-single-height-line
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECEFR(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECEFR - enable-filter-rectangle
+         * Defines the coordinates of a filter rectangle (top, left, bottom,
+         * right as @args[0] to @args[3]) and activates it.
+         * Anytime the locator is detected outside of the filter rectangle, an
+         * outside rectangle event is generated and the rectangle is disabled.
+         * Filter rectangles are always treated as "one-shot" events. Any
+         * parameters that are omitted default to the current locator position.
+         * If all parameters are omitted, any locator motion will be reported.
+         * DECELR always cancels any prevous rectangle definition.
+         *
+         * The locator is usually associated with the mouse-cursor, but based
+         * on cells instead of pixels. See DECELR how to initialize and enable
+         * it. DECELR can also enable pixel-mode instead of cell-mode.
+         *
+         * TODO: implement
+         */
+}
+
+void
+VteTerminalPrivate::DECELF(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECELF - enable-local-functions
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECELR(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECELR - enable-locator-reporting
+         * This changes the locator-reporting mode. @args[0] specifies the mode
+         * to set, 0 disables locator-reporting, 1 enables it continuously, 2
+         * enables it for a single report. @args[1] specifies the
+         * precision-mode. 0 and 2 set the reporting to cell-precision, 1 sets
+         * pixel-precision.
+         *
+         * Defaults:
+         *   args[0]: 0
+         *   args[1]: 0
+         *
+         * TODO: implement
+         */
+}
+
+void
+VteTerminalPrivate::DECERA(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECERA - erase-rectangular-area
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECFI(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECFI - forward-index
+         * This control function moves the cursor forward one column. If the
+         * cursor is at the right margin, then all screen data within the
+         * margins moves one column to the left. The column shifted past the
+         * left margin is lost.
+         * DECFI adds a new column at the right margin, with no visual
+         * attributes. DECFI does not affect margins. If the cursor is beyond
+         * the right margin at the border of the page when the terminal
+         * receives DECFI, then the terminal ignores DECFI.
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECFRA(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECFRA - fill-rectangular-area
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECIC(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECIC - insert-column
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECID(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECID - return-terminal-id
+         * This is an obsolete form of VTE_CMD_DA1.
+         */
+
+        DA1(seq);
+}
+
+void
+VteTerminalPrivate::DECINVM(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECINVM - invoke-macro
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECKBD(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECKBD - keyboard-language-selection
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECKPAM(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECKPAM - keypad-application-mode
+         * Enables the keypad-application mode. If enabled, the keypad sends
+         * special characters instead of the printed characters. This way,
+         * applications can detect whether a numeric key was pressed on the
+         * top-row or on the keypad.
+         * Default is keypad-numeric-mode.
+         */
+#if 0
+        screen->flags |= VTE_FLAG_KEYPAD_MODE;
+#endif
+
+        set_keypad_mode(VTE_KEYMODE_APPLICATION);
+}
+
+void
+VteTerminalPrivate::DECKPNM(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECKPNM - keypad-numeric-mode
+         * This disables the keypad-application-mode (DECKPAM) and returns to
+         * the keypad-numeric-mode. Keypresses on the keypad generate the same
+         * sequences as corresponding keypresses on the main keyboard.
+         * Default is keypad-numeric-mode.
+         */
+#if 0
+        screen->flags &= ~VTE_FLAG_KEYPAD_MODE;
+#endif
+
+       set_keypad_mode(VTE_KEYMODE_NORMAL);
+}
+
+void
+VteTerminalPrivate::DECLFKC(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECLFKC - local-function-key-control
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECLL(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECLL - load-leds
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECLTOD(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECLTOD - load-time-of-day
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECPCTERM(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECPCTERM - pcterm-mode
+         * This enters/exits the PCTerm mode. Default mode is VT-mode. It can
+         * also select parameters for scancode/keycode mappings in SCO mode.
+         *
+         * Definitely not worth implementing. Lets kill PCTerm/SCO modes!
+         */
+}
+
+void
+VteTerminalPrivate::DECPKA(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECPKA - program-key-action
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECPKFMR(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECPKFMR - program-key-free-memory-report
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECRARA(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECRARA - reverse-attributes-in-rectangular-area
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECRC(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECRC - restore-cursor
+         * Restores the terminal to the state saved by the save cursor (DECSC)
+         * function. If there was not a previous DECSC, then this does:
+         *   * Home the cursor
+         *   * Resets DECOM
+         *   * Resets the SGR attributes
+         *   * Designates ASCII (IR #6) to GL, and DEC Supplemental Graphics to GR
+         *
+         * Note that the status line has its own DECSC buffer.
+         */
+#if 0
+        screen_restore_state(screen, &screen->saved);
+#endif
+
+        seq_restore_cursor(seq);
+}
+
+void
+VteTerminalPrivate::DECREQTPARM(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECREQTPARM - request-terminal-parameters
+         * The sequence DECREPTPARM is sent by the terminal controller to notify
+         * the host of the status of selected terminal parameters. The status
+         * sequence may be sent when requested by the host or at the terminal's
+         * discretion. DECREPTPARM is sent upon receipt of a DECREQTPARM.
+         *
+         * If @args[0] is 0, this marks a request and the terminal is allowed
+         * to send DECREPTPARM messages without request. If it is 1, the same
+         * applies but the terminal should no longer send DECREPTPARM
+         * unrequested.
+         * 2 and 3 mark a report, but 3 is only used if the terminal answers as
+         * an explicit request with @args[0] == 1.
+         *
+         * The other arguments are ignored in requests, but have the following
+         * meaning in responses:
+         *   args[1]: 1=no-parity-set 4=parity-set-and-odd 5=parity-set-and-even
+         *   args[2]: 1=8bits-per-char 2=7bits-per-char
+         *   args[3]: transmission-speed
+         *   args[4]: receive-speed
+         *   args[5]: 1=bit-rate-multiplier-is-16
+         *   args[6]: This value communicates the four switch values in block 5
+         *            of SETUP B, which are only visible to the user when an STP
+         *            option is installed. These bits may be assigned for an STP
+         *            device. The four bits are a decimal-encoded binary number.
+         *            Value between 0-15.
+         *
+         * The transmission/receive speeds have mappings for number => bits/s
+         * which are quite weird. Examples are: 96->3600, 112->9600, 120->19200
+         *
+         * Defaults:
+         *   args[0]: 0
+         */
+#if 0
+        if (seq->n_args < 1 || seq->args[0] == 0) {
+                screen->flags &= ~VTE_FLAG_INHIBIT_TPARM;
+                return SEQ_WRITE(screen, C0_CSI, C1_CSI, "2;1;1;120;120;1;0x");
+        } else if (seq->args[0] == 1) {
+                screen->flags |= VTE_FLAG_INHIBIT_TPARM;
+                return SEQ_WRITE(screen, C0_CSI, C1_CSI, "3;1;1;120;120;1;0x");
+        } else {
+                return 0;
+        }
+#endif
+
+        seq_request_terminal_parameters(seq);
+}
+
+void
+VteTerminalPrivate::DECRPKT(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECRPKT - report-key-type
+         * Response to DECRQKT, we can safely ignore it as we're the one sending
+         * it to the host.
+         */
+}
+
+void
+VteTerminalPrivate::DECRQCRA(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECRQCRA - request-checksum-of-rectangular-area
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECRQDE(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECRQDE - request-display-extent
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECRQKT(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECRQKT - request-key-type
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECRQLP(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECRQLP - request-locator-position
+         * See DECELR for locator-information.
+         *
+         * TODO: document and implement
+         */
+}
+
+void
+VteTerminalPrivate::DECRQM_ANSI(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECRQM_ANSI - request-mode-ansi
+         * The host sends this control function to find out if a particular mode
+         * is set or reset. The terminal responds with a report mode function.
+         * @args[0] contains the mode to query.
+         *
+         * Response is DECRPM with the first argument set to the mode that was
+         * queried, second argument is 0 if mode is invalid, 1 if mode is set,
+         * 2 if mode is not set (reset), 3 if mode is permanently set and 4 if
+         * mode is permanently not set (reset):
+         *   ANSI: ^[ MODE ; VALUE $ y
+         *   DEC:  ^[ ? MODE ; VALUE $ y
+         *
+         * TODO: implement
+         */
+}
+
+void
+VteTerminalPrivate::DECRQM_DEC(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECRQM_DEC - request-mode-dec
+         * Same as DECRQM_ANSI but for DEC modes.
+         *
+         * TODO: implement
+         */
+}
+
+void
+VteTerminalPrivate::DECRQPKFM(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECRQPKFM - request-program-key-free-memory
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECRQPSR(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECRQPSR - request-presentation-state-report
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECRQTSR(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECRQTSR - request-terminal-state-report
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECRQUPSS(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECRQUPSS - request-user-preferred-supplemental-set
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSACE(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSACE - select-attribute-change-extent
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSASD(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSASD - select-active-status-display
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSC(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSC - save-cursor
+         * Save cursor and terminal state so it can be restored later on.
+         * This stores:
+         *   * Cursor position
+         *   * SGR attributes
+         *   * Charset designations for GL and GR
+         *   * Wrap flag
+         *   * DECOM state
+         *   * Selective erase attribute
+         *   * Any SS2 or SS3 sent
+         *
+         */
+#if 0
+        screen_save_state(screen, &screen->saved);
+#endif
+
+        seq_save_cursor(seq);
+}
+
+void
+VteTerminalPrivate::DECSCA(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSCA - select-character-protection-attribute
+         *
+         * Defaults:
+         *   args[0]: 0
+         *
+         * References: VT525
+         */
+#if 0
+        unsigned int mode = 0;
+
+        if (seq->args[0] > 0)
+                mode = seq->args[0];
+
+        switch (mode) {
+        case 0:
+        case 2:
+                screen->state.attr.protect = 0;
+                break;
+        case 1:
+                screen->state.attr.protect = 1;
+                break;
+        }
+#endif
+}
+
+void
+VteTerminalPrivate::DECSCL(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSCL - select-conformance-level
+         * Select the terminal's operating level. The factory default is
+         * level 4 (VT Level 4 mode, 7-bit controls).
+         * When you change the conformance level, the terminal performs a hard
+         * reset (RIS).
+         *
+         * @args[0] defines the conformance-level, valid values are:
+         *   61: Level 1 (VT100)
+         *   62: Level 2 (VT200)
+         *   63: Level 3 (VT300)
+         *   64: Level 4 (VT400)
+         * @args[1] defines the 8bit-mode, valid values are:
+         *    0: 8-bit controls
+         *    1: 7-bit controls
+         *    2: 8-bit controls (same as 0)
+         *
+         * If @args[0] is 61, then @args[1] is ignored and 7bit controls are
+         * enforced.
+         *
+         * Defaults:
+         *   args[0]: 64
+         *   args[1]: 0
+         */
+#if 0
+        unsigned int level = 64, bit = 0;
+
+        if (seq->n_args > 0) {
+                level = seq->args[0];
+                if (seq->n_args > 1)
+                        bit = seq->args[1];
+        }
+
+        vte_screen_hard_reset(screen);
+
+        switch (level) {
+        case 61:
+                screen->conformance_level = VTE_CONFORMANCE_LEVEL_VT100;
+                screen->flags |= VTE_FLAG_7BIT_MODE;
+                break;
+        case 62 ... 69:
+                screen->conformance_level = VTE_CONFORMANCE_LEVEL_VT400;
+                if (bit == 1)
+                        screen->flags |= VTE_FLAG_7BIT_MODE;
+                else
+                        screen->flags &= ~VTE_FLAG_7BIT_MODE;
+                break;
+        }
+#endif
+}
+
+void
+VteTerminalPrivate::DECSCP(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSCP - select-communication-port
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSCPP(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSCPP - select-columns-per-page
+         * Select columns per page. The number of rows is unaffected by this.
+         * @args[0] selectes the number of columns (width), DEC only defines 80
+         * and 132, but we allow any integer here. 0 is equivalent to 80.
+         * Page content is *not* cleared and the cursor is left untouched.
+         * However, if the page is reduced in width and the cursor would be
+         * outside the visible region, it's set to the right border. Newly added
+         * cells are cleared. No data is retained outside the visible region.
+         *
+         * Defaults:
+         *   args[0]: 0
+         *
+         * TODO: implement
+         */
+}
+
+void
+VteTerminalPrivate::DECSCS(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSCS - select-communication-speed
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSCUSR(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSCUSR - set-cursor-style
+         * This changes the style of the cursor. @args[0] can be one of:
+         *   0, 1: blinking block
+         *      2: steady block
+         *      3: blinking underline
+         *      4: steady underline
+         * Changing this setting does _not_ affect the cursor visibility itself.
+         * Use DECTCEM for that.
+         *
+         * Defaults:
+         *   args[0]: 0
+         */
+
+        seq_set_cursor_style(seq);
+}
+
+void
+VteTerminalPrivate::DECSDDT(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSDDT - select-disconnect-delay-time
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSDPT(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSDPT - select-digital-printed-data-type
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSED(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSED - selective-erase-in-display
+         * This control function erases some or all of the erasable characters
+         * in the display. DECSED can only erase characters defined as erasable
+         * by the DECSCA control function. DECSED works inside or outside the
+         * scrolling margins.
+         *
+         * @args[0] defines which regions are erased. If it is 0, all cells from
+         * the cursor (inclusive) till the end of the display are erase. If it
+         * is 1, all cells from the start of the display till the cursor
+         * (inclusive) are erased. If it is 2, all cells are erased.
+         *
+         * Defaults:
+         *   args[0]: 0
+         */
+
+        erase_in_display(seq);
+}
+
+void
+VteTerminalPrivate::DECSEL(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSEL - selective-erase-in-line
+         * This control function erases some or all of the erasable characters
+         * in a single line of text. DECSEL erases only those characters defined
+         * as erasable by the DECSCA control function. DECSEL works inside or
+         * outside the scrolling margins.
+         *
+         * @args[0] defines the region to be erased. If it is 0, all cells from
+         * the cursor (inclusive) till the end of the line are erase. If it is
+         * 1, all cells from the start of the line till the cursor (inclusive)
+         * are erased. If it is 2, the whole line of the cursor is erased.
+         *
+         * Defaults:
+         *   args[0]: 0
+         */
+
+        erase_in_line(seq);
+}
+
+void
+VteTerminalPrivate::DECSERA(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSERA - selective-erase-rectangular-area
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSFC(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSFC - select-flow-control
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSKCV(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSKCV - set-key-click-volume
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSLCK(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSLCK - set-lock-key-style
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSLE(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSLE - select-locator-events
+         *
+         * TODO: implement
+         */
+}
+
+void
+VteTerminalPrivate::DECSLPP(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSLPP - set-lines-per-page
+         * Set the number of lines used for the page. @args[0] specifies the
+         * number of lines to be used. DEC only allows a limited number of
+         * choices, however, we allow all integers. 0 is equivalent to 24.
+         *
+         * Defaults:
+         *   args[0]: 0
+         *
+         * TODO: implement
+         */
+}
+
+void
+VteTerminalPrivate::DECSLRM_OR_SC(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSLRM_OR_SC - set-left-and-right-margins or save-cursor
+         *
+         * TODO: Detect save-cursor and run it. DECSLRM is not worth
+         *       implementing.
+         */
+
+        //FIXMEchpe
+        seq_save_cursor(seq);
+}
+
+void
+VteTerminalPrivate::DECSMBV(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSMBV - set-margin-bell-volume
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSMKR(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSMKR - select-modifier-key-reporting
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSNLS(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSNLS - set-lines-per-screen
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSPP(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSPP - set-port-parameter
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSPPCS(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSPPCS - select-pro-printer-character-set
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSPRTT(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSPRTT - select-printer-type
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSR(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSR - secure-reset
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSRFR(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSRFR - select-refresh-rate
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSSCLS(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSSCLS - set-scroll-speed
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSSDT(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSSDT - select-status-display-line-type
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSSL(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSSL - select-setup-language
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECST8C(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECST8C - set-tab-at-every-8-columns
+         * Clear the tab-ruler and reset it to a tab at every 8th column,
+         * starting at 9 (though, setting a tab at 1 is fine as it has no
+         * effect).
+         */
+#if 0
+        unsigned int i;
+
+        for (i = 0; i < screen->page->width; i += 8)
+                screen->tabs[i / 8] = 0x1;
+#endif
+}
+
+void
+VteTerminalPrivate::DECSTBM(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSTBM - set-top-and-bottom-margins
+         * This call resets the cursor position to (1,1).
+         *
+         * Defaults:
+         *   args[0]: 1
+         *   args[1]: last page-line
+         */
+#if 0
+        unsigned int top, bottom;
+
+        top = 1;
+        bottom = screen->page->height;
+
+        if (seq->args[0] > 0)
+                top = seq->args[0];
+        if (seq->args[1] > 0)
+                bottom = seq->args[1];
+
+        if (top > screen->page->height)
+                top = screen->page->height;
+        if (bottom > screen->page->height)
+                bottom = screen->page->height;
+
+        if (top >= bottom ||
+            top > screen->page->height ||
+            bottom > screen->page->height) {
+                top = 1;
+                bottom = screen->page->height;
+        }
+
+        vte_page_set_scroll_region(screen->page, top - 1, bottom - top + 1);
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_set(screen, 0, 0);
+#endif
+
+        seq_set_scrolling_region(seq);
+}
+
+void
+VteTerminalPrivate::DECSTR(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSTR - soft-terminal-reset
+         * Perform a soft reset to the default values.
+         */
+#if 0
+        vte_screen_soft_reset(screen);
+#endif
+
+        seq_soft_reset(seq);
+}
+
+void
+VteTerminalPrivate::DECSTRL(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSTRL - set-transmit-rate-limit
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSWBV(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSWBV - set-warning-bell-volume
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECSWL(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECSWL - single-width-single-height-line
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECTID(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECTID - select-terminal-id
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECTME(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECTME - terminal-mode-emulation
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DECTST(vte::parser::Sequence const& seq)
+{
+        /*
+         * DECTST - invoke-confidence-test
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::DL(vte::parser::Sequence const& seq)
+{
+        /*
+         * DL - delete-line
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        vte_page_delete_lines(screen->page,
+                                 screen->state.cursor_y,
+                                 num,
+                                 &screen->state.attr,
+                                 screen->age);
+#endif
+
+        seq_delete_lines(seq);
+}
+
+void
+VteTerminalPrivate::DSR_ANSI(vte::parser::Sequence const& seq)
+{
+        /*
+         * DSR_ANSI - device-status-report-ansi
+         *
+         * TODO: implement
+         */
+
+        seq_device_status_report(seq);
+}
+
+void
+VteTerminalPrivate::DSR_DEC(vte::parser::Sequence const& seq)
+{
+        /*
+         * DSR_DEC - device-status-report-dec
+         *
+         * TODO: implement
+         */
+
+        seq_dec_device_status_report(seq);
+}
+
+void
+VteTerminalPrivate::ECH(vte::parser::Sequence const& seq)
+{
+        /*
+         * ECH - erase-character
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        vte_page_erase(screen->page,
+                          screen->state.cursor_x, screen->state.cursor_y,
+                          screen->state.cursor_x + num, screen->state.cursor_y,
+                          &screen->state.attr, screen->age, false);
+#endif
+
+        seq_erase_characters(seq);
+}
+
+void
+VteTerminalPrivate::ED(vte::parser::Sequence const& seq)
+{
+        /*
+         * ED - erase-in-display
+         *
+         * Defaults:
+         *   args[0]: 0
+         */
+
+        erase_in_display(seq);
+}
+
+void
+VteTerminalPrivate::EL(vte::parser::Sequence const& seq)
+{
+        /*
+         * EL - erase-in-line
+         *
+         * Defaults:
+         *   args[0]: 0
+         */
+
+        erase_in_line(seq);
+}
+
+void
+VteTerminalPrivate::ENQ(vte::parser::Sequence const& seq)
+{
+        /*
+         * ENQ - enquiry
+         * Transmit the answerback-string. If none is set, do nothing.
+         */
+#if 0
+        if (screen->answerback)
+                return screen_write(screen,
+                                    screen->answerback,
+                                    strlen(screen->answerback));
+#endif
+
+        seq_return_terminal_status(seq);
+}
+
+void
+VteTerminalPrivate::EPA(vte::parser::Sequence const& seq)
+{
+        /*
+         * EPA - end-of-guarded-area
+         *
+         * TODO: What is this?
+         */
+}
+
+void
+VteTerminalPrivate::FF(vte::parser::Sequence const& seq)
+{
+        /*
+         * FF - form-feed
+         * This causes the cursor to jump to the next line. It is treated the
+         * same as LF.
+         */
+
+#if 0
+        screen_LF(screen, seq);
+#endif
+
+        seq_form_feed(seq);
+}
+
+void
+VteTerminalPrivate::HPA(vte::parser::Sequence const& seq)
+{
+        /*
+         * HPA - horizontal-position-absolute
+         * HPA causes the active position to be moved to the n-th horizontal
+         * position of the active line. If an attempt is made to move the active
+         * position past the last position on the line, then the active position
+         * stops at the last position on the line.
+         *
+         * @args[0] defines the horizontal position. 0 is treated as 1.
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_set(screen, num - 1, screen->state.cursor_y);
+#endif
+
+        seq_character_position_absolute(seq);
+}
+
+void
+VteTerminalPrivate::HPR(
+                      vte::parser::Sequence const& seq)
+{
+        /*
+         * HPR - horizontal-position-relative
+         * HPR causes the active position to be moved to the n-th following
+         * horizontal position of the active line. If an attempt is made to move
+         * the active position past the last position on the line, then the
+         * active position stops at the last position on the line.
+         *
+         * @args[0] defines the horizontal position. 0 is treated as 1.
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_right(screen, num);
+#endif
+}
+
+void
+VteTerminalPrivate::HT(vte::parser::Sequence const& seq)
+{
+        /*
+         * HT - horizontal-tab
+         * Moves the cursor to the next tab stop. If there are no more tab
+         * stops, the cursor moves to the right margin. HT does not cause text
+         * to auto wrap.
+         */
+#if 0
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_right_tab(screen, 1);
+#endif
+
+        seq_tab(seq);
+}
+
+void
+VteTerminalPrivate::HTS(vte::parser::Sequence const& seq)
+{
+        /*
+         * HTS - horizontal-tab-set
+         *
+         * XXX
+         */
+#if 0
+        unsigned int pos;
+
+        pos = screen->state.cursor_x;
+        if (screen->page->width > 0)
+                screen->tabs[pos / 8] |= 1U << (pos % 8);
+#endif
+
+        seq_tab_set(seq);
+}
+
+void
+VteTerminalPrivate::HVP(vte::parser::Sequence const& seq)
+{
+        /*
+         * HVP - horizontal-and-vertical-position
+         * XXX
+         *
+         * Defaults:
+         *   args[0]: 1
+         *   args[1]: 1
+         *
+         * References: ECMA-48 FIXME
+         *             VT525
+         */
+
+        CUP(seq);
+}
+
+void
+VteTerminalPrivate::ICH(vte::parser::Sequence const& seq)
+{
+        /*
+         * ICH - insert-character
+         * XXX
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        screen_cursor_clear_wrap(screen);
+        vte_page_insert_cells(screen->page,
+                                 screen->state.cursor_x,
+                                 screen->state.cursor_y,
+                                 num,
+                                 &screen->state.attr,
+                                 screen->age);
+#endif
+
+        seq_insert_blank_characters(seq);
+}
+
+void
+VteTerminalPrivate::IL(vte::parser::Sequence const& seq)
+{
+        /*
+         * IL - insert-line
+         * XXX
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        screen_cursor_clear_wrap(screen);
+        vte_page_insert_lines(screen->page,
+                                 screen->state.cursor_y,
+                                 num,
+                                 &screen->state.attr,
+                                 screen->age);
+#endif
+
+        seq_insert_lines(seq);
+}
+
+void
+VteTerminalPrivate::IND(vte::parser::Sequence const& seq)
+{
+        /*
+         * IND - index - DEPRECATED
+         */
+#if 0
+        screen_cursor_down(screen, 1, true);
+#endif
+
+        seq_index(seq);
+}
+
+void
+VteTerminalPrivate::LF(vte::parser::Sequence const& seq)
+{
+        /*
+         * LF - line-feed
+         */
+
+#if 0
+        screen_cursor_down(screen, 1, true);
+        if (screen->flags & VTE_FLAG_NEWLINE_MODE)
+                screen_cursor_left(screen, screen->state.cursor_x);
+#endif
+
+        seq_line_feed(seq);
+}
+
+void
+VteTerminalPrivate::LS1R(vte::parser::Sequence const& seq)
+{
+        /*
+         * LS1R - locking-shift-1-right
+         * Map G1 into GR.
+         */
+#if 0
+        screen->state.gr = &screen->g1;
+#endif
+}
+
+void
+VteTerminalPrivate::LS2(vte::parser::Sequence const& seq)
+{
+        /*
+         * LS2 - locking-shift-2
+         * Map G2 into GL.
+         */
+#if 0
+        screen->state.gl = &screen->g2;
+#endif
+}
+
+void
+VteTerminalPrivate::LS2R(vte::parser::Sequence const& seq)
+{
+        /*
+         * LS2R - locking-shift-2-right
+         * Map G2 into GR.
+         */
+#if 0
+        screen->state.gr = &screen->g2;
+#endif
+}
+
+void
+VteTerminalPrivate::LS3(vte::parser::Sequence const& seq)
+{
+        /*
+         * LS3 - locking-shift-3
+         * Map G3 into GL.
+         */
+
+#if 0
+        screen->state.gl = &screen->g3;
+#endif
+}
+
+void
+VteTerminalPrivate::LS3R(vte::parser::Sequence const& seq)
+{
+        /*
+         * LS3R - locking-shift-3-right
+         * Map G3 into GR.
+         */
+#if 0
+        screen->state.gr = &screen->g3;
+#endif
+}
+
+void
+VteTerminalPrivate::MC_ANSI(vte::parser::Sequence const& seq)
+{
+        /*
+         * MC_ANSI - media-copy-ansi
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::MC_DEC(vte::parser::Sequence const& seq)
+{
+        /*
+         * MC_DEC - media-copy-dec
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::NEL(vte::parser::Sequence const& seq)
+{
+        /*
+         * NEL - next-line
+         * XXX
+         */
+#if 0
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_down(screen, 1, true);
+        screen_cursor_set(screen, 0, screen->state.cursor_y);
+#endif
+
+        seq_next_line(seq);
+}
+
+void
+VteTerminalPrivate::NP(vte::parser::Sequence const& seq)
+{
+        /*
+         * NP - next-page
+         * XXX
+         *
+         * Defaults:
+         *   args[0]: 1
+         *
+         * Probably not worth implementing. We only support a single page.
+         */
+}
+
+void
+VteTerminalPrivate::NUL(vte::parser::Sequence const& seq)
+{
+        /*
+         */
+}
+
+void
+VteTerminalPrivate::PP(vte::parser::Sequence const& seq)
+{
+        /*
+         * PP - preceding-page
+         * XXX
+         *
+         * Defaults:
+         *   args[0]: 1
+         *
+         * Probably not worth implementing. We only support a single page.
+         */
+}
+
+void
+VteTerminalPrivate::PPA(vte::parser::Sequence const& seq)
+{
+        /*
+         * PPA - page-position-absolute
+         * XXX
+         *
+         * Defaults:
+         *   args[0]: 1
+         *
+         * Probably not worth implementing. We only support a single page.
+         */
+}
+
+void
+VteTerminalPrivate::PPB(vte::parser::Sequence const& seq)
+{
+        /*
+         * PPB - page-position-backward
+         * XXX
+         *
+         * Defaults:
+         *   args[0]: 1
+         *
+         * Probably not worth implementing. We only support a single page.
+         */
+}
+
+void
+VteTerminalPrivate::PPR(vte::parser::Sequence const& seq)
+{
+        /*
+         * PPR - page-position-relative
+         * XXX
+         *
+         * Defaults:
+         *   args[0]: 1
+         *
+         * Probably not worth implementing. We only support a single page.
+         */
+}
+
+void
+VteTerminalPrivate::RC(vte::parser::Sequence const& seq)
+{
+        /*
+         * RC - restore-cursor
+         */
+
+#if 0
+        screen_DECRC(screen, seq);
+#endif
+}
+
+void
+VteTerminalPrivate::REP(vte::parser::Sequence const& seq)
+{
+        /*
+         * REP - repeat
+         * Repeat the preceding graphics-character the given number of times.
+         * @args[0] specifies how often it shall be repeated. 0 is treated as 1.
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+
+        seq_repeat(seq);
+}
+
+void
+VteTerminalPrivate::RI(vte::parser::Sequence const& seq)
+{
+        /*
+         * RI - reverse-index
+         * Moves the cursor up one line in the same column. If the cursor is at
+         * the top margin, the page scrolls down.
+         */
+#if 0
+        screen_cursor_up(screen, 1, true);
+#endif
+
+        seq_reverse_index(seq);
+}
+
+void
+VteTerminalPrivate::RIS(vte::parser::Sequence const& seq)
+{
+        /*
+         * RIS - reset-to-initial-state
+         * XXX
+         */
+
+#if 0
+        vte_screen_hard_reset(screen);
+#endif
+
+        seq_full_reset(seq);
+}
+
+void
+VteTerminalPrivate::RM_ANSI(vte::parser::Sequence const& seq)
+{
+        /*
+         * RM_ANSI - reset-mode-ansi
+         *
+         * TODO: implement (see VT510rm manual)
+         */
+#if 0
+        unsigned int i;
+
+        for (i = 0; i < seq->n_args; ++i)
+                screen_mode_change_ansi(screen, seq->args[i], false);
+#endif
+
+        seq_reset_mode(seq);
+}
+
+void
+VteTerminalPrivate::RM_DEC(vte::parser::Sequence const& seq)
+{
+        /*
+         * RM_DEC - reset-mode-dec
+         * This is the same as RM_ANSI but for DEC modes.
+         */
+#if 0
+        unsigned int i;
+
+        for (i = 0; i < seq->n_args; ++i)
+                screen_mode_change_dec(screen, seq->args[i], false);
+#endif
+
+        seq_decreset(seq);
+}
+
+void
+VteTerminalPrivate::S7C1T(vte::parser::Sequence const& seq)
+{
+        /*
+         * S7C1T - set-7bit-c1-terminal
+         * This causes the terminal to start sending C1 controls as 7bit
+         * sequences instead of 8bit C1 controls.
+         * This is ignored if the terminal is below level-2 emulation mode
+         * (VT100 and below), the terminal already sends 7bit controls then.
+         */
+
+#if 0
+        if (screen->conformance_level > VTE_CONFORMANCE_LEVEL_VT100)
+                screen->flags |= VTE_FLAG_7BIT_MODE;
+#endif
+}
+
+void
+VteTerminalPrivate::S8C1T(vte::parser::Sequence const& seq)
+{
+        /*
+         * S8C1T - set-8bit-c1-terminal
+         * This causes the terminal to start sending C1 controls as 8bit C1
+         * control instead of 7bit sequences.
+         * This is ignored if the terminal is below level-2 emulation mode
+         * (VT100 and below). The terminal always sends 7bit controls in those
+         * modes.
+         */
+#if 0
+        if (screen->conformance_level > VTE_CONFORMANCE_LEVEL_VT100)
+                screen->flags &= ~VTE_FLAG_7BIT_MODE;
+#endif
+}
+
+void
+VteTerminalPrivate::SCS(vte::parser::Sequence const& seq)
+{
+        /*
+         * SCS - select-character-set
+         * Designate character sets to G-sets. The mapping from intermediates
+         * and terminal characters in the escape sequence to G-sets and
+         * character-sets is non-trivial and implemented separately. See there
+         * for more information.
+         * This call simply sets the selected G-set to the desired
+         * character-set.
+         */
+#if 0
+        vte_charset *cs = NULL;
+
+        /* TODO: support more of them? */
+        switch (seq->charset) {
+        case VTE_CHARSET_ISO_LATIN1_SUPPLEMENTAL:
+        case VTE_CHARSET_ISO_LATIN2_SUPPLEMENTAL:
+        case VTE_CHARSET_ISO_LATIN5_SUPPLEMENTAL:
+        case VTE_CHARSET_ISO_GREEK_SUPPLEMENTAL:
+        case VTE_CHARSET_ISO_HEBREW_SUPPLEMENTAL:
+        case VTE_CHARSET_ISO_LATIN_CYRILLIC:
+                break;
+
+        case VTE_CHARSET_DEC_SPECIAL_GRAPHIC:
+                cs = &vte_dec_special_graphics;
+                break;
+        case VTE_CHARSET_DEC_SUPPLEMENTAL:
+                cs = &vte_dec_supplemental_graphics;
+                break;
+        case VTE_CHARSET_DEC_TECHNICAL:
+        case VTE_CHARSET_CYRILLIC_DEC:
+        case VTE_CHARSET_DUTCH_NRCS:
+        case VTE_CHARSET_FINNISH_NRCS:
+        case VTE_CHARSET_FRENCH_NRCS:
+        case VTE_CHARSET_FRENCH_CANADIAN_NRCS:
+        case VTE_CHARSET_GERMAN_NRCS:
+        case VTE_CHARSET_GREEK_DEC:
+        case VTE_CHARSET_GREEK_NRCS:
+        case VTE_CHARSET_HEBREW_DEC:
+        case VTE_CHARSET_HEBREW_NRCS:
+        case VTE_CHARSET_ITALIAN_NRCS:
+        case VTE_CHARSET_NORWEGIAN_DANISH_NRCS:
+        case VTE_CHARSET_PORTUGUESE_NRCS:
+        case VTE_CHARSET_RUSSIAN_NRCS:
+        case VTE_CHARSET_SCS_NRCS:
+        case VTE_CHARSET_SPANISH_NRCS:
+        case VTE_CHARSET_SWEDISH_NRCS:
+        case VTE_CHARSET_SWISS_NRCS:
+        case VTE_CHARSET_TURKISH_DEC:
+        case VTE_CHARSET_TURKISH_NRCS:
+                break;
+
+        case VTE_CHARSET_USERPREF_SUPPLEMENTAL:
+                break;
+        }
+
+        if (seq->intermediates & VTE_SEQ_FLAG_POPEN)
+                screen->g0 = cs ? : &vte_unicode_lower;
+        else if (seq->intermediates & VTE_SEQ_FLAG_PCLOSE)
+                screen->g1 = cs ? : &vte_unicode_upper;
+        else if (seq->intermediates & VTE_SEQ_FLAG_MULT)
+                screen->g2 = cs ? : &vte_unicode_lower;
+        else if (seq->intermediates & VTE_SEQ_FLAG_PLUS)
+                screen->g3 = cs ? : &vte_unicode_upper;
+        else if (seq->intermediates & VTE_SEQ_FLAG_MINUS)
+                screen->g1 = cs ? : &vte_unicode_upper;
+        else if (seq->intermediates & VTE_SEQ_FLAG_DOT)
+                screen->g2 = cs ? : &vte_unicode_lower;
+        else if (seq->intermediates & VTE_SEQ_FLAG_SLASH)
+                screen->g3 = cs ? : &vte_unicode_upper;
+#endif
+
+        // FIXMEchpe: seq_designate_*(seq);
+        set_character_replacements(0, VTE_CHARACTER_REPLACEMENT_NONE);
+}
+
+void
+VteTerminalPrivate::SD(vte::parser::Sequence const& seq)
+{
+        /*
+         * SD - scroll-down
+         * XXX
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        vte_page_scroll_down(screen->page,
+                                num,
+                                &screen->state.attr,
+                                screen->age,
+                                NULL);
+#endif
+
+        seq_scroll_down(seq);
+}
+
+void
+VteTerminalPrivate::SGR(vte::parser::Sequence const& seq)
+{
+        /*
+         * SGR - select-graphics-rendition
+         */
+#if 0
+        struct vte_color *dst;
+        unsigned int i, code;
+        int v;
+
+        if (seq->n_args < 1) {
+                memset(&screen->state.attr, 0, sizeof(screen->state.attr));
+                return 0;
+        }
+
+        for (i = 0; i < seq->n_args; ++i) {
+                v = seq->args[i];
+                switch (v) {
+                case 1:
+                        screen->state.attr.bold = 1;
+                        break;
+                case 3:
+                        screen->state.attr.italic = 1;
+                        break;
+                case 4:
+                        screen->state.attr.underline = 1;
+                        break;
+                case 5:
+                        screen->state.attr.blink = 1;
+                        break;
+                case 7:
+                        screen->state.attr.inverse = 1;
+                        break;
+                case 8:
+                        screen->state.attr.hidden = 1;
+                        break;
+                case 22:
+                        screen->state.attr.bold = 0;
+                        break;
+                case 23:
+                        screen->state.attr.italic = 0;
+                        break;
+                case 24:
+                        screen->state.attr.underline = 0;
+                        break;
+                case 25:
+                        screen->state.attr.blink = 0;
+                        break;
+                case 27:
+                        screen->state.attr.inverse = 0;
+                        break;
+                case 28:
+                        screen->state.attr.hidden = 0;
+                        break;
+                case 30 ... 37:
+                        screen->state.attr.fg.ccode = v - 30 +
+                                                      VTE_CCODE_BLACK;
+                        break;
+                case 39:
+                        screen->state.attr.fg.ccode = 0;
+                        break;
+                case 40 ... 47:
+                        screen->state.attr.bg.ccode = v - 40 +
+                                                      VTE_CCODE_BLACK;
+                        break;
+                case 49:
+                        screen->state.attr.bg.ccode = 0;
+                        break;
+                case 90 ... 97:
+                        screen->state.attr.fg.ccode = v - 90 +
+                                                      VTE_CCODE_LIGHT_BLACK;
+                        break;
+                case 100 ... 107:
+                        screen->state.attr.bg.ccode = v - 100 +
+                                                      VTE_CCODE_LIGHT_BLACK;
+                        break;
+                case 38:
+                        /* fallthrough */
+                case 48:
+
+                        if (v == 38)
+                                dst = &screen->state.attr.fg;
+                        else
+                                dst = &screen->state.attr.bg;
+
+                        ++i;
+                        if (i >= seq->n_args)
+                                break;
+
+                        switch (seq->args[i]) {
+                        case 2:
+                                /* 24bit-color support */
+
+                                i += 3;
+                                if (i >= seq->n_args)
+                                        break;
+
+                                dst->ccode = VTE_CCODE_RGB;
+                                dst->red = (seq->args[i - 2] >= 0) ? seq->args[i - 2] : 0;
+                                dst->green = (seq->args[i - 1] >= 0) ? seq->args[i - 1] : 0;
+                                dst->blue = (seq->args[i] >= 0) ? seq->args[i] : 0;
+
+                                break;
+                        case 5:
+                                /* 256-color support */
+
+                                ++i;
+                                if (i >= seq->n_args || seq->args[i] < 0)
+                                        break;
+
+                                dst->ccode = VTE_CCODE_256;
+                                code = seq->args[i];
+                                dst->c256 = code < 256 ? code : 0;
+
+                                break;
+                        }
+
+                        break;
+                case -1:
+                        /* fallthrough */
+                case 0:
+                        memset(&screen->state.attr, 0,
+                               sizeof(screen->state.attr));
+                        break;
+                }
+        }
+#endif
+
+        seq_character_attributes(seq);
+}
+
+void
+VteTerminalPrivate::SI(vte::parser::Sequence const& seq)
 {
-#include "caps-list.hh"
-        *n_entries = G_N_ELEMENTS (entries);
-        return entries;
+        /*
+         * SI - shift-in
+         * Map G0 into GL.
+         */
+#if 0
+        screen->state.gl = &screen->g0;
+#endif
+
+        seq_shift_in(seq);
+}
+
+void
+VteTerminalPrivate::SM_ANSI(vte::parser::Sequence const& seq)
+{
+        /*
+         * SM_ANSI - set-mode-ansi
+         *
+         * TODO: implement
+         */
+#if 0
+        unsigned int i;
+
+        for (i = 0; i < seq->n_args; ++i)
+                screen_mode_change_ansi(screen, seq->args[i], true);
+#endif
+
+        seq_set_mode(seq);
+}
+
+void
+VteTerminalPrivate::SM_DEC(vte::parser::Sequence const& seq)
+{
+        /*
+         * SM_DEC - set-mode-dec
+         * This is the same as SM_ANSI but for DEC modes.
+         */
+#if 0
+        unsigned int i;
+
+        for (i = 0; i < seq->n_args; ++i)
+                screen_mode_change_dec(screen, seq->args[i], true);
+#endif
+
+        seq_decset(seq);
+}
+
+void
+VteTerminalPrivate::SO(vte::parser::Sequence const& seq)
+{
+        /*
+         * SO - shift-out
+         * Map G1 into GL.
+         */
+#if 0
+        screen->state.gl = &screen->g1;
+#endif
+
+        seq_shift_out(seq);
+}
+
+void
+VteTerminalPrivate::SPA(vte::parser::Sequence const& seq)
+{
+        /*
+         * SPA - start-of-protected-area
+         *
+         * TODO: What is this?
+         */
+}
+
+void
+VteTerminalPrivate::SS2(vte::parser::Sequence const& seq)
+{
+        /*
+         * SS2 - single-shift-2
+         * Temporarily map G2 into GL for the next graphics character.
+         */
+#if 0
+        screen->state.glt = &screen->g2;
+#endif
+}
+
+void
+VteTerminalPrivate::SS3(vte::parser::Sequence const& seq)
+{
+        /*
+         * SS3 - single-shift-3
+         * Temporarily map G3 into GL for the next graphics character
+         */
+#if 0
+        screen->state.glt = &screen->g3;
+#endif
+}
+
+void
+VteTerminalPrivate::ST(vte::parser::Sequence const& seq)
+{
+        /*
+         * ST - string-terminator
+         * The string-terminator is usually part of control-sequences and
+         * handled by the parser. In all other situations it is silently
+         * ignored.
+         */
+}
+
+void
+VteTerminalPrivate::SU(vte::parser::Sequence const& seq)
+{
+        /*
+         * SU - scroll-up
+         * XXX
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        vte_page_scroll_up(screen->page,
+                              num,
+                              &screen->state.attr,
+                              screen->age,
+                              screen->history);
+#endif
+
+        seq_scroll_up(seq);
+}
+
+void
+VteTerminalPrivate::SUB(vte::parser::Sequence const& seq)
+{
+        /*
+         * SUB - substitute
+         * Cancel the current control-sequence and print a replacement
+         * character. Our parser already handles this so all we have to do is
+         * print the replacement character.
+         */
+#if 0
+        static const struct vte_seq rep = {
+                .type = VTE_SEQ_GRAPHIC,
+                .command = VTE_CMD_GRAPHIC,
+                .terminator = 0xfffd,
+        };
+
+        return screen_GRAPHIC(screen, &rep);
+#endif
+}
+
+void
+VteTerminalPrivate::TBC(vte::parser::Sequence const& seq)
+{
+        /*
+         * TBC - tab-clear
+         * Clears tab stops.
+         *
+         * Arguments:
+         *   args[0]: mode
+         *
+         * Defaults:
+         *   args[0]: 0
+         */
+#if 0
+        unsigned int mode = 0, pos;
+
+        if (seq->args[0] > 0)
+                mode = seq->args[0];
+
+        switch (mode) {
+        case 0:
+                pos = screen->state.cursor_x;
+                if (screen->page->width > 0)
+                        screen->tabs[pos / 8] &= ~(1U << (pos % 8));
+                break;
+        case 3:
+                if (screen->page->width > 0)
+                        memset(screen->tabs, 0, (screen->page->width + 7) / 8);
+                break;
+        }
+#endif
+
+        seq_tab_clear(seq);
+}
+
+void
+VteTerminalPrivate::VPA(vte::parser::Sequence const& seq)
+{
+        /*
+         * VPA - vertical-line-position-absolute
+         * XXX
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+        unsigned int pos = 1;
+
+        if (seq->args[0] > 0)
+                pos = seq->args[0];
+
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_set_rel(screen, screen->state.cursor_x, pos - 1);
+#endif
+
+        seq_line_position_absolute(seq);
+}
+
+void
+VteTerminalPrivate::VPR(vte::parser::Sequence const& seq)
+{
+        /*
+         * VPR - vertical-line-position-relative
+         * XXX
+         *
+         * Defaults:
+         *   args[0]: 1
+         */
+#if 0
+        unsigned int num = 1;
+
+        if (seq->args[0] > 0)
+                num = seq->args[0];
+
+        screen_cursor_clear_wrap(screen);
+        screen_cursor_down(screen, num, false);
+#endif
+}
+
+void
+VteTerminalPrivate::VT(vte::parser::Sequence const& seq)
+{
+        /*
+         * VT - vertical-tab
+         * This causes a vertical jump by one line. Terminals treat it exactly
+         * the same as LF.
+         */
+
+        LF(seq);
+}
+
+void
+VteTerminalPrivate::XTERM_CLLHP(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_CLLHP - xterm-cursor-lower-left-hp-bugfix
+         * Move the cursor to the lower-left corner of the page. This is an HP
+         * bugfix by xterm.
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::XTERM_IHMT(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_IHMT - xterm-initiate-highlight-mouse-tracking
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::XTERM_MLHP(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_MLHP - xterm-memory-lock-hp-bugfix
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::XTERM_MUHP(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_MUHP - xterm-memory-unlock-hp-bugfix
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::XTERM_RPM(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_RPM - xterm-restore-private-mode
+         */
+
+        seq_restore_mode(seq);
+}
+
+void
+VteTerminalPrivate::XTERM_RRV(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_RRV - xterm-reset-resource-value
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::XTERM_RTM(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_RTM - xterm-reset-title-mode
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::XTERM_SACL1(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_SACL1 - xterm-set-ansi-conformance-level-1
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::XTERM_SACL2(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_SACL2 - xterm-set-ansi-conformance-level-2
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::XTERM_SACL3(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_SACL3 - xterm-set-ansi-conformance-level-3
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::XTERM_SDCS(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_SDCS - xterm-set-default-character-set
+         * Select the default character set. We treat this the same as UTF-8 as
+         * this is our default character set. As we always use UTF-8, this
+         * becomes as no-op.
+         */
+}
+
+void
+VteTerminalPrivate::XTERM_SGFX(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_SGFX - xterm-sixel-graphics
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::XTERM_SPM(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_SPM - xterm-set-private-mode
+         */
+
+        seq_save_mode(seq);
+}
+
+void
+VteTerminalPrivate::XTERM_SRV(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_SRV - xterm-set-resource-value
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::XTERM_STM(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_STM - xterm-set-title-mode
+         *
+         * Probably not worth implementing.
+         */
+}
+
+void
+VteTerminalPrivate::XTERM_SUCS(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_SUCS - xterm-select-utf8-character-set
+         * Select UTF-8 as character set. This is our default and only
+         * character set. Hence, this is a no-op.
+         */
+}
+
+void
+VteTerminalPrivate::XTERM_WM(vte::parser::Sequence const& seq)
+{
+        /*
+         * XTERM_WM - xterm-window-management
+         *
+         * Probably not worth implementing.
+         */
+
+        seq_window_manipulation(seq);
 }


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