diff src/libvterm/src/parser.c @ 20488:1d595fada804 v8.2.0798

patch 8.2.0798: libvterm code lags behind the upstream version Commit: https://github.com/vim/vim/commit/be593bf135f6967335b14ba188bd5f8f32175c75 Author: Bram Moolenaar <Bram@vim.org> Date: Tue May 19 21:20:04 2020 +0200 patch 8.2.0798: libvterm code lags behind the upstream version Problem: Libvterm code lags behind the upstream version. Solution: Include revisions 755 - 758.
author Bram Moolenaar <Bram@vim.org>
date Tue, 19 May 2020 21:30:07 +0200
parents 1c75e1974313
children 55a373a243c0
line wrap: on
line diff
--- a/src/libvterm/src/parser.c
+++ b/src/libvterm/src/parser.c
@@ -23,10 +23,10 @@ static void do_csi(VTerm *vt, char comma
 {
 #ifdef DEBUG_PARSER
   printf("Parsed CSI args as:\n", arglen, args);
-  printf(" leader: %s\n", vt->parser.csi_leader);
-  for(int argi = 0; argi < vt->parser.csi_argi; argi++) {
-    printf(" %lu", CSI_ARG(vt->parser.csi_args[argi]));
-    if(!CSI_ARG_HAS_MORE(vt->parser.csi_args[argi]))
+  printf(" leader: %s\n", vt->parser.v.csi.leader);
+  for(int argi = 0; argi < vt->parser.v.csi.argi; argi++) {
+    printf(" %lu", CSI_ARG(vt->parser.v.csi.args[argi]));
+    if(!CSI_ARG_HAS_MORE(vt->parser.v.csi.args[argi]))
       printf("\n");
   printf(" intermed: %s\n", vt->parser.intermed);
   }
@@ -34,9 +34,9 @@ static void do_csi(VTerm *vt, char comma
 
   if(vt->parser.callbacks && vt->parser.callbacks->csi)
     if((*vt->parser.callbacks->csi)(
-          vt->parser.csi_leaderlen ? vt->parser.csi_leader : NULL,
-          vt->parser.csi_args,
-          vt->parser.csi_argi,
+          vt->parser.v.csi.leaderlen ? vt->parser.v.csi.leader : NULL,
+          vt->parser.v.csi.args,
+          vt->parser.v.csi.argi,
           vt->parser.intermedlen ? vt->parser.intermed : NULL,
           command,
           vt->parser.cbdata))
@@ -61,65 +61,36 @@ static void do_escape(VTerm *vt, char co
   DEBUG_LOG1("libvterm: Unhandled escape ESC 0x%02x\n", command);
 }
 
-static void append_strbuffer(VTerm *vt, const char *str, size_t len)
+static void string_fragment(VTerm *vt, const char *str, size_t len, int final)
 {
-  if(len > vt->parser.strbuffer_len - vt->parser.strbuffer_cur) {
-    len = vt->parser.strbuffer_len - vt->parser.strbuffer_cur;
-    DEBUG_LOG1("Truncating strbuffer preserve to %zu bytes\n", len);
+  VTermStringFragment frag;
+
+  frag.str = str;
+  frag.len = len;
+  frag.initial = vt->parser.string_initial;
+  frag.final = final;
+
+  switch(vt->parser.state) {
+    case OSC:
+      if(vt->parser.callbacks && vt->parser.callbacks->osc)
+        (*vt->parser.callbacks->osc)(vt->parser.v.osc.command, frag, vt->parser.cbdata);
+      break;
+
+    case DCS:
+      if(len && vt->parser.callbacks && vt->parser.callbacks->dcs)
+        (*vt->parser.callbacks->dcs)(vt->parser.v.dcs.command, vt->parser.v.dcs.commandlen, frag, vt->parser.cbdata);
+      break;
+
+    case NORMAL:
+    case CSI_LEADER:
+    case CSI_ARGS:
+    case CSI_INTERMED:
+    case OSC_COMMAND:
+    case DCS_COMMAND:
+      break;
   }
 
-  if(len > 0) {
-    strncpy(vt->parser.strbuffer + vt->parser.strbuffer_cur, str, len);
-    vt->parser.strbuffer_cur += len;
-  }
-}
-
-static void start_string(VTerm *vt, VTermParserStringType type)
-{
-  vt->parser.stringtype = type;
-
-  vt->parser.strbuffer_cur = 0;
-}
-
-static void more_string(VTerm *vt, const char *str, size_t len)
-{
-  append_strbuffer(vt, str, len);
-}
-
-static void done_string(VTerm *vt, const char *str, size_t len)
-{
-  if(vt->parser.strbuffer_cur) {
-    if(str)
-      append_strbuffer(vt, str, len);
-
-    str = vt->parser.strbuffer;
-    len = vt->parser.strbuffer_cur;
-  }
-  else if(!str) {
-    DEBUG_LOG("parser.c: TODO: No strbuffer _and_ no final fragment???\n");
-    len = 0;
-  }
-
-  switch(vt->parser.stringtype) {
-  case VTERM_PARSER_OSC:
-    if(vt->parser.callbacks && vt->parser.callbacks->osc)
-      if((*vt->parser.callbacks->osc)(str, len, vt->parser.cbdata))
-        return;
-
-    DEBUG_LOG2("libvterm: Unhandled OSC %.*s\n", (int)len, str);
-    return;
-
-  case VTERM_PARSER_DCS:
-    if(vt->parser.callbacks && vt->parser.callbacks->dcs)
-      if((*vt->parser.callbacks->dcs)(str, len, vt->parser.cbdata))
-        return;
-
-    DEBUG_LOG2("libvterm: Unhandled DCS %.*s\n", (int)len, str);
-    return;
-
-  case VTERM_N_PARSER_TYPES:
-    return;
-  }
+  vt->parser.string_initial = FALSE;
 }
 
 size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
@@ -135,43 +106,45 @@ size_t vterm_input_write(VTerm *vt, cons
   case CSI_LEADER:
   case CSI_ARGS:
   case CSI_INTERMED:
-  case ESC:
+  case OSC_COMMAND:
+  case DCS_COMMAND:
     string_start = NULL;
     break;
-  case STRING:
-  case ESC_IN_STRING:
+  case OSC:
+  case DCS:
     string_start = bytes;
     break;
   }
 
-#define ENTER_STRING_STATE()   do { vt->parser.state = STRING; string_start = bytes + pos + 1; } while(0)
 #define ENTER_STATE(st)        do { vt->parser.state = st; string_start = NULL; } while(0)
 #define ENTER_NORMAL_STATE()   ENTER_STATE(NORMAL)
 
   for( ; pos < len; pos++) {
     unsigned char c = bytes[pos];
+    int c1_allowed = !vt->mode.utf8;
+    size_t string_len;
 
     if(c == 0x00 || c == 0x7f) { // NUL, DEL
-      if(vt->parser.state >= STRING) {
-        more_string(vt, string_start, bytes + pos - string_start);
+      if(vt->parser.state >= OSC) {
+        string_fragment(vt, string_start, bytes + pos - string_start, FALSE);
         string_start = bytes + pos + 1;
       }
       continue;
     }
     if(c == 0x18 || c == 0x1a) { // CAN, SUB
+      vt->parser.in_esc = FALSE;
       ENTER_NORMAL_STATE();
       continue;
     }
     else if(c == 0x1b) { // ESC
       vt->parser.intermedlen = 0;
-      if(vt->parser.state == STRING)
-        vt->parser.state = ESC_IN_STRING;
-      else
-        ENTER_STATE(ESC);
+      if(vt->parser.state < OSC)
+        vt->parser.state = NORMAL;
+      vt->parser.in_esc = TRUE;
       continue;
     }
     else if(c == 0x07 &&  // BEL, can stand for ST in OSC or DCS state
-            vt->parser.state == STRING) {
+            vt->parser.state >= OSC) {
       // fallthrough
     }
     else if(c < 0x20) { // other C0
@@ -182,96 +155,72 @@ size_t vterm_input_write(VTerm *vt, cons
           if(pos + 2 < len && bytes[pos + 1] == 0x20 && bytes[pos + 2] == 0x08)
             vt->in_backspace = 2; // Trigger when count down to 1
       }
-      if(vt->parser.state >= STRING)
-        more_string(vt, string_start, bytes + pos - string_start);
+      if(vt->parser.state >= OSC)
+        string_fragment(vt, string_start, bytes + pos - string_start, FALSE);
       do_control(vt, c);
-      if(vt->parser.state >= STRING)
+      if(vt->parser.state >= OSC)
         string_start = bytes + pos + 1;
       continue;
     }
     // else fallthrough
 
-    switch(vt->parser.state) {
-    case ESC_IN_STRING:
-      if(c == 0x5c) { // ST
-        vt->parser.state = STRING;
-        done_string(vt, string_start, bytes + pos - string_start - 1);
-        ENTER_NORMAL_STATE();
-        break;
-      }
-      vt->parser.state = ESC;
-      // else fallthrough
+    string_len = bytes + pos - string_start;
 
-    case ESC:
-      switch(c) {
-      case 0x50: // DCS
-        start_string(vt, VTERM_PARSER_DCS);
-        ENTER_STRING_STATE();
-        break;
-      case 0x5b: // CSI
-        vt->parser.csi_leaderlen = 0;
-        ENTER_STATE(CSI_LEADER);
-        break;
-      case 0x5d: // OSC
-        start_string(vt, VTERM_PARSER_OSC);
-        ENTER_STRING_STATE();
-        break;
-      default:
-        if(is_intermed(c)) {
-          if(vt->parser.intermedlen < INTERMED_MAX-1)
-            vt->parser.intermed[vt->parser.intermedlen++] = c;
-        }
-        else if(!vt->parser.intermedlen && c >= 0x40 && c < 0x60) {
-          do_control(vt, c + 0x40);
-          ENTER_NORMAL_STATE();
-        }
-        else if(c >= 0x30 && c < 0x7f) {
-          do_escape(vt, c);
-          ENTER_NORMAL_STATE();
-        }
-        else {
-          DEBUG_LOG1("TODO: Unhandled byte %02x in Escape\n", c);
-        }
+    if(vt->parser.in_esc) {
+      // Hoist an ESC letter into a C1 if we're not in a string mode
+      // Always accept ESC \ == ST even in string mode
+      if(!vt->parser.intermedlen &&
+          c >= 0x40 && c < 0x60 &&
+          ((vt->parser.state < OSC || c == 0x5c))) {
+        c += 0x40;
+        c1_allowed = TRUE;
+        string_len -= 1;
+        vt->parser.in_esc = FALSE;
       }
-      break;
+      else {
+        string_start = NULL;
+        vt->parser.state = NORMAL;
+      }
+    }
 
+    switch(vt->parser.state) {
     case CSI_LEADER:
       // Extract leader bytes 0x3c to 0x3f
       if(c >= 0x3c && c <= 0x3f) {
-        if(vt->parser.csi_leaderlen < CSI_LEADER_MAX-1)
-          vt->parser.csi_leader[vt->parser.csi_leaderlen++] = c;
+        if(vt->parser.v.csi.leaderlen < CSI_LEADER_MAX-1)
+          vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen++] = c;
         break;
       }
 
       // else fallthrough
-      vt->parser.csi_leader[vt->parser.csi_leaderlen] = 0;
+      vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen] = 0;
 
-      vt->parser.csi_argi = 0;
-      vt->parser.csi_args[0] = CSI_ARG_MISSING;
+      vt->parser.v.csi.argi = 0;
+      vt->parser.v.csi.args[0] = CSI_ARG_MISSING;
       vt->parser.state = CSI_ARGS;
 
       // fallthrough
     case CSI_ARGS:
       // Numerical value of argument
       if(c >= '0' && c <= '9') {
-        if(vt->parser.csi_args[vt->parser.csi_argi] == CSI_ARG_MISSING)
-          vt->parser.csi_args[vt->parser.csi_argi] = 0;
-        vt->parser.csi_args[vt->parser.csi_argi] *= 10;
-        vt->parser.csi_args[vt->parser.csi_argi] += c - '0';
+        if(vt->parser.v.csi.args[vt->parser.v.csi.argi] == CSI_ARG_MISSING)
+          vt->parser.v.csi.args[vt->parser.v.csi.argi] = 0;
+        vt->parser.v.csi.args[vt->parser.v.csi.argi] *= 10;
+        vt->parser.v.csi.args[vt->parser.v.csi.argi] += c - '0';
         break;
       }
       if(c == ':') {
-        vt->parser.csi_args[vt->parser.csi_argi] |= CSI_ARG_FLAG_MORE;
+        vt->parser.v.csi.args[vt->parser.v.csi.argi] |= CSI_ARG_FLAG_MORE;
         c = ';';
       }
       if(c == ';') {
-        vt->parser.csi_argi++;
-        vt->parser.csi_args[vt->parser.csi_argi] = CSI_ARG_MISSING;
+        vt->parser.v.csi.argi++;
+        vt->parser.v.csi.args[vt->parser.v.csi.argi] = CSI_ARG_MISSING;
         break;
       }
 
       // else fallthrough
-      vt->parser.csi_argi++;
+      vt->parser.v.csi.argi++;
       vt->parser.intermedlen = 0;
       vt->parser.state = CSI_INTERMED;
       // fallthrough
@@ -293,31 +242,77 @@ size_t vterm_input_write(VTerm *vt, cons
       ENTER_NORMAL_STATE();
       break;
 
-    case STRING:
-      if(c == 0x07 || (c == 0x9c && !vt->mode.utf8)) {
-        done_string(vt, string_start, bytes + pos - string_start);
-        ENTER_NORMAL_STATE();
+    case OSC_COMMAND:
+      /* Numerical value of command */
+      if(c >= '0' && c <= '9') {
+        if(vt->parser.v.osc.command == -1)
+          vt->parser.v.osc.command = 0;
+        else
+          vt->parser.v.osc.command *= 10;
+        vt->parser.v.osc.command += c - '0';
+        break;
+      }
+      if(c == ';') {
+        vt->parser.state = OSC;
+        string_start = bytes + pos + 1;
+        break;
       }
-      else if (pos + 1 == len) {
-	// end of input but OSC string isn't finished yet, copy it to
-	// vt->parser.strbuffer to continue it later
-        more_string(vt, string_start, bytes + pos + 1 - string_start);
+
+      /* else fallthrough */
+      string_start = bytes + pos;
+      vt->parser.state = OSC;
+      goto string_state;
+
+    case DCS_COMMAND:
+      if(vt->parser.v.dcs.commandlen < CSI_LEADER_MAX)
+        vt->parser.v.dcs.command[vt->parser.v.dcs.commandlen++] = c;
+
+      if(c >= 0x40 && c<= 0x7e) {
+        string_start = bytes + pos + 1;
+        vt->parser.state = DCS;
+      }
+      break;
+
+string_state:
+    case OSC:
+    case DCS:
+      if(c == 0x07 || (c1_allowed && c == 0x9c)) {
+        string_fragment(vt, string_start, string_len, TRUE);
+        ENTER_NORMAL_STATE();
       }
       break;
 
     case NORMAL:
-      if(c >= 0x80 && c < 0xa0 && !vt->mode.utf8) {
+      if(vt->parser.in_esc) {
+        if(is_intermed(c)) {
+          if(vt->parser.intermedlen < INTERMED_MAX-1)
+            vt->parser.intermed[vt->parser.intermedlen++] = c;
+        }
+        else if(c >= 0x30 && c < 0x7f) {
+          do_escape(vt, c);
+          vt->parser.in_esc = 0;
+          ENTER_NORMAL_STATE();
+        }
+        else {
+          DEBUG_LOG1("TODO: Unhandled byte %02x in Escape\n", c);
+        }
+        break;
+      }
+      if(c1_allowed && c >= 0x80 && c < 0xa0) {
         switch(c) {
         case 0x90: // DCS
-          start_string(vt, VTERM_PARSER_DCS);
-          ENTER_STRING_STATE();
+          vt->parser.string_initial = TRUE;
+          vt->parser.v.dcs.commandlen = 0;
+          ENTER_STATE(DCS_COMMAND);
           break;
         case 0x9b: // CSI
+          vt->parser.v.csi.leaderlen = 0;
           ENTER_STATE(CSI_LEADER);
           break;
         case 0x9d: // OSC
-          start_string(vt, VTERM_PARSER_OSC);
-          ENTER_STRING_STATE();
+          vt->parser.v.osc.command = -1;
+          vt->parser.string_initial = TRUE;
+          ENTER_STATE(OSC_COMMAND);
           break;
         default:
           do_control(vt, c);
@@ -341,6 +336,9 @@ size_t vterm_input_write(VTerm *vt, cons
     }
   }
 
+  if(string_start)
+    string_fragment(vt, string_start, bytes + pos - string_start, FALSE);
+
   return len;
 }