aboutsummaryrefslogtreecommitdiff
path: root/src/vterm/parser.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2025-02-05 23:09:29 +0000
committerJosh Rahm <joshuarahm@gmail.com>2025-02-05 23:09:29 +0000
commitd5f194ce780c95821a855aca3c19426576d28ae0 (patch)
treed45f461b19f9118ad2bb1f440a7a08973ad18832 /src/vterm/parser.c
parentc5d770d311841ea5230426cc4c868e8db27300a8 (diff)
parent44740e561fc93afe3ebecfd3618bda2d2abeafb0 (diff)
downloadrneovim-rahm.tar.gz
rneovim-rahm.tar.bz2
rneovim-rahm.zip
Merge remote-tracking branch 'upstream/master' into mix_20240309HEADrahm
Diffstat (limited to 'src/vterm/parser.c')
-rw-r--r--src/vterm/parser.c408
1 files changed, 0 insertions, 408 deletions
diff --git a/src/vterm/parser.c b/src/vterm/parser.c
deleted file mode 100644
index 84d017a791..0000000000
--- a/src/vterm/parser.c
+++ /dev/null
@@ -1,408 +0,0 @@
-#include "vterm_internal.h"
-
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-
-#undef DEBUG_PARSER
-
-static bool is_intermed(unsigned char c)
-{
- return c >= 0x20 && c <= 0x2f;
-}
-
-static void do_control(VTerm *vt, unsigned char control)
-{
- if(vt->parser.callbacks && vt->parser.callbacks->control)
- if((*vt->parser.callbacks->control)(control, vt->parser.cbdata))
- return;
-
- DEBUG_LOG("libvterm: Unhandled control 0x%02x\n", control);
-}
-
-static void do_csi(VTerm *vt, char command)
-{
-#ifdef DEBUG_PARSER
- printf("Parsed CSI args as:\n", arglen, args);
- 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);
- }
-#endif
-
- if(vt->parser.callbacks && vt->parser.callbacks->csi)
- if((*vt->parser.callbacks->csi)(
- 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))
- return;
-
- DEBUG_LOG("libvterm: Unhandled CSI %c\n", command);
-}
-
-static void do_escape(VTerm *vt, char command)
-{
- char seq[INTERMED_MAX+1];
-
- size_t len = vt->parser.intermedlen;
- strncpy(seq, vt->parser.intermed, len);
- seq[len++] = command;
- seq[len] = 0;
-
- if(vt->parser.callbacks && vt->parser.callbacks->escape)
- if((*vt->parser.callbacks->escape)(seq, len, vt->parser.cbdata))
- return;
-
- DEBUG_LOG("libvterm: Unhandled escape ESC 0x%02x\n", command);
-}
-
-static void string_fragment(VTerm *vt, const char *str, size_t len, bool final)
-{
- VTermStringFragment frag = {
- .str = str,
- .len = len,
- .initial = vt->parser.string_initial,
- .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(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 APC:
- if(vt->parser.callbacks && vt->parser.callbacks->apc)
- (*vt->parser.callbacks->apc)(frag, vt->parser.cbdata);
- break;
-
- case PM:
- if(vt->parser.callbacks && vt->parser.callbacks->pm)
- (*vt->parser.callbacks->pm)(frag, vt->parser.cbdata);
- break;
-
- case SOS:
- if(vt->parser.callbacks && vt->parser.callbacks->sos)
- (*vt->parser.callbacks->sos)(frag, vt->parser.cbdata);
- break;
-
- case NORMAL:
- case CSI_LEADER:
- case CSI_ARGS:
- case CSI_INTERMED:
- case OSC_COMMAND:
- case DCS_COMMAND:
- break;
- }
-
- vt->parser.string_initial = false;
-}
-
-size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
-{
- size_t pos = 0;
- const char *string_start;
-
- switch(vt->parser.state) {
- case NORMAL:
- case CSI_LEADER:
- case CSI_ARGS:
- case CSI_INTERMED:
- case OSC_COMMAND:
- case DCS_COMMAND:
- string_start = NULL;
- break;
- case OSC:
- case DCS:
- case APC:
- case PM:
- case SOS:
- string_start = bytes;
- break;
- }
-
-#define ENTER_STATE(st) do { vt->parser.state = st; string_start = NULL; } while(0)
-#define ENTER_NORMAL_STATE() ENTER_STATE(NORMAL)
-
-#define IS_STRING_STATE() (vt->parser.state >= OSC_COMMAND)
-
- for( ; pos < len; pos++) {
- unsigned char c = bytes[pos];
- bool c1_allowed = !vt->mode.utf8;
-
- if(c == 0x00 || c == 0x7f) { // NUL, DEL
- if(IS_STRING_STATE()) {
- string_fragment(vt, string_start, bytes + pos - string_start, false);
- string_start = bytes + pos + 1;
- }
- if(vt->parser.emit_nul)
- do_control(vt, c);
- continue;
- }
- if(c == 0x18 || c == 0x1a) { // CAN, SUB
- vt->parser.in_esc = false;
- ENTER_NORMAL_STATE();
- if(vt->parser.emit_nul)
- do_control(vt, c);
- continue;
- }
- else if(c == 0x1b) { // ESC
- vt->parser.intermedlen = 0;
- if(!IS_STRING_STATE())
- vt->parser.state = NORMAL;
- vt->parser.in_esc = true;
- continue;
- }
- else if(c == 0x07 && // BEL, can stand for ST in OSC or DCS state
- IS_STRING_STATE()) {
- // fallthrough
- }
- else if(c < 0x20) { // other C0
- if(vt->parser.state == SOS)
- continue; // All other C0s permitted in SOS
-
- if(IS_STRING_STATE())
- string_fragment(vt, string_start, bytes + pos - string_start, false);
- do_control(vt, c);
- if(IS_STRING_STATE())
- string_start = bytes + pos + 1;
- continue;
- }
- // else fallthrough
-
- size_t string_len = bytes + pos - string_start;
-
- 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 &&
- ((!IS_STRING_STATE() || c == 0x5c))) {
- c += 0x40;
- c1_allowed = true;
- if(string_len) {
- assert(string_len > 0);
- string_len -= 1;
- }
- vt->parser.in_esc = false;
- }
- 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.v.csi.leaderlen < CSI_LEADER_MAX-1)
- vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen++] = c;
- break;
- }
-
- /* else fallthrough */
- vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen] = 0;
-
- 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.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.v.csi.args[vt->parser.v.csi.argi] |= CSI_ARG_FLAG_MORE;
- c = ';';
- }
- if(c == ';') {
- vt->parser.v.csi.argi++;
- vt->parser.v.csi.args[vt->parser.v.csi.argi] = CSI_ARG_MISSING;
- break;
- }
-
- /* else fallthrough */
- vt->parser.v.csi.argi++;
- vt->parser.intermedlen = 0;
- vt->parser.state = CSI_INTERMED;
- case CSI_INTERMED:
- if(is_intermed(c)) {
- if(vt->parser.intermedlen < INTERMED_MAX-1)
- vt->parser.intermed[vt->parser.intermedlen++] = c;
- break;
- }
- else if(c == 0x1b) {
- /* ESC in CSI cancels */
- }
- else if(c >= 0x40 && c <= 0x7e) {
- vt->parser.intermed[vt->parser.intermedlen] = 0;
- do_csi(vt, c);
- }
- /* else was invalid CSI */
-
- ENTER_NORMAL_STATE();
- break;
-
- 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 fallthrough */
- string_start = bytes + pos;
- string_len = 0;
- 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:
- case APC:
- case PM:
- case SOS:
- if(c == 0x07 || (c1_allowed && c == 0x9c)) {
- string_fragment(vt, string_start, string_len, true);
- ENTER_NORMAL_STATE();
- }
- break;
-
- case NORMAL:
- 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_LOG("TODO: Unhandled byte %02x in Escape\n", c);
- }
- break;
- }
- if(c1_allowed && c >= 0x80 && c < 0xa0) {
- switch(c) {
- case 0x90: // DCS
- vt->parser.string_initial = true;
- vt->parser.v.dcs.commandlen = 0;
- ENTER_STATE(DCS_COMMAND);
- break;
- case 0x98: // SOS
- vt->parser.string_initial = true;
- ENTER_STATE(SOS);
- string_start = bytes + pos + 1;
- string_len = 0;
- break;
- case 0x9b: // CSI
- vt->parser.v.csi.leaderlen = 0;
- ENTER_STATE(CSI_LEADER);
- break;
- case 0x9d: // OSC
- vt->parser.v.osc.command = -1;
- vt->parser.string_initial = true;
- string_start = bytes + pos + 1;
- ENTER_STATE(OSC_COMMAND);
- break;
- case 0x9e: // PM
- vt->parser.string_initial = true;
- ENTER_STATE(PM);
- string_start = bytes + pos + 1;
- string_len = 0;
- break;
- case 0x9f: // APC
- vt->parser.string_initial = true;
- ENTER_STATE(APC);
- string_start = bytes + pos + 1;
- string_len = 0;
- break;
- default:
- do_control(vt, c);
- break;
- }
- }
- else {
- size_t eaten = 0;
- if(vt->parser.callbacks && vt->parser.callbacks->text)
- eaten = (*vt->parser.callbacks->text)(bytes + pos, len - pos, vt->parser.cbdata);
-
- if(!eaten) {
- DEBUG_LOG("libvterm: Text callback did not consume any input\n");
- /* force it to make progress */
- eaten = 1;
- }
-
- pos += (eaten - 1); // we'll ++ it again in a moment
- }
- break;
- }
- }
-
- if(string_start) {
- size_t string_len = bytes + pos - string_start;
- if (string_len > 0) {
- if(vt->parser.in_esc) {
- string_len -= 1;
- }
- string_fragment(vt, string_start, string_len, false);
- }
- }
-
- return len;
-}
-
-void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user)
-{
- vt->parser.callbacks = callbacks;
- vt->parser.cbdata = user;
-}
-
-void *vterm_parser_get_cbdata(VTerm *vt)
-{
- return vt->parser.cbdata;
-}
-
-void vterm_parser_set_emit_nul(VTerm *vt, bool emit)
-{
- vt->parser.emit_nul = emit;
-}