patch 8.2.3666: libvterm is outdated

Problem:    Libvterm is outdated.
Solution:   Include patches from revision 769 to revision 789.
diff --git a/src/libvterm/t/02parser.test b/src/libvterm/t/02parser.test
index 0a21b92..2cc51dc 100644
--- a/src/libvterm/t/02parser.test
+++ b/src/libvterm/t/02parser.test
@@ -17,15 +17,15 @@
 PUSH "\x83"
   control 0x83
 
-PUSH "\x9f"
-  control 0x9f
+PUSH "\x99"
+  control 0x99
 
 !C1 7bit
 PUSH "\e\x43"
   control 0x83
 
-PUSH "\e\x5f"
-  control 0x9f
+PUSH "\e\x59"
+  control 0x99
 
 !High bytes
 PUSH "\xa0\xcc\xfe"
@@ -184,6 +184,12 @@
 PUSH "\x{90}Hello\x9c"
   dcs ["Hello"]
 
+!Split write of 7bit ST
+PUSH "\ePABC\e"
+  dcs ["ABC"
+PUSH "\\"
+  dcs ]
+
 !Escape cancels DCS, starts Escape
 PUSH "\ePSomething\e9"
   escape "9"
@@ -198,6 +204,48 @@
   control 10
   dcs "e"]
 
+!APC BEL
+PUSH "\e_Hello\x07"
+  apc ["Hello"]
+
+!APC ST (7bit)
+PUSH "\e_Hello\e\\"
+  apc ["Hello"]
+
+!APC ST (8bit)
+PUSH "\x{9f}Hello\x9c"
+  apc ["Hello"]
+
+!PM BEL
+PUSH "\e^Hello\x07"
+  pm ["Hello"]
+
+!PM ST (7bit)
+PUSH "\e^Hello\e\\"
+  pm ["Hello"]
+
+!PM ST (8bit)
+PUSH "\x{9e}Hello\x9c"
+  pm ["Hello"]
+
+!SOS BEL
+PUSH "\eXHello\x07"
+  sos ["Hello"]
+
+!SOS ST (7bit)
+PUSH "\eXHello\e\\"
+  sos ["Hello"]
+
+!SOS ST (8bit)
+PUSH "\x{98}Hello\x9c"
+  sos ["Hello"]
+
+!SOS can contain any C0 or C1 code
+PUSH "\eXABC\x01DEF\e\\"
+  sos ["ABC\x01DEF"]
+PUSH "\eXABC\x99DEF\e\\"
+  sos ["ABC\x{99}DEF"]
+
 !NUL ignored
 PUSH "\x{00}"
 
diff --git a/src/libvterm/t/17state_mouse.test b/src/libvterm/t/17state_mouse.test
index c39f56b..e5ba29b 100644
--- a/src/libvterm/t/17state_mouse.test
+++ b/src/libvterm/t/17state_mouse.test
@@ -170,3 +170,12 @@
   output "\e[?1006;2\$y"
 PUSH "\e[?1015\$p"
   output "\e[?1015;1\$y"
+
+!Mouse disabled reports nothing
+RESET
+  settermprop 1 true
+  settermprop 2 true
+  settermprop 7 1
+MOUSEMOVE 0,0 0
+MOUSEBTN d 1 0
+MOUSEBTN u 1 0
diff --git a/src/libvterm/t/29state_fallback.test b/src/libvterm/t/29state_fallback.test
index 7995dd1..4ab2e18 100644
--- a/src/libvterm/t/29state_fallback.test
+++ b/src/libvterm/t/29state_fallback.test
@@ -17,3 +17,15 @@
 !Unrecognised DCS
 PUSH "\ePz123\e\\"
   dcs ["z123"]
+
+!Unrecognised APC
+PUSH "\e_z123\e\\"
+  apc ["z123"]
+
+!Unrecognised PM
+PUSH "\e^z123\e\\"
+  pm ["z123"]
+
+!Unrecognised SOS
+PUSH "\eXz123\e\\"
+  sos ["z123"]
diff --git a/src/libvterm/t/40state_selection.test b/src/libvterm/t/40state_selection.test
new file mode 100644
index 0000000..6ed8972
--- /dev/null
+++ b/src/libvterm/t/40state_selection.test
@@ -0,0 +1,55 @@
+INIT
+UTF8 1
+WANTSTATE
+
+!Set clipboard; final chunk len 4
+PUSH "\e]52;c;SGVsbG8s\e\\"
+  selection-set mask=0001 ["Hello,"]
+
+!Set clipboard; final chunk len 3
+PUSH "\e]52;c;SGVsbG8sIHc=\e\\"
+  selection-set mask=0001 ["Hello, w"]
+
+!Set clipboard; final chunk len 2
+PUSH "\e]52;c;SGVsbG8sIHdvcmxkCg==\e\\"
+  selection-set mask=0001 ["Hello, world\n"]
+
+!Set clipboard; split between chunks
+PUSH "\e]52;c;SGVs"
+  selection-set mask=0001 ["Hel"
+PUSH "bG8s\e\\"
+  selection-set mask=0001 "lo,"]
+
+!Set clipboard; split within chunk
+PUSH "\e]52;c;SGVsbG"
+  selection-set mask=0001 ["Hel"
+PUSH "8s\e\\"
+  selection-set mask=0001 "lo,"]
+
+!Query clipboard
+PUSH "\e]52;c;?\e\\"
+  selection-query mask=0001
+
+!Send clipboard; final chunk len 4
+SELECTION 1 ["Hello,"]
+  output "\e]52;c;SGVsbG8s\e\\"
+
+!Send clipboard; final chunk len 3
+SELECTION 1 ["Hello, w"]
+  output "\e]52;c;SGVsbG8sIHc=\e\\"
+
+!Send clipboard; final chunk len 2
+SELECTION 1 ["Hello, world\n"]
+  output "\e]52;c;SGVsbG8sIHdvcmxkCg==\e\\"
+
+!Send clipboard; split between chunks
+SELECTION 1 ["Hel"
+  output "\e]52;c;SGVs"
+SELECTION 1  "lo,"]
+  output "bG8s\e\\"
+
+!Send clipboard; split within chunk
+SELECTION 1 ["Hello"
+  output "\e]52;c;SGVs"
+SELECTION 1 ","]
+  output "bG8s\e\\"
diff --git a/src/libvterm/t/harness.c b/src/libvterm/t/harness.c
index 10afbfd..07babb6 100644
--- a/src/libvterm/t/harness.c
+++ b/src/libvterm/t/harness.c
@@ -13,7 +13,8 @@
 
   while(*inpos) {
     unsigned int ch;
-    sscanf(inpos, "%2x", &ch);
+    if(sscanf(inpos, "%2x", &ch) < 1)
+      break;
     *outpos = ch;
     outpos += 1; inpos += 2;
   }
@@ -98,7 +99,7 @@
 static void printhex(const char *s, size_t len)
 {
   while(len--)
-    printf("%02x", (s++)[0]);
+    printf("%02x", (uint8_t)(s++)[0]);
 }
 
 static int parser_text(const char bytes[], size_t len, void *user UNUSED)
@@ -216,6 +217,57 @@
   return 1;
 }
 
+static int parser_apc(VTermStringFragment frag, void *user UNUSED)
+{
+  printf("apc ");
+
+  if(frag.initial)
+    printf("[");
+
+  printhex(frag.str, frag.len);
+
+  if(frag.final)
+    printf("]");
+
+  printf("\n");
+
+  return 1;
+}
+
+static int parser_pm(VTermStringFragment frag, void *user UNUSED)
+{
+  printf("pm ");
+
+  if(frag.initial)
+    printf("[");
+
+  printhex(frag.str, frag.len);
+
+  if(frag.final)
+    printf("]");
+
+  printf("\n");
+
+  return 1;
+}
+
+static int parser_sos(VTermStringFragment frag, void *user UNUSED)
+{
+  printf("sos ");
+
+  if(frag.initial)
+    printf("[");
+
+  printhex(frag.str, frag.len);
+
+  if(frag.final)
+    printf("]");
+
+  printf("\n");
+
+  return 1;
+}
+
 static VTermParserCallbacks parser_cbs = {
   parser_text, // text
   parser_control, // control
@@ -223,6 +275,9 @@
   parser_csi, // csi
   parser_osc, // osc
   parser_dcs, // dcs
+  parser_apc, // apc
+  parser_pm, // pm
+  parser_sos, // sos
   NULL // resize
 };
 
@@ -230,7 +285,10 @@
   parser_control, // control
   parser_csi, // csi
   parser_osc, // osc
-  parser_dcs // dcs
+  parser_dcs, // dcs
+  parser_apc, // dcs
+  parser_pm, // pm
+  parser_sos // sos
 };
 
 /* These callbacks are shared by State and Screen */
@@ -414,6 +472,31 @@
   state_setlineinfo, // setlineinfo
 };
 
+static int selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user UNUSED)
+{
+  printf("selection-set mask=%04X ", mask);
+  if(frag.initial)
+    printf("[");
+  printhex(frag.str, frag.len);
+  if(frag.final)
+    printf("]");
+  printf("\n");
+
+  return 1;
+}
+
+static int selection_query(VTermSelectionMask mask, void *user UNUSED)
+{
+  printf("selection-query mask=%04X\n", mask);
+
+  return 1;
+}
+
+VTermSelectionCallbacks selection_cbs = {
+  .set   = selection_set,
+  .query = selection_query,
+};
+
 static int want_screen_damage = 0;
 static int want_screen_damage_cells = 0;
 static int screen_damage(VTermRect rect, void *user UNUSED)
@@ -555,6 +638,7 @@
       if(!state) {
         state = vterm_obtain_state(vt);
         vterm_state_set_callbacks(state, &state_cbs, NULL);
+        vterm_state_set_selection_callbacks(state, &selection_cbs, NULL, NULL, 1024);
         vterm_state_set_bold_highbright(state, 1);
         vterm_state_reset(state, 1);
       }
@@ -768,6 +852,32 @@
       vterm_mouse_button(vt, button, (press == 'd' || press == 'D'), mod);
     }
 
+    else if(strstartswith(line, "SELECTION ")) {
+      char *linep = line + 10;
+      unsigned int mask;
+      int len;
+      VTermStringFragment frag = { 0 };
+      sscanf(linep, "%x%n", &mask, &len);
+      linep += len;
+      while(linep[0] == ' ')
+        linep++;
+      if(linep[0] == '[') {
+        frag.initial = TRUE;
+        linep++;
+        while(linep[0] == ' ')
+          linep++;
+      }
+      frag.len = inplace_hex2bytes(linep);
+      frag.str = linep;
+      linep += frag.len * 2;
+      while(linep[0] == ' ')
+        linep++;
+      if(linep[0] == ']') {
+        frag.final = TRUE;
+      }
+      vterm_state_send_selection(state, mask, frag);
+    }
+
     else if(strstartswith(line, "DAMAGEMERGE ")) {
       char *linep = line + 12;
       while(linep[0] == ' ')
diff --git a/src/libvterm/t/run-test.pl b/src/libvterm/t/run-test.pl
index 82abb29..2e359cc 100644
--- a/src/libvterm/t/run-test.pl
+++ b/src/libvterm/t/run-test.pl
@@ -85,6 +85,11 @@
          my $string = eval($2);
          $line = "$1 " . unpack "H*", $string;
       }
+      elsif( $line =~ m/^(SELECTION \d+) +(\[?)(.*?)(\]?)$/ ) {
+         # we're evil
+         my $string = eval($3);
+         $line = "$1 $2 " . unpack( "H*", $string ) . " $4";
+      }
 
       do_onetest if defined $command;
 
@@ -113,15 +118,18 @@
 
          $line = "$cmd $initial" . join( "", map sprintf("%02x", $_), unpack "C*", length $data ? eval($data) : "" ) . "$final";
       }
-      elsif( $line =~ m/^(escape|dcs) (\[?)(.*?)(\]?)$/ ) {
-         $line = "$1 $2" . join( "", map sprintf("%02x", $_), unpack "C*", eval($3) ) . "$4";
+      elsif( $line =~ m/^(escape|dcs|apc|pm|sos) (\[?)(.*?)(\]?)$/ ) {
+         $line = "$1 $2" . join( "", map sprintf("%02x", $_), unpack "C*", length $3 ? eval($3) : "" ) . "$4";
       }
       elsif( $line =~ m/^putglyph (\S+) (.*)$/ ) {
          $line = "putglyph " . join( ",", map sprintf("%x", $_), eval($1) ) . " $2";
       }
-      elsif( $line =~ m/^(?:movecursor|scrollrect|moverect|erase|damage|sb_pushline|sb_popline|settermprop|setmousefunc) / ) {
+      elsif( $line =~ m/^(?:movecursor|scrollrect|moverect|erase|damage|sb_pushline|sb_popline|settermprop|setmousefunc|selection-query) / ) {
          # no conversion
       }
+      elsif( $line =~ m/^(selection-set) (.*?) (\[?)(.*?)(\]?)$/ ) {
+         $line = "$1 $2 $3" . join( "", map sprintf("%02x", $_), unpack "C*", eval($4) ) . "$5";
+      }
       else {
          warn "Unrecognised test expectation '$line'\n";
       }