[vte] parser: glue: Add sequence builder



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

    parser: glue: Add sequence builder
    
    ... and use it throughout.

 src/Makefile.am     |    3 +
 src/debug.cc        |    1 +
 src/debug.h         |    1 +
 src/parser-arg.hh   |    9 +
 src/parser-cat.cc   |    3 +
 src/parser-glue.hh  |  312 +++++++++++++++++++++++++++++++
 src/parser-reply.hh |   54 ++++++
 src/parser-test.cc  |   15 ++
 src/parser.hh       |   42 ++++
 src/vte.cc          |   83 ++++++++-
 src/vteinternal.hh  |   15 ++
 src/vteseq.cc       |  515 ++++++++++++++++++++++++++++++---------------------
 12 files changed, 836 insertions(+), 217 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 5e3dff4..f5f1434 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -66,6 +66,7 @@ libvte_@VTE_API_MAJOR_VERSION@_@VTE_API_MINOR_VERSION@_la_SOURCES = \
        parser-cmd.hh \
        parser-glue.hh \
        parser-osc.hh \
+       parser-reply.hh \
        parser-string.hh \
        pty.cc \
        reaper.cc \
@@ -250,6 +251,7 @@ parser_cat_SOURCES = \
        parser-cmd.hh \
        parser-glue.hh \
        parser-osc.hh \
+       parser-reply.hh \
        parser-string.hh \
        parser-cat.cc \
        vteconv.cc \
@@ -285,6 +287,7 @@ test_parser_SOURCES = \
        parser-charset-tables.hh \
        parser-glue.hh \
        parser-osc.hh \
+       parser-reply.hh \
        parser-string.hh \
        $(NULL)
 test_parser_CPPFLAGS = \
diff --git a/src/debug.cc b/src/debug.cc
index 0101f69..03f8fd0 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -56,6 +56,7 @@ _vte_debug_init(void)
     { "regex",        VTE_DEBUG_REGEX        },
     { "hyperlink",    VTE_DEBUG_HYPERLINK    },
     { "modes",        VTE_DEBUG_MODES        },
+    { "emulation",    VTE_DEBUG_EMULATION    },
   };
 
   _vte_debug_flags = g_parse_debug_string (g_getenv("VTE_DEBUG"),
diff --git a/src/debug.h b/src/debug.h
index e5222bd..d9eb601 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -63,6 +63,7 @@ typedef enum {
         VTE_DEBUG_REGEX         = 1 << 23,
         VTE_DEBUG_HYPERLINK     = 1 << 24,
         VTE_DEBUG_MODES         = 1 << 25,
+        VTE_DEBUG_EMULATION     = 1 << 26,
 } VteDebugFlags;
 
 void _vte_debug_init(void);
diff --git a/src/parser-arg.hh b/src/parser-arg.hh
index 0f94832..a61d323 100644
--- a/src/parser-arg.hh
+++ b/src/parser-arg.hh
@@ -116,6 +116,15 @@ static inline void vte_seq_arg_finish(vte_seq_arg_t* arg,
                 *arg |= VTE_SEQ_ARG_FLAG_NONFINAL;
 }
 
+static inline void vte_seq_arg_refinish(vte_seq_arg_t* arg,
+                                        bool nonfinal = false)
+{
+        if (nonfinal)
+                *arg |= VTE_SEQ_ARG_FLAG_NONFINAL;
+        else
+                *arg &= ~VTE_SEQ_ARG_FLAG_NONFINAL;
+}
+
 /*
  * vte_seq_arg_started:
  * @arg:
diff --git a/src/parser-cat.cc b/src/parser-cat.cc
index 6953097..08d5412 100644
--- a/src/parser-cat.cc
+++ b/src/parser-cat.cc
@@ -45,6 +45,9 @@ seq_to_str(unsigned int type)
         case VTE_SEQ_CSI: return "CSI";
         case VTE_SEQ_DCS: return "DCS";
         case VTE_SEQ_OSC: return "OSC";
+        case VTE_SEQ_APC: return "APC";
+        case VTE_SEQ_PM: return "PM";
+        case VTE_SEQ_SOS: return "SOS";
         default:
                 assert(false);
         }
diff --git a/src/parser-glue.hh b/src/parser-glue.hh
index 5e4303e..27bb680 100644
--- a/src/parser-glue.hh
+++ b/src/parser-glue.hh
@@ -334,6 +334,318 @@ private:
         char const* command_string() const;
 };
 
+/* Helper classes to unify UTF-32 and UTF-8 versions of SequenceBuilder.
+ * ::put will only be called with C1 controls, so it's ok to simplify
+ * the UTF-8 version to simply prepend 0xc2.
+ */
+template<typename C>
+class DirectEncoder {
+public:
+        using string_type = std::basic_string<C>;
+        inline void put(string_type& s, C const c) const noexcept
+        {
+                s.push_back(c);
+        }
+};
+
+class UTF8Encoder {
+public:
+        using string_type = std::basic_string<char>;
+        inline void put(string_type& s, unsigned char const c) const noexcept
+        {
+                s.push_back(0xc2);
+                s.push_back(c);
+        }
+};
+
+template<class S, class E = DirectEncoder<typename S::value_type>>
+class SequenceBuilder {
+public:
+        using string_type = S;
+        using encoder_type = E;
+
+private:
+        struct vte_seq m_seq;
+        string_type m_arg_str;
+        unsigned char m_intermediates[4];
+        unsigned char m_n_intermediates{0};
+        unsigned char m_param_intro{0};
+        encoder_type m_encoder;
+
+public:
+        SequenceBuilder(unsigned int type = VTE_SEQ_NONE)
+        {
+                memset(&m_seq, 0, sizeof(m_seq));
+                set_type(type);
+        }
+
+        SequenceBuilder(unsigned int type,
+                        string_type const& str)
+                : SequenceBuilder(type)
+        {
+                set_string(str);
+        }
+
+        SequenceBuilder(unsigned int type,
+                        string_type&& str)
+                : SequenceBuilder(type)
+        {
+                set_string(str);
+        }
+
+        SequenceBuilder(SequenceBuilder const&) = delete;
+        SequenceBuilder(SequenceBuilder&&) = delete;
+        ~SequenceBuilder() = default;
+
+        SequenceBuilder& operator= (SequenceBuilder const&) = delete;
+        SequenceBuilder& operator= (SequenceBuilder&&) = delete;
+
+        inline void set_type(unsigned int type) noexcept
+        {
+                m_seq.type = type;
+        }
+
+        inline void set_final(uint32_t t) noexcept
+        {
+                m_seq.terminator = t;
+        }
+
+        inline void append_intermediate(unsigned char i) noexcept
+        {
+                assert(unsigned(m_n_intermediates + 1) <= 
(sizeof(m_intermediates)/sizeof(m_intermediates[0])));
+
+                m_seq.intermediates |= (1u << (i - 0x20));
+                m_intermediates[m_n_intermediates++] = i;
+        }
+
+        inline void append_intermediates(std::initializer_list<unsigned char> l) noexcept
+        {
+                assert(m_n_intermediates + l.size() <= (sizeof(m_intermediates)/sizeof(m_intermediates[0])));
+
+                for (uint32_t i : l) {
+                        m_seq.intermediates |= (1u << (i - 0x20));
+                        m_intermediates[m_n_intermediates++] = i;
+                }
+        }
+
+        inline void set_param_intro(unsigned char p) noexcept
+        {
+                m_param_intro = p;
+                if (p != 0) {
+                        m_seq.intermediates |= (1u << (p - 0x20));
+                }
+        }
+
+        inline void append_params(std::initializer_list<int> params) noexcept
+        {
+                assert(m_seq.n_args + params.size() <= (sizeof(m_seq.args) / sizeof(m_seq.args[0])));
+                for (int p : params)
+                        m_seq.args[m_seq.n_args++] = vte_seq_arg_init(std::min(p, 0xffff));
+        }
+
+        inline void append_subparams(std::initializer_list<int> subparams) noexcept
+        {
+                assert(m_seq.n_args + subparams.size() <= (sizeof(m_seq.args) / sizeof(m_seq.args[0])));
+                for (int p : subparams) {
+                        int* arg = &m_seq.args[m_seq.n_args++];
+                        *arg = vte_seq_arg_init(std::min(p, 0xffff));
+                        vte_seq_arg_finish(arg, false);
+                }
+                vte_seq_arg_refinish(&m_seq.args[m_seq.n_args - 1], true);
+        }
+
+        inline void set_string(string_type const& str) noexcept
+        {
+                m_arg_str = str;
+        }
+
+        inline void set_string(string_type&& str) noexcept
+        {
+                m_arg_str = str;
+        }
+
+        enum class ST {
+                NONE,
+                DEFAULT,
+                C0,
+                C1,
+                BEL
+        };
+
+
+private:
+        void append_introducer(string_type& s,
+                               bool c1 = true) const noexcept
+        {
+                /* Introducer */
+                if (c1) {
+                        switch (m_seq.type) {
+                        case VTE_SEQ_ESCAPE: m_encoder.put(s, 0x1b); break; // ESC
+                        case VTE_SEQ_CSI:    m_encoder.put(s, 0x9b); break; // CSI
+                        case VTE_SEQ_DCS:    m_encoder.put(s, 0x90); break; // DCS
+                        case VTE_SEQ_OSC:    m_encoder.put(s, 0x9d); break; // OSC
+                        case VTE_SEQ_APC:    m_encoder.put(s, 0x9f); break; // APC
+                        case VTE_SEQ_PM:     m_encoder.put(s, 0x9e); break; // PM
+                        case VTE_SEQ_SOS:    m_encoder.put(s, 0x98); break; // SOS
+                        default: return;
+                        }
+                } else {
+                        s.push_back(0x1B); // ESC
+                        switch (m_seq.type) {
+                        case VTE_SEQ_ESCAPE:                    break; // nothing more
+                        case VTE_SEQ_CSI:    s.push_back(0x5b); break; // [
+                        case VTE_SEQ_DCS:    s.push_back(0x50); break; // P
+                        case VTE_SEQ_OSC:    s.push_back(0x5d); break; // ]
+                        case VTE_SEQ_APC:    s.push_back(0x5f); break; // _
+                        case VTE_SEQ_PM:     s.push_back(0x5e); break; // ^
+                        case VTE_SEQ_SOS:    s.push_back(0x58); break; // X
+                        default: return;
+                        }
+                }
+        }
+
+        void append_params(string_type& s) const noexcept
+        {
+                /* Parameters */
+                switch (m_seq.type) {
+                case VTE_SEQ_CSI:
+                case VTE_SEQ_DCS: {
+
+                        if (m_param_intro != 0)
+                                s.push_back(m_param_intro);
+                        auto n_args = m_seq.n_args;
+                        for (unsigned int n = 0; n < n_args; n++) {
+                                auto arg = vte_seq_arg_value(m_seq.args[n]);
+                                if (n > 0) {
+                                        s.push_back(";:"[vte_seq_arg_nonfinal(m_seq.args[n])]);
+                                }
+                                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:
+                        break;
+                }
+        }
+
+        void append_intermediates_and_final(string_type& s) const noexcept
+        {
+                /* Intermediates and Final */
+                switch (m_seq.type) {
+                case VTE_SEQ_ESCAPE:
+                case VTE_SEQ_CSI:
+                case VTE_SEQ_DCS:
+                        for (unsigned char n = 0; n < m_n_intermediates; n++)
+                                s.push_back(m_intermediates[n]);
+
+                        if (m_seq.terminator != 0)
+                                s.push_back(m_seq.terminator);
+                        break;
+                default:
+                        break;
+                }
+        }
+
+        void append_arg_string(string_type& s,
+                               bool c1 = false,
+                               ssize_t max_arg_str_len = -1,
+                               ST st = ST::DEFAULT) const noexcept
+        {
+                /* String and ST */
+                switch (m_seq.type) {
+                case VTE_SEQ_DCS:
+                case VTE_SEQ_OSC:
+
+                        if (max_arg_str_len < 0)
+                                s.append(m_arg_str, 0, max_arg_str_len);
+                        else
+                                s.append(m_arg_str);
+
+                        switch (st) {
+                        case ST::NONE:
+                                // omit ST
+                                break;
+                        case ST::DEFAULT:
+                                if (c1) {
+                                        // s.push_back(0xc2); // fixmechpe
+                                        m_encoder.put(s, 0x9c); // ST
+                                } else {
+                                        s.push_back(0x1b); // ESC
+                                        s.push_back(0x5c); // BACKSLASH
+                                }
+                                break;
+                        case ST::C0:
+                                s.push_back(0x1b); // ESC
+                                s.push_back(0x5c); // BACKSLASH
+                                break;
+                        case ST::C1:
+                                m_encoder.put(s, 0x9c); // ST
+                                break;
+                        case ST::BEL:
+                                s.push_back(0x7); // BEL
+                                break;
+                        default:
+                                break;
+                        }
+                }
+        }
+
+public:
+        void to_string(string_type& s,
+                       bool c1 = false,
+                       ssize_t max_arg_str_len = -1,
+                       ST st = ST::DEFAULT) const noexcept
+        {
+                append_introducer(s, c1);
+                append_params(s);
+                append_intermediates_and_final(s);
+                append_arg_string(s, c1, max_arg_str_len, st);
+        }
+
+        void assert_equal(struct vte_seq* seq);
+        void assert_equal_full(struct vte_seq* seq);
+
+        void print(bool c1 = false);
+};
+
+using u8SequenceBuilder = SequenceBuilder<std::string, UTF8Encoder>;
+using u32SequenceBuilder = SequenceBuilder<std::u32string>;
+
+class ReplyBuilder : public u8SequenceBuilder {
+public:
+        ReplyBuilder(unsigned int reply,
+                     std::initializer_list<int> params)
+        {
+                switch (reply) {
+#define _VTE_REPLY_PARAMS(params) append_params(params);
+#define _VTE_REPLY_STRING(str) set_string(str);
+#define _VTE_REPLY(cmd,type,final,pintro,intermediate,code) \
+                case VTE_REPLY_##cmd: \
+                        set_type(VTE_SEQ_##type); \
+                        set_final(final); \
+                        set_param_intro(VTE_SEQ_INTERMEDIATE_##pintro); \
+                        if (VTE_SEQ_INTERMEDIATE_##intermediate != VTE_SEQ_INTERMEDIATE_NONE) \
+                                append_intermediate(VTE_SEQ_INTERMEDIATE_##intermediate); \
+                        code \
+                        break;
+#include "parser-reply.hh"
+#undef _VTE_REPLY
+#undef _VTE_REPLY_PARAMS
+#undef _VTE_REPLY_STRING
+                default:
+                        assert(false);
+                        break;
+                }
+                append_params(params);
+        }
+
+}; // class ReplyBuilder
+
 class StringTokeniser {
 public:
         using string_type = std::string;
diff --git a/src/parser-reply.hh b/src/parser-reply.hh
new file mode 100644
index 0000000..b5d58b8
--- /dev/null
+++ b/src/parser-reply.hh
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2018 Christian Persch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+_VTE_REPLY(NONE, NONE, 0, NONE, NONE,) /* placeholder */
+
+_VTE_REPLY(APC,         APC, 0,   NONE, NONE,  ) /* application program command */
+_VTE_REPLY(CPR,         CSI, 'R', NONE, NONE,  ) /* cursor position report */
+_VTE_REPLY(DECAUPSS,    DCS, 'u', NONE, BANG,  ) /* assign user preferred supplemental set */
+_VTE_REPLY(DECDA1R,     CSI, 'c', WHAT, NONE,  ) /* DA1 report */
+_VTE_REPLY(DECDA2R,     CSI, 'c', GT,   NONE,  ) /* DA2 report */
+_VTE_REPLY(DECCIR,      DCS, 'u', NONE, CASH,  _VTE_REPLY_PARAMS({1})) /* cursor information report */
+_VTE_REPLY(DECCTR,      DCS, 's', NONE, CASH,  _VTE_REPLY_PARAMS({2})) /* color table report */
+_VTE_REPLY(DECCKSR,     DCS, '~', NONE, BANG,  ) /* memory checksum report */
+_VTE_REPLY(DECEKBD,     APC, 0,   NONE, NONE,  ) /* extended keyboard report */
+_VTE_REPLY(DECDSR,      CSI, 'n', WHAT, NONE,  ) /* device status report */
+_VTE_REPLY(DECMSR,      CSI, '{', NONE, MULT,  ) /* macro space report */
+_VTE_REPLY(DECPKMFR,    CSI, 'y', NONE, PLUS,  ) /* program key free memory report */
+_VTE_REPLY(DECREPTPARM, CSI, 'x', NONE, NONE,  ) /* report terminal parameters */
+_VTE_REPLY(DECRPAK,     DCS, '~', NONE, DQUOTE,) /* report all modifiers/alphanumeric key */
+_VTE_REPLY(DECRPDE,     CSI, 'w', NONE, DQUOTE,) /* report displayed extent */
+_VTE_REPLY(DECRPFK,     DCS, '}', NONE, DQUOTE,) /* report function key */
+_VTE_REPLY(DECRPKT,     CSI, 'v', NONE, COMMA, ) /* report key type */
+_VTE_REPLY(DECRPM_ECMA, CSI, 'y', NONE, CASH,  ) /* report ECMA mode */
+_VTE_REPLY(DECRPM_DEC,  CSI, 'y', WHAT, CASH,  ) /* report private mode */
+_VTE_REPLY(DECRPSS,     DCS, 'r', NONE, CASH,  ) /* report state or setting */
+_VTE_REPLY(DECRPTUI,    DCS, '|', NONE, BANG,  _VTE_REPLY_STRING("7E565445") /* "~VTE" */) /* report 
terminal unit ID */
+_VTE_REPLY(DECTABSR,    DCS, '@', NONE, CASH,  ) /* tabulation stop report */
+_VTE_REPLY(DECTSR,      DCS, 's', NONE, CASH,  _VTE_REPLY_PARAMS({1})) /* terminal state report */
+_VTE_REPLY(DECXCPR,     CSI, 'R', NONE, NONE,  ) /* extended cursor position report */
+_VTE_REPLY(DSR,         CSI, 'n', NONE, NONE,  ) /* device status report */
+_VTE_REPLY(OSC,         OSC, 0,   NONE, NONE,  ) /* operating system command */
+_VTE_REPLY(PM,          PM,  0,   NONE, NONE,  ) /* privacy message */
+_VTE_REPLY(SOS,         SOS, 0,   NONE, NONE,  ) /* start of string */
+_VTE_REPLY(URXVT_MOUSE_EXT_REPORT,                    CSI, 'M', NONE, NONE,) /* URXVT mouse mode report */
+_VTE_REPLY(XTERM_BRACKET,                             CSI, '~', NONE, NONE,) /* XTERM bracketed paste */
+_VTE_REPLY(XTERM_FOCUS_IN,                            CSI, 'I', NONE, NONE,) /* XTERM focus in report */
+_VTE_REPLY(XTERM_FOCUS_OUT,                           CSI, 'O', NONE, NONE,) /* XTERM focus out report */
+_VTE_REPLY(XTERM_MOUSE_EXT_SGR_REPORT_BUTTON_PRESS,   CSI, 'M', LT,   NONE,) /* XTERM SGR mouse mode button 
press report */
+_VTE_REPLY(XTERM_MOUSE_EXT_SGR_REPORT_BUTTON_RELEASE, CSI, 'm', LT,   NONE,) /* XTERM SGR mouse mode button 
release report */
+_VTE_REPLY(XTERM_WM,                                  CSI, 't', NONE, NONE,) /* XTERM WM report */
diff --git a/src/parser-test.cc b/src/parser-test.cc
index 293995f..b0890b2 100644
--- a/src/parser-test.cc
+++ b/src/parser-test.cc
@@ -48,6 +48,9 @@ seq_to_str(unsigned int type)
         case VTE_SEQ_CSI: return "CSI";
         case VTE_SEQ_DCS: return "DCS";
         case VTE_SEQ_OSC: return "OSC";
+        case VTE_SEQ_APC: return "APC";
+        case VTE_SEQ_PM: return "PM";
+        case VTE_SEQ_SOS: return "SOS";
         default:
                 g_assert_not_reached();
         }
@@ -1422,6 +1425,16 @@ test_seq_glue_string_tokeniser(void)
         g_assert_true(pit4 == tokeniser4.cend());
 }
 
+static void
+test_seq_glue_sequence_builder(void)
+{
+}
+
+static void
+test_seq_glue_reply_builder(void)
+{
+}
+
 int
 main(int argc,
      char* argv[])
@@ -1436,6 +1449,8 @@ main(int argc,
         g_test_add_func("/vte/parser/sequences/glue/arg", test_seq_glue_arg);
         g_test_add_func("/vte/parser/sequences/glue/string", test_seq_glue_string);
         g_test_add_func("/vte/parser/sequences/glue/string-tokeniser", test_seq_glue_string_tokeniser);
+        g_test_add_func("/vte/parser/sequences/glue/sequence-builder", test_seq_glue_sequence_builder);
+        g_test_add_func("/vte/parser/sequences/glue/reply-builder", test_seq_glue_reply_builder);
         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/charset/94", test_seq_esc_charset_94);
diff --git a/src/parser.hh b/src/parser.hh
index 751ee11..f6a11ee 100644
--- a/src/parser.hh
+++ b/src/parser.hh
@@ -81,10 +81,44 @@ enum {
         VTE_SEQ_DCS,         /* device control string */
         VTE_SEQ_OSC,         /* operating system control */
 
+        VTE_SEQ_APC,         /* application program command */
+        VTE_SEQ_PM,          /* privacy message */
+        VTE_SEQ_SOS,         /* start of string */
+
         VTE_SEQ_N,
 };
 
 enum {
+        VTE_SEQ_INTERMEDIATE_NONE   = 0,
+
+        VTE_SEQ_INTERMEDIATE_SPACE  = ' ',  /* 02/00 */
+        VTE_SEQ_INTERMEDIATE_BANG   = '!',  /* 02/01 */
+        VTE_SEQ_INTERMEDIATE_DQUOTE = '"',  /* 02/02 */
+        VTE_SEQ_INTERMEDIATE_HASH   = '#',  /* 02/03 */
+        VTE_SEQ_INTERMEDIATE_CASH   = '$',  /* 02/04 */
+        VTE_SEQ_INTERMEDIATE_PERCENT= '%',  /* 02/05 */
+        VTE_SEQ_INTERMEDIATE_AND    = '&',  /* 02/06 */
+        VTE_SEQ_INTERMEDIATE_SQUOTE = '\'', /* 02/07 */
+        VTE_SEQ_INTERMEDIATE_POPEN  = '(',  /* 02/08 */
+        VTE_SEQ_INTERMEDIATE_PCLOSE = ')',  /* 02/09 */
+        VTE_SEQ_INTERMEDIATE_MULT   = '*',  /* 02/10 */
+        VTE_SEQ_INTERMEDIATE_PLUS   = '+',  /* 02/11 */
+        VTE_SEQ_INTERMEDIATE_COMMA  = ',',  /* 02/12 */
+        VTE_SEQ_INTERMEDIATE_MINUS  = '-',  /* 02/13 */
+        VTE_SEQ_INTERMEDIATE_DOT    = '.',  /* 02/14 */
+        VTE_SEQ_INTERMEDIATE_SLASH  = '/',  /* 02/15 */
+
+        /* 16-25 is reserved for numbers; unused */
+
+        /* COLON is reserved        = ':'   * 03/10 */
+        /* SEMICOLON is reserved    = ';'   * 03/11 */
+        VTE_SEQ_INTERMEDIATE_LT     = '<', /* 03/12 */
+        VTE_SEQ_INTERMEDIATE_EQUAL  = '=', /* 03/13 */
+        VTE_SEQ_INTERMEDIATE_GT     = '>', /* 03/14 */
+        VTE_SEQ_INTERMEDIATE_WHAT   = '?'  /* 03/15 */
+};
+
+enum {
         /* these must be kept compatible to (1U << (ch - 0x20)) */
 
         VTE_SEQ_FLAG_SPACE              = (1U <<  0),        /* char:   */
@@ -123,6 +157,14 @@ enum {
 };
 
 enum {
+#define _VTE_REPLY(cmd,type,final,pintro,intermediate,code) VTE_REPLY_##cmd,
+#include "parser-reply.hh"
+#undef _VTE_REPLY
+
+        VTE_REPLY_N
+};
+
+enum {
 #define _VTE_CHARSET_PASTE(name) VTE_CHARSET_##name,
 #define _VTE_CHARSET(name) _VTE_CHARSET_PASTE(name)
 #define _VTE_CHARSET_ALIAS_PASTE(name1,name2) VTE_CHARSET_##name1 = VTE_CHARSET_##name2,
diff --git a/src/vte.cc b/src/vte.cc
index e312ae3..fdf7a23 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -4272,6 +4272,70 @@ VteTerminalPrivate::feed_child_using_modes(char const* data,
                send_child(data, length, !m_modes_ecma.SRM());
 }
 
+void
+VteTerminalPrivate::send(vte::parser::u8SequenceBuilder const& builder,
+                         bool c1,
+                         vte::parser::u8SequenceBuilder::ST st) noexcept
+{
+        std::string str;
+        builder.to_string(str, c1, -1, st);
+        feed_child(str.data(), str.size());
+}
+
+void
+VteTerminalPrivate::send(vte::parser::Sequence const& seq,
+                         vte::parser::u8SequenceBuilder const& builder) noexcept
+{
+        // FIXMEchpe take c1 & ST from @seq
+        send(builder, false);
+}
+
+void
+VteTerminalPrivate::send(unsigned int type,
+                         std::initializer_list<int> params) noexcept
+{
+        // FIXMEchpe take c1 & ST from @seq
+        send(vte::parser::ReplyBuilder{type, params}, false);
+}
+
+void
+VteTerminalPrivate::reply(vte::parser::Sequence const& seq,
+                          unsigned int type,
+                          std::initializer_list<int> params) noexcept
+{
+        send(seq, vte::parser::ReplyBuilder{type, params});
+}
+
+void
+VteTerminalPrivate::reply(vte::parser::Sequence const& seq,
+                          unsigned int type,
+                          char const* format,
+                          ...) noexcept
+{
+        switch (type) {
+        case VTE_SEQ_OSC:
+        case VTE_SEQ_APC:
+        case VTE_SEQ_PM:
+        case VTE_SEQ_SOS:
+                break;
+        default:
+                assert(false);
+                return;
+        }
+
+        char buf[128];
+        va_list vargs;
+        va_start(vargs, format);
+        auto len = g_vsnprintf(buf, sizeof(buf), format, vargs);
+        va_end(vargs);
+        g_assert_cmpint(len, <, sizeof(buf));
+
+        vte::parser::u8SequenceBuilder builder{type};
+        builder.set_string(std::string{buf});
+
+        send(seq, builder);
+}
+
 /* Send text from the input method to the child. */
 static void
 vte_terminal_im_commit_cb(GtkIMContext *im_context,
@@ -5250,6 +5314,7 @@ VteTerminalPrivate::widget_paste_received(char const* text)
         }
 
         bool const bracketed_paste = m_modes_private.XTERM_READLINE_BRACKETED_PASTE();
+        // FIXMEchpe can we not hardcode C0 controls here?
         if (bracketed_paste)
                 feed_child("\e[200~", -1);
         // FIXMEchpe add a way to avoid the extra string copy done here
@@ -5324,17 +5389,19 @@ VteTerminalPrivate::feed_mouse_event(vte::grid::coords const& rowcol /* confined
        /* Check the extensions in decreasing order of preference. Encoding the release event above assumes 
that 1006 comes first. */
        if (m_modes_private.XTERM_MOUSE_EXT_SGR()) {
                /* xterm's extended mode (1006) */
-               len = g_snprintf(buf, sizeof(buf), _VTE_CAP_CSI "<%d;%ld;%ld%c", cb, cx, cy, is_release ? 'm' 
: 'M');
+                send(is_release ? VTE_REPLY_XTERM_MOUSE_EXT_SGR_REPORT_BUTTON_RELEASE
+                                : VTE_REPLY_XTERM_MOUSE_EXT_SGR_REPORT_BUTTON_PRESS,
+                     {cb, (int)cx, (int)cy});
        } else if (m_modes_private.URXVT_MOUSE_EXT()) {
                /* urxvt's extended mode (1015) */
-               len = g_snprintf(buf, sizeof(buf), _VTE_CAP_CSI "%d;%ld;%ldM", 32 + cb, cx, cy);
+                send(VTE_REPLY_URXVT_MOUSE_EXT_REPORT, {32 + cb, (int)cx, (int)cy});
        } else if (cx <= 231 && cy <= 231) {
                /* legacy mode */
                len = g_snprintf(buf, sizeof(buf), _VTE_CAP_CSI "M%c%c%c", 32 + cb, 32 + (guchar)cx, 32 + 
(guchar)cy);
-       }
 
-       /* Send event direct to the child, this is binary not text data */
-       feed_child_binary((guint8*) buf, len);
+                /* Send event direct to the child, this is binary not text data */
+                feed_child_binary((guint8*) buf, len);
+       }
 
         return true;
 }
@@ -5342,11 +5409,7 @@ VteTerminalPrivate::feed_mouse_event(vte::grid::coords const& rowcol /* confined
 void
 VteTerminalPrivate::feed_focus_event(bool in)
 {
-        char buf[8];
-        gsize len;
-
-        len = g_snprintf(buf, sizeof(buf), _VTE_CAP_CSI "%c", in ? 'I' : 'O');
-        feed_child_binary((guint8 *)buf, len);
+        send(in ? VTE_REPLY_XTERM_FOCUS_IN : VTE_REPLY_XTERM_FOCUS_OUT, {});
 }
 
 void
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index e6b1a1e..b4c0123 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -1223,6 +1223,21 @@ public:
         void select_empty(vte::grid::column_t col,
                           vte::grid::row_t row);
 
+        void send(vte::parser::u8SequenceBuilder const& builder,
+                  bool c1 = true,
+                  vte::parser::u8SequenceBuilder::ST st = vte::parser::u8SequenceBuilder::ST::DEFAULT) 
noexcept;
+        void send(vte::parser::Sequence const& seq,
+                  vte::parser::u8SequenceBuilder const& builder) noexcept;
+        void send(unsigned int type,
+                  std::initializer_list<int> params) noexcept;
+        void reply(vte::parser::Sequence const& seq,
+                   unsigned int type,
+                   std::initializer_list<int> params) noexcept;
+        void reply(vte::parser::Sequence const& seq,
+                   unsigned int type,
+                   char const* format,
+                   ...) noexcept G_GNUC_PRINTF(4, 5);
+
         /* OSC handlers */
         void set_color(vte::parser::Sequence const& seq,
                        vte::parser::StringTokeniser::const_iterator& token,
diff --git a/src/vteseq.cc b/src/vteseq.cc
index 46eb62b..69b444a 100644
--- a/src/vteseq.cc
+++ b/src/vteseq.cc
@@ -1358,14 +1358,11 @@ VteTerminalPrivate::set_color(vte::parser::Sequence const& seq,
                 auto const str = *token;
 
                 if (str == "?"s) {
-                        gchar buf[128];
                         auto c = get_color(value);
                         g_assert_nonnull(c);
-                        g_snprintf (buf, sizeof (buf),
-                                    _VTE_CAP_OSC "4;%u;rgb:%04x/%04x/%04x%s",
-                                    value, c->red, c->green, c->blue,
-                                    seq.terminator() == 0x7 ? BEL_C0 : ST_C0);
-                        feed_child(buf, -1);
+
+                        reply(seq, VTE_SEQ_OSC, "4;%d;rgb:%04x/%04x/%04x",
+                              value, c->red, c->green, c->blue);
                 } else {
                         vte::color::rgb color;
                         if (color.parse(str.data())) {
@@ -1396,17 +1393,13 @@ VteTerminalPrivate::set_special_color(vte::parser::Sequence const& seq,
 
         auto const str = *token;
         if (str == "?"s) {
-                gchar buf[128];
                 auto c = get_color(index);
                 if (c == nullptr && index_fallback != -1)
                         c = get_color(index_fallback);
                 g_assert_nonnull(c);
-                auto len = g_snprintf (buf, sizeof (buf),
-                                       _VTE_CAP_OSC "%d;rgb:%04x/%04x/%04x%s",
-                                       osc,
-                                       c->red, c->green, c->blue,
-                                       ST_C0);//seq.terminator() == 7 ? BEL_C0 : ST_C0);
-                feed_child(buf, len);
+
+                reply(seq, VTE_SEQ_OSC, "%d;rgb:%04x/%04x/%04x",
+                      osc, c->red, c->green, c->blue);
         } else {
                 vte::color::rgb color;
                 if (color.parse(str.data())) {
@@ -2087,8 +2080,8 @@ VteTerminalPrivate::DA1(vte::parser::Sequence const& seq)
          * enabled features.
          *
          * The terminal's answer is:
-         *   ^[ ? 64 ; ARGS c
-         * The first argument, 64, is fixed and denotes a VT420, the last
+         *   ^[ ? 65 ; ARGS c
+         * The first argument, 65, is fixed and denotes a VT520, 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
@@ -2107,7 +2100,7 @@ VteTerminalPrivate::DA1(vte::parser::Sequence const& seq)
          *       Support for ReGIS graphics is available. The ReGIS routines
          *       provide the "remote graphics instruction set" and allow basic
          *       vector-rendering.
-         *    4: sixel
+         *    4: Sixel
          *       Support of Sixel graphics is available. This provides access
          *       to the sixel bitmap routines.
          *    6: selective erase
@@ -2120,7 +2113,7 @@ VteTerminalPrivate::DA1(vte::parser::Sequence const& seq)
          *       TODO: ?
          *    9: national-replacement character sets (NRCS)
          *       National-replacement character-sets are available.
-         *   12: Yugoslavian (SCS)
+         *   12: Serbo-Croatian (SCS)
          *       TODO: ?
          *   15: technical character set
          *       The DEC technical-character-set is available.
@@ -2128,13 +2121,13 @@ VteTerminalPrivate::DA1(vte::parser::Sequence const& seq)
          *       TODO: ?
          *   21: horizontal scrolling
          *       TODO: ?
-         *   22: ANSII color
+         *   22: ANSI color
          *       TODO: ?
          *   23: Greek
          *       TODO: ?
          *   24: Turkish
          *       TODO: ?
-         *   29: ANSI text locator
+         *   29: DECterm text locator
          *       TODO: ?
          *   42: ISO Latin-2 character set
          *       TODO: ?
@@ -2149,16 +2142,13 @@ VteTerminalPrivate::DA1(vte::parser::Sequence const& seq)
          *   args[0]: 0
          *
          * References: ECMA-48 § 8.3.24
+         *             VT525
          */
-#if 0
-        SEQ_WRITE(screen, C0_CSI, C1_CSI, "?64;1;6;9;15c");
-#endif
 
         if (seq.collect1(0, 0) != 0)
                 return;
 
-        /* Claim to be a VT220 with only national character set support. */
-        feed_child("\e[?62;c", -1);
+        reply(seq, VTE_REPLY_DECDA1R, {62});
 }
 
 void
@@ -2172,7 +2162,7 @@ VteTerminalPrivate::DA2(vte::parser::Sequence const& seq)
          * terminal features.
          *
          * The terminal's response is:
-         *   ^[ > 61 ; FIRMWARE ; KEYBOARD c
+         *   ^[ > 65 ; 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
@@ -2183,29 +2173,13 @@ VteTerminalPrivate::DA2(vte::parser::Sequence const& seq)
          *
          * References: VT525
          */
-#if 0
-        return SEQ_WRITE(screen, C0_CSI, C1_CSI,
-                         ">65;" __stringify(LINUX_VERSION_CODE) ";1c");
-#endif
 
+        /* Param != 0 means this is a reply, not a request */
         if (seq.collect1(0, 0) != 0)
                 return;
 
-       char **version;
-       char buf[128];
-       long ver = 0, i;
-       /* Claim to be a VT220, more or less.  The '>' in the response appears
-        * to be undocumented. */
-       version = g_strsplit(VERSION, ".", 0);
-       if (version != NULL) {
-               for (i = 0; version[i] != NULL; i++) {
-                       ver = ver * 100;
-                       ver += atol(version[i]);
-               }
-               g_strfreev(version);
-       }
-       g_snprintf(buf, sizeof (buf), _VTE_CAP_ESC "[>65;%ld;0c", ver);
-       feed_child(buf, -1);
+        int const version = (VTE_MAJOR_VERSION * 100 + VTE_MINOR_VERSION) * 100 + VTE_MICRO_VERSION;
+        reply(seq, VTE_REPLY_DECDA2R, {65, version, 1});
 }
 
 void
@@ -2219,12 +2193,14 @@ VteTerminalPrivate::DA3(vte::parser::Sequence const& seq)
          *   ^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 always reply with '~VTE' encoded in hex.
          */
 
-        /* we do not support tertiary DAs */
-
         if (seq.collect1(0, 0) != 0)
                 return;
+
+        reply(seq, VTE_REPLY_DECRPTUI, {});
 }
 
 void
@@ -2805,21 +2781,31 @@ VteTerminalPrivate::DECREQTPARM(vte::parser::Sequence const& seq)
          * Defaults:
          *   args[0]: 0
          *
-         * References: VT525
+         * References: VT100
          */
-#if 0
-        if (seq->n_args < 1 || seq->args[0] == 0) {
+
+        switch (seq.collect1(0)) {
+        case -1:
+        case 0:
+                #if 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) {
+                #endif
+                reply(seq, VTE_REPLY_DECREPTPARM,
+                      {2, 1, 1, 120, 120, 1, 0});
+                break;
+        case 1:
+                #if 0
                 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
+                reply(seq, VTE_REPLY_DECREPTPARM,
+                      {3, 1, 1, 120, 120, 1, 0});
+                break;
+        case 2:
+        case 3:
+                /* This is a report, not a request */
+        default:
+                break;
         }
-#endif
-
-       feed_child("\e[?x", -1);
 }
 
 void
@@ -3693,9 +3679,7 @@ VteTerminalPrivate::DSR_ECMA(vte::parser::Sequence const& seq)
          * References: ECMA-48 § 8.3.35
          */
 
-        auto param = seq.collect1(0);
-
-        switch (param) {
+        switch (seq.collect1(0)) {
         case -1:
         case 0:
         case 1:
@@ -3704,14 +3688,23 @@ VteTerminalPrivate::DSR_ECMA(vte::parser::Sequence const& seq)
         case 4:
                 /* This is a status report */
                 break;
+
         case 5:
-                /* Requesting a DSR */
-                feed_child(_VTE_CAP_CSI "0n", -1);
+                /* Request operating status report.
+                 * Reply: DSR
+                 *   @arg[0]: status
+                 *     0 = ok
+                 *     3 = malfunction
+                 */
+                reply(seq, VTE_REPLY_DSR, {0});
                 break;
-        case 6:
-                /* Requesting a CPR */
 
-                /* Send the cursor position. */
+        case 6:
+                /* Request extended cursor position report
+                 * Reply: CPR
+                 *   @arg[0]: line
+                 *   @arg[1]: column
+                 */
                 vte::grid::row_t rowval, origin, rowmax;
                 if (m_modes_private.DEC_ORIGIN() &&
                     m_scrolling_restricted) {
@@ -3724,13 +3717,11 @@ VteTerminalPrivate::DSR_ECMA(vte::parser::Sequence const& seq)
                 // FIXMEchpe this looks wrong. shouldn't this first clamp to origin,rowmax and *then* 
subtract origin?
                 rowval = m_screen->cursor.row - m_screen->insert_delta - origin;
                 rowval = CLAMP(rowval, 0, rowmax);
-                char buf[128];
-                g_snprintf(buf, sizeof(buf),
-                           _VTE_CAP_CSI "%ld;%ldR",
-                           rowval + 1,
-                           CLAMP(m_screen->cursor.col + 1, 1, m_column_count));
-                feed_child(buf, -1);
+
+                reply(seq, VTE_REPLY_CPR,
+                      {int(rowval + 1), int(CLAMP(m_screen->cursor.col + 1, 1, m_column_count))});
                 break;
+
         default:
                 break;
         }
@@ -3748,13 +3739,19 @@ VteTerminalPrivate::DSR_DEC(vte::parser::Sequence const& seq)
          *   arg[0]: 0
          *
          * References: VT525 5–173
+         *             VT330
+         *             XTERM
          */
 
-        auto param = seq.collect1(0);
-
-        switch (param) {
+        switch (seq.collect1(0)) {
         case 6:
-                /* Send the cursor position. */
+                /* Request extended cursor position report
+                 * Reply: DECXCPR
+                 *   @arg[0]: line
+                 *   @arg[1]: column
+                 *   @arg[2]: page
+                 *     Always report page 1 here (per XTERM source code).
+                 */
                 vte::grid::row_t rowval, origin, rowmax;
                 if (m_modes_private.DEC_ORIGIN() &&
                     m_scrolling_restricted) {
@@ -3767,28 +3764,127 @@ VteTerminalPrivate::DSR_DEC(vte::parser::Sequence const& seq)
                 // FIXMEchpe this looks wrong. shouldn't this first clamp to origin,rowmax and *then* 
subtract origin?
                 rowval = m_screen->cursor.row - m_screen->insert_delta - origin;
                 rowval = CLAMP(rowval, 0, rowmax);
-                char buf[128];
-                g_snprintf(buf, sizeof(buf),
-                           _VTE_CAP_CSI "?%ld;%ldR",
-                           rowval + 1,
-                           CLAMP(m_screen->cursor.col + 1, 1, m_column_count));
-                feed_child(buf, -1);
+
+                reply(seq, VTE_REPLY_DECXCPR,
+                      {int(rowval + 1), int(CLAMP(m_screen->cursor.col + 1, 1, m_column_count)), 1});
                 break;
+
         case 15:
-                /* Send printer status -- 10 = ready,
-                 * 11 = not ready.  We don't print. */
-                feed_child(_VTE_CAP_CSI "?11n", -1);
+                /* Request printer port report
+                 * Reply: DECDSR
+                 *   @arg[0]: status
+                 *     10 = printer ready
+                 *     11 = printer not ready
+                 *     13 = no printer
+                 *     18 = printer busy
+                 *     19 = printer assigned to another session
+                 */
+                reply(seq, VTE_REPLY_DECDSR, {13});
                 break;
+
         case 25:
-                /* Send UDK status -- 20 = locked,
-                 * 21 = not locked.  I don't even know what
-                 * that means, but punt anyway. */
-                feed_child(_VTE_CAP_CSI "?20n", -1);
+                /* Request user-defined keys report
+                 * Reply: DECDSR
+                 *   @arg[0]: locked status
+                 *      20 = UDK unlocked
+                 *      21 = UDK locked
+                 *
+                 * Since we don't do UDK, we report them as locked.
+                 */
+                reply(seq, VTE_REPLY_DECDSR, {21});
                 break;
+
         case 26:
-                /* Send keyboard status.  50 = no locator. */
-                feed_child(_VTE_CAP_CSI "?50n", -1);
+                /* Request keyboard report
+                 * Reply: DECDSR
+                 *   @arg[0]: 27
+                 *   @arg[1]: Keyboard language
+                 *     0 = undetermined
+                 *     1..40
+                 *
+                 *   @arg[2]: Keyboard status
+                 *     0 = ready
+                 *     3 = no keyboard
+                 *     8 = keyboard busy
+                 *
+                 *   @arg[3]: Keyboard type
+                 *     0 = LK201 (XTERM response)
+                 *     4 = LK411
+                 *     5 = PCXAL
+                 */
+                reply(seq, VTE_REPLY_DECDSR, {27, 0, 0, 5});
                 break;
+
+        case 53:
+                /* XTERM alias for 55 */
+                /* [[fallthrough]]; */
+        case 55:
+                /* Request locator status report
+                 * Reply: DECDSR
+                 *   @arg[0]: status
+                 *     50 = locator ready
+                 *     53 = no locator
+                 *
+                 * Since we don't implement the DEC locator mode,
+                 * we reply with 53.
+                 */
+                reply(seq, VTE_REPLY_DECDSR, {53});
+                break;
+
+        case 56:
+                /* Request locator type report
+                 * Reply: DECDSR
+                 *   @arg[0]: 57
+                 *   @arg[1]: status
+                 *     0 = unknown
+                 *     1 = mouse
+                 *
+                 * Since we don't implement the DEC locator mode,
+                 * we reply with 0.
+                 */
+                reply(seq, VTE_REPLY_DECDSR, {57, 0});
+                break;
+
+        case 62:
+                /* Request macro space report
+                 * Reply: DECMSR
+                 *   @arg[0]: floor((number of bytes available) / 16); we report 0
+                 */
+                reply(seq, VTE_REPLY_DECMSR, {0});
+                break;
+
+        case 63:
+                /* Request memory checksum report
+                 * Reply: DECCKSR
+                 *   @arg[0]: PID
+                 *   DATA: hex encoded
+                 *
+                 * Reply with empty DATA.
+                 */
+                reply(seq, VTE_REPLY_DECCKSR, {seq.collect1(1)});
+                break;
+
+        case 75:
+                /* Request data integrity report
+                 * Reply: DECDSR
+                 *   @arg[0]: status
+                 *     70 = no error, no power loss, no communication errors
+                 *     71 = malfunction or communication error
+                 *     73 = no data loss since last power-up
+                 */
+                reply(seq, VTE_REPLY_DECDSR, {70});
+                break;
+
+        case 85:
+                /* Request multi-session status report
+                 * Reply: DECDSR
+                 *   @arg[0]: status
+                 *     ...
+                 *     83 = not configured
+                 */
+                reply(seq, VTE_REPLY_DECDSR, {83});
+                break;
+
         default:
                 break;
         }
@@ -5255,94 +5351,101 @@ VteTerminalPrivate::XTERM_WM(vte::parser::Sequence const& seq)
          * No parameter default values.
          *
          * References: XTERM
+         *             VT525
          */
 
-        int param, arg1, arg2;
-        if (!seq.collect(0, {&param, &arg1, &arg2}))
-                return;
-
-       GdkScreen *gscreen;
+        #if 0
        char buf[128];
-       int width, height;
+        #endif
 
+        int param = seq.collect1(0);
         switch (param) {
         case -1:
         case 0:
                 break;
 
         case VTE_XTERM_WM_RESTORE_WINDOW:
-                _vte_debug_print(VTE_DEBUG_PARSER,
-                                 "Deiconifying window.\n");
+                _vte_debug_print(VTE_DEBUG_EMULATION, "Deiconifying window.\n");
                 emit_deiconify_window();
                 break;
 
         case VTE_XTERM_WM_MINIMIZE_WINDOW:
-                _vte_debug_print(VTE_DEBUG_PARSER,
-                                 "Iconifying window.\n");
+                _vte_debug_print(VTE_DEBUG_EMULATION, "Iconifying window.\n");
                 emit_iconify_window();
                 break;
 
-        case VTE_XTERM_WM_SET_WINDOW_POSITION:
-                if ((arg1 != -1) && (arg2 != -1)) {
-                        _vte_debug_print(VTE_DEBUG_PARSER,
-                                         "Moving window to "
-                                         "%d,%d.\n", arg1, arg2);
-                        emit_move_window(arg1, arg2);
-                }
+        case VTE_XTERM_WM_SET_WINDOW_POSITION: {
+                int pos_x = seq.collect1(1, 0);
+                int pos_y = seq.collect1(2, 0);
+
+                _vte_debug_print(VTE_DEBUG_EMULATION,
+                                 "Moving window to %d,%d.\n", pos_x, pos_y);
+                emit_move_window(pos_x, pos_y);
                 break;
+        }
 
-        case VTE_XTERM_WM_SET_WINDOW_SIZE_PIXELS:
-                if ((arg1 != -1) && (arg2 != -1)) {
-                        _vte_debug_print(VTE_DEBUG_PARSER,
-                                         "Resizing window "
-                                         "(to %dx%d pixels, grid size %ldx%ld).\n",
-                                         arg2, arg1,
-                                         arg2 / m_cell_width,
-                                         arg1 / m_cell_height);
-                        emit_resize_window(arg2 / m_cell_width,
-                                           arg1 / m_cell_height);
+        case VTE_XTERM_WM_SET_WINDOW_SIZE_PIXELS: {
+                int width, height;
+                seq.collect(1, {&height, &width});
+
+                if (width != -1 && height != -1) {
+                        _vte_debug_print(VTE_DEBUG_EMULATION,
+                                         "Resizing window to %dx%d pixels, grid size %dx%d.\n",
+                                         width, height,
+                                         width / int(m_cell_height), height / int(m_cell_width));
+                        emit_resize_window(width / int(m_cell_height), height / int(m_cell_width));
                 }
                 break;
+        }
 
         case VTE_XTERM_WM_RAISE_WINDOW:
-                _vte_debug_print(VTE_DEBUG_PARSER, "Raising window.\n");
+                _vte_debug_print(VTE_DEBUG_EMULATION, "Raising window.\n");
                 emit_raise_window();
                 break;
 
         case VTE_XTERM_WM_LOWER_WINDOW:
-                _vte_debug_print(VTE_DEBUG_PARSER, "Lowering window.\n");
+                _vte_debug_print(VTE_DEBUG_EMULATION, "Lowering window.\n");
                 emit_lower_window();
                 break;
 
         case VTE_XTERM_WM_REFRESH_WINDOW:
-                _vte_debug_print(VTE_DEBUG_PARSER,
-                                 "Refreshing window.\n");
+                _vte_debug_print(VTE_DEBUG_EMULATION, "Refreshing window.\n");
                 invalidate_all();
                 emit_refresh_window();
                 break;
 
-        case VTE_XTERM_WM_SET_WINDOW_SIZE_CELLS:
-                if ((arg1 != -1) && (arg2 != -1)) {
-                        _vte_debug_print(VTE_DEBUG_PARSER,
-                                         "Resizing window "
-                                         "(to %d columns, %d rows).\n",
-                                         arg2, arg1);
-                        emit_resize_window(arg2, arg1);
+        case VTE_XTERM_WM_SET_WINDOW_SIZE_CELLS: {
+                int width, height;
+                seq.collect(1, {&height, &width});
+
+                if (width != -1 && height != -1) {
+                        _vte_debug_print(VTE_DEBUG_EMULATION,
+                                         "Resizing window to %d columns, %d rows.\n",
+                                         width, height);
+                        emit_resize_window(width, height);
                 }
                 break;
+        }
 
         case VTE_XTERM_WM_MAXIMIZE_WINDOW:
-                switch (arg1) {
+                switch (seq.collect1(1)) {
+                case -1: /* default */
                 case 0:
-                        _vte_debug_print(VTE_DEBUG_PARSER,
-                                         "Restoring window.\n");
+                        /* Restore */
+                        _vte_debug_print(VTE_DEBUG_EMULATION, "Restoring window.\n");
                         emit_restore_window();
                         break;
                 case 1:
-                        _vte_debug_print(VTE_DEBUG_PARSER,
-                                         "Maximizing window.\n");
+                        /* Maximise */
+                        _vte_debug_print(VTE_DEBUG_EMULATION, "Maximizing window.\n");
                         emit_maximize_window();
                         break;
+                case 2:
+                        /* Maximise Vertically */
+                        break;
+                case 3:
+                        /* Maximise Horizontally */
+                        break;
                 default:
                         break;
                 }
@@ -5353,96 +5456,91 @@ VteTerminalPrivate::XTERM_WM(vte::parser::Sequence const& seq)
 
         case VTE_XTERM_WM_GET_WINDOW_STATE:
                 /* If we're unmapped, then we're iconified. */
-                g_snprintf(buf, sizeof(buf),
-                           _VTE_CAP_CSI "%dt",
-                           1 + !gtk_widget_get_mapped(m_widget));
-                _vte_debug_print(VTE_DEBUG_PARSER,
-                                 "Reporting window state %s.\n",
-                                 gtk_widget_get_mapped(m_widget) ?
-                                 "non-iconified" : "iconified");
-                feed_child(buf, -1);
+                _vte_debug_print(VTE_DEBUG_EMULATION,
+                                 "Reporting window state %siconified.\n",
+                                 gtk_widget_get_mapped(m_widget) ? "non-" : "");
+
+                reply(seq, VTE_REPLY_XTERM_WM,
+                      {gtk_widget_get_mapped(m_widget) ? 1 : 2});
                 break;
 
-        case VTE_XTERM_WM_GET_WINDOW_POSITION:
+        case VTE_XTERM_WM_GET_WINDOW_POSITION: {
                 /* Send window location, in pixels. */
-                gdk_window_get_origin(gtk_widget_get_window(m_widget),
-                                      &width, &height);
-                g_snprintf(buf, sizeof(buf),
-                           _VTE_CAP_CSI "3;%d;%dt",
-                           width + m_padding.left,
-                           height + m_padding.top);
-                _vte_debug_print(VTE_DEBUG_PARSER,
-                                 "Reporting window location"
-                                 "(%d++,%d++).\n",
-                                 width, height);
-                feed_child(buf, -1);
+                /* FIXME: this is not supported on wayland; just hardwire
+                 * it to a fixed return always.
+                 */
+                int x0, y0;
+                gdk_window_get_origin(gtk_widget_get_window(m_widget), &x0, &y0);
+                _vte_debug_print(VTE_DEBUG_EMULATION,
+                                 "Reporting window location (%d,%d).\n", x0, y0);
+
+                reply(seq, VTE_REPLY_XTERM_WM,
+                      {3, x0 + m_padding.left, y0 + m_padding.top});
                 break;
+        }
 
-        case VTE_XTERM_WM_GET_WINDOW_SIZE_PIXELS:
+        case VTE_XTERM_WM_GET_WINDOW_SIZE_PIXELS: {
                 /* Send window size, in pixels. */
-                g_snprintf(buf, sizeof(buf),
-                           _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_PARSER,
-                                 "Reporting window size "
-                                 "(%dx%d)\n",
-                                 (int)(m_row_count * m_cell_height),
-                                 (int)(m_column_count * m_cell_width));
-
-                feed_child(buf, -1);
+                int width = m_row_count * m_cell_height;
+                int height = m_column_count * m_cell_width;
+                _vte_debug_print(VTE_DEBUG_EMULATION,
+                                 "Reporting window size (%dx%d)\n",
+                                 width, height);
+
+                reply(seq, VTE_REPLY_XTERM_WM, {4, height, width});
                 break;
+        }
 
         case VTE_XTERM_WM_GET_WINDOW_SIZE_CELLS:
                 /* Send widget size, in cells. */
-                _vte_debug_print(VTE_DEBUG_PARSER,
-                                 "Reporting widget size.\n");
-                g_snprintf(buf, sizeof(buf),
-                           _VTE_CAP_CSI "8;%ld;%ldt",
-                           m_row_count,
-                           m_column_count);
-                feed_child(buf, -1);
+                _vte_debug_print(VTE_DEBUG_EMULATION,
+                                 "Reporting widget size %ldx%ld\n",
+                                 m_row_count, m_column_count);
+
+                reply(seq, VTE_REPLY_XTERM_WM,
+                      {8, (int)m_row_count, (int)m_column_count});
                 break;
 
-        case VTE_XTERM_WM_GET_SCREEN_SIZE_CELLS:
-                _vte_debug_print(VTE_DEBUG_PARSER,
-                                 "Reporting screen size.\n");
-                gscreen = gtk_widget_get_screen(m_widget);
-                height = gdk_screen_get_height(gscreen);
-                width = gdk_screen_get_width(gscreen);
-                g_snprintf(buf, sizeof(buf),
-                           _VTE_CAP_CSI "9;%ld;%ldt",
-                           height / m_cell_height,
-                           width / m_cell_width);
-                feed_child(buf, -1);
+        case VTE_XTERM_WM_GET_SCREEN_SIZE_CELLS: {
+                /* FIMXE: this should really report the monitor's workarea,
+                 * or even just a fixed value.
+                 */
+                auto gdkscreen = gtk_widget_get_screen(m_widget);
+                int height = gdk_screen_get_height(gdkscreen);
+                int width = gdk_screen_get_width(gdkscreen);
+                _vte_debug_print(VTE_DEBUG_EMULATION,
+                                 "Reporting screen size as %dx%d cells.\n",
+                                 height / int(m_cell_height), width / int(m_cell_width));
+
+                reply(seq, VTE_REPLY_XTERM_WM,
+                      {9, height / int(m_cell_height), width / int(m_cell_width)});
                 break;
+        }
 
         case VTE_XTERM_WM_GET_ICON_TITLE:
                 /* Report a static icon title, since the real
-                   icon title should NEVER be reported, as it
-                   creates a security vulnerability.  See
-                   http://marc.info/?l=bugtraq&m=104612710031920&w=2
-                   and CVE-2003-0070. */
-                _vte_debug_print(VTE_DEBUG_PARSER,
-                                 "Reporting fake icon title.\n");
-                /* never use m_icon_title here! */
-                g_snprintf (buf, sizeof (buf),
-                            _VTE_CAP_OSC "LTerminal" _VTE_CAP_ST);
-                feed_child(buf, -1);
+                 * icon title should NEVER be reported, as it
+                 * creates a security vulnerability.  See
+                 * http://marc.info/?l=bugtraq&m=104612710031920&w=2
+                 * and CVE-2003-0070.
+                 */
+                _vte_debug_print(VTE_DEBUG_EMULATION,
+                                 "Reporting empty icon title.\n");
+
+                send(seq, vte::parser::u8SequenceBuilder{VTE_SEQ_OSC, "L"s});
                 break;
 
         case VTE_XTERM_WM_GET_WINDOW_TITLE:
                 /* Report a static window title, since the real
-                   window title should NEVER be reported, as it
-                   creates a security vulnerability.  See
-                   http://marc.info/?l=bugtraq&m=104612710031920&w=2
-                   and CVE-2003-0070. */
-                _vte_debug_print(VTE_DEBUG_PARSER,
-                                 "Reporting fake window title.\n");
-                /* never use m_window_title here! */
-                g_snprintf (buf, sizeof (buf),
-                            _VTE_CAP_OSC "lTerminal" _VTE_CAP_ST);
-                feed_child(buf, -1);
+                 * window title should NEVER be reported, as it
+                 * creates a security vulnerability.  See
+                 * http://marc.info/?l=bugtraq&m=104612710031920&w=2
+                 * and CVE-2003-0070.
+                 */
+                _vte_debug_print(VTE_DEBUG_EMULATION,
+                                 "Reporting empty window title.\n");
+
+                send(seq, vte::parser::u8SequenceBuilder{VTE_SEQ_OSC, "l"s});
                 break;
 
         case VTE_XTERM_WM_TITLE_STACK_PUSH:
@@ -5452,13 +5550,16 @@ VteTerminalPrivate::XTERM_WM(vte::parser::Sequence const& seq)
                 break;
 
         default:
-                /* DECSLPP; param is 24, 25, 36, 41, 42, 48, 52, 53, 72, or 144 */
+                /* DECSLPP.
+                 *
+                 * VTxxx variously supported 24, 25, 36, 41, 42, 48, 52, 53, 72, or 144 rows,
+                 * but we support any value >= 24.
+                 */
                 if (param >= 24) {
-                        _vte_debug_print(VTE_DEBUG_PARSER,
+                        _vte_debug_print(VTE_DEBUG_EMULATION,
                                          "Resizing to %d rows.\n",
                                          param);
-                        /* Resize to the specified number of
-                         * rows. */
+                        /* Resize to the specified number of rows. */
                         emit_resize_window(m_column_count, param);
                 }
                 break;


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