To: vim_dev@googlegroups.com Subject: Patch 8.0.1639 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.0.1639 Problem: Libvterm code lags behind master. Solution: Sync to head, solve merge problems. Files: src/libvterm/README, src/libvterm/bin/unterm.c, src/libvterm/bin/vterm-ctrl.c, src/libvterm/bin/vterm-dump.c, src/libvterm/doc/URLs, src/libvterm/doc/seqs.txt, src/libvterm/include/vterm.h, src/libvterm/include/vterm_keycodes.h, src/libvterm/src/mouse.c, src/libvterm/src/parser.c, src/libvterm/src/pen.c, src/libvterm/src/screen.c, src/libvterm/src/state.c, src/libvterm/src/vterm.c, src/libvterm/src/vterm_internal.h, src/libvterm/t/10state_putglyph.test, src/libvterm/t/25state_input.test, src/libvterm/t/harness.c, src/libvterm/t/26state_query.test *** ../vim-8.0.1638/src/libvterm/README 2017-07-23 22:07:23.041277153 +0200 --- src/libvterm/README 2018-03-25 15:51:01.967096196 +0200 *************** *** 10,12 **** --- 10,30 ---- - Add a .gitignore file. - Convert from C99 to C90. - Other changes to support embedding in Vim. + + + To merge in changes from Github, do this: + - Commit any pending changes. + - Setup the merge tool: + git config merge.tool vimdiff + git config merge.conflictstyle diff3 + git config mergetool.prompt false + - Run the merge tool: + git mergetool + This will open a four-way diff between: + LOCAL - your current version + BASE - version as it was at your last sync + REMOTE - version at head on Github + MERGED - best-effort merge of LOCAL and REMOTE + Now find places where automatic merge didn't work, they are marked with + <<<<<<<<, ======= and >>>>>>> + Fix those places in MERGED, remove the markers, and save the file :wqall. *** ../vim-8.0.1638/src/libvterm/bin/unterm.c 2017-07-25 21:34:42.065132676 +0200 --- src/libvterm/bin/unterm.c 2018-03-25 15:04:33.706954390 +0200 *************** *** 95,102 **** sgr[sgri++] = 90 + (index - 8); else { sgr[sgri++] = 38; ! sgr[sgri++] = 5 | (1<<31); ! sgr[sgri++] = index | (1<<31); } } --- 95,102 ---- sgr[sgri++] = 90 + (index - 8); else { sgr[sgri++] = 38; ! sgr[sgri++] = 5 | CSI_ARG_FLAG_MORE; ! sgr[sgri++] = index | CSI_ARG_FLAG_MORE; } } *************** *** 112,119 **** sgr[sgri++] = 100 + (index - 8); else { sgr[sgri++] = 48; ! sgr[sgri++] = 5 | (1<<31); ! sgr[sgri++] = index | (1<<31); } } --- 112,119 ---- sgr[sgri++] = 100 + (index - 8); else { sgr[sgri++] = 48; ! sgr[sgri++] = 5 | CSI_ARG_FLAG_MORE; ! sgr[sgri++] = index | CSI_ARG_FLAG_MORE; } } *************** *** 125,133 **** int i; for(i = 0; i < sgri; i++) printf(!i ? "%d" : ! sgr[i] & (1<<31) ? ":%d" : ";%d", ! sgr[i] & ~(1<<31)); } printf("m"); } --- 125,133 ---- int i; for(i = 0; i < sgri; i++) printf(!i ? "%d" : ! CSI_ARG_HAS_MORE(sgr[i]) ? ":%d" : ";%d", ! CSI_ARG(sgr[i])); } printf("m"); } *************** *** 283,287 **** --- 283,288 ---- close(fd); vterm_free(vt); + return 0; } *** ../vim-8.0.1638/src/libvterm/bin/vterm-ctrl.c 2017-07-24 22:26:39.757774872 +0200 --- src/libvterm/bin/vterm-ctrl.c 2018-03-25 15:12:40.460260840 +0200 *************** *** 53,58 **** --- 53,59 ---- "curblink [off|on|query]", "curshape [block|under|bar|query]", "mouse [off|click|clickdrag|motion]", + "reportfocus [off|on|query]", "altscreen [off|on|query]", "bracketpaste [off|on|query]", "icontitle [STR]", *************** *** 81,89 **** return ret; } ! static void await_c1(int c1) { ! int c; /* await CSI - 8bit or 2byte 7bit form */ int in_esc = FALSE; --- 82,90 ---- return ret; } ! static void await_c1(unsigned char c1) { ! unsigned char c; /* await CSI - 8bit or 2byte 7bit form */ int in_esc = FALSE; *************** *** 340,345 **** --- 341,349 ---- printf("\x1b[?1003h"); break; } } + else if(streq(arg, "reportfocus")) { + do_dec_mode(1004, getboolq(&argi, argc, argv), "reportfocus"); + } else if(streq(arg, "altscreen")) { do_dec_mode(1049, getboolq(&argi, argc, argv), "altscreen"); } *** ../vim-8.0.1638/src/libvterm/bin/vterm-dump.c 2017-07-07 11:53:29.515876528 +0200 --- src/libvterm/bin/vterm-dump.c 2018-03-25 15:13:04.920126272 +0200 *************** *** 227,231 **** --- 227,232 ---- close(fd); vterm_free(vt); + return 0; } *** ../vim-8.0.1638/src/libvterm/doc/URLs 2017-07-07 11:53:29.515876528 +0200 --- src/libvterm/doc/URLs 2018-03-25 14:54:41.670318525 +0200 *************** *** 9,11 **** --- 9,14 ---- Digital VT220 Programmer Reference Manual http://vt100.net/docs/vt220-rm/ + + Summary of ANSI standards for ASCII terminals + http://www.inwap.com/pdp10/ansicode.txt *** ../vim-8.0.1638/src/libvterm/doc/seqs.txt 2017-07-07 11:53:29.515876528 +0200 --- src/libvterm/doc/seqs.txt 2018-03-25 14:54:41.670318525 +0200 *************** *** 151,156 **** --- 151,157 ---- DECSM 1000 = Mouse click/release tracking DECSM 1002 = Mouse click/release/drag tracking DECSM 1003 = Mouse all movements tracking + DECSM 1004 = Focus in/out reporting DECSM 1005 = Mouse protocol extended (UTF-8) - not recommended DECSM 1006 = Mouse protocol SGR DECSM 1015 = Mouse protocol rxvt *** ../vim-8.0.1638/src/libvterm/include/vterm.h 2018-03-11 19:30:40.124142765 +0100 --- src/libvterm/include/vterm.h 2018-03-25 15:17:15.922747952 +0200 *************** *** 96,102 **** VTERM_VALUETYPE_BOOL = 1, VTERM_VALUETYPE_INT, VTERM_VALUETYPE_STRING, ! VTERM_VALUETYPE_COLOR } VTermValueType; typedef union { --- 96,104 ---- VTERM_VALUETYPE_BOOL = 1, VTERM_VALUETYPE_INT, VTERM_VALUETYPE_STRING, ! VTERM_VALUETYPE_COLOR, ! ! VTERM_N_VALUETYPES } VTermValueType; typedef union { *************** *** 116,122 **** VTERM_ATTR_STRIKE, /* bool: 9, 29 */ VTERM_ATTR_FONT, /* number: 10-19 */ VTERM_ATTR_FOREGROUND, /* color: 30-39 90-97 */ ! VTERM_ATTR_BACKGROUND /* color: 40-49 100-107 */ } VTermAttr; typedef enum { --- 118,126 ---- VTERM_ATTR_STRIKE, /* bool: 9, 29 */ VTERM_ATTR_FONT, /* number: 10-19 */ VTERM_ATTR_FOREGROUND, /* color: 30-39 90-97 */ ! VTERM_ATTR_BACKGROUND, /* color: 40-49 100-107 */ ! ! VTERM_N_ATTRS } VTermAttr; typedef enum { *************** *** 129,148 **** VTERM_PROP_REVERSE, /* bool */ VTERM_PROP_CURSORSHAPE, /* number */ VTERM_PROP_MOUSE, /* number */ ! VTERM_PROP_CURSORCOLOR /* string */ } VTermProp; enum { VTERM_PROP_CURSORSHAPE_BLOCK = 1, VTERM_PROP_CURSORSHAPE_UNDERLINE, ! VTERM_PROP_CURSORSHAPE_BAR_LEFT }; enum { VTERM_PROP_MOUSE_NONE = 0, VTERM_PROP_MOUSE_CLICK, VTERM_PROP_MOUSE_DRAG, ! VTERM_PROP_MOUSE_MOVE }; typedef struct { --- 133,158 ---- VTERM_PROP_REVERSE, /* bool */ VTERM_PROP_CURSORSHAPE, /* number */ VTERM_PROP_MOUSE, /* number */ ! VTERM_PROP_CURSORCOLOR, /* string */ ! ! VTERM_N_PROPS } VTermProp; enum { VTERM_PROP_CURSORSHAPE_BLOCK = 1, VTERM_PROP_CURSORSHAPE_UNDERLINE, ! VTERM_PROP_CURSORSHAPE_BAR_LEFT, ! ! VTERM_N_PROP_CURSORSHAPES }; enum { VTERM_PROP_MOUSE_NONE = 0, VTERM_PROP_MOUSE_CLICK, VTERM_PROP_MOUSE_DRAG, ! VTERM_PROP_MOUSE_MOVE, ! ! VTERM_N_PROP_MOUSES }; typedef struct { *************** *** 213,220 **** * * Don't confuse this with the final byte of the CSI escape; 'a' in this case. */ ! #define CSI_ARG_FLAG_MORE (1<<30) ! #define CSI_ARG_MASK (~(1<<30)) #define CSI_ARG_HAS_MORE(a) ((a) & CSI_ARG_FLAG_MORE) #define CSI_ARG(a) ((a) & CSI_ARG_MASK) --- 223,230 ---- * * Don't confuse this with the final byte of the CSI escape; 'a' in this case. */ ! #define CSI_ARG_FLAG_MORE (1U<<31) ! #define CSI_ARG_MASK (~(1U<<31)) #define CSI_ARG_HAS_MORE(a) ((a) & CSI_ARG_FLAG_MORE) #define CSI_ARG(a) ((a) & CSI_ARG_MASK) *************** *** 293,298 **** --- 303,310 ---- void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright); int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val); int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val); + void vterm_state_focus_in(VTermState *state); + void vterm_state_focus_out(VTermState *state); const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row); /* ------------ *************** *** 357,363 **** VTERM_DAMAGE_CELL, /* every cell */ VTERM_DAMAGE_ROW, /* entire rows */ VTERM_DAMAGE_SCREEN, /* entire screen */ ! VTERM_DAMAGE_SCROLL /* entire screen + scrollrect */ } VTermDamageSize; /* Invoke the relevant callbacks to update the screen. */ --- 369,377 ---- VTERM_DAMAGE_CELL, /* every cell */ VTERM_DAMAGE_ROW, /* entire rows */ VTERM_DAMAGE_SCREEN, /* entire screen */ ! VTERM_DAMAGE_SCROLL, /* entire screen + scrollrect */ ! ! VTERM_N_DAMAGES } VTermDamageSize; /* Invoke the relevant callbacks to update the screen. */ *************** *** 384,390 **** VTERM_ATTR_STRIKE_MASK = 1 << 5, VTERM_ATTR_FONT_MASK = 1 << 6, VTERM_ATTR_FOREGROUND_MASK = 1 << 7, ! VTERM_ATTR_BACKGROUND_MASK = 1 << 8 } VTermAttrMask; int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs); --- 398,406 ---- VTERM_ATTR_STRIKE_MASK = 1 << 5, VTERM_ATTR_FONT_MASK = 1 << 6, VTERM_ATTR_FOREGROUND_MASK = 1 << 7, ! VTERM_ATTR_BACKGROUND_MASK = 1 << 8, ! ! VTERM_ALL_ATTRS_MASK = (1 << 9) - 1 } VTermAttrMask; int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs); *** ../vim-8.0.1638/src/libvterm/include/vterm_keycodes.h 2018-02-27 17:25:48.012151938 +0100 --- src/libvterm/include/vterm_keycodes.h 2018-03-25 15:17:54.606535872 +0200 *************** *** 5,11 **** VTERM_MOD_NONE = 0x00, VTERM_MOD_SHIFT = 0x01, VTERM_MOD_ALT = 0x02, ! VTERM_MOD_CTRL = 0x04 } VTermModifier; /* The order here must match keycodes[] in src/keyboard.c! */ --- 5,13 ---- VTERM_MOD_NONE = 0x00, VTERM_MOD_SHIFT = 0x01, VTERM_MOD_ALT = 0x02, ! VTERM_MOD_CTRL = 0x04, ! ! VTERM_ALL_MODS_MASK = 0x07 } VTermModifier; /* The order here must match keycodes[] in src/keyboard.c! */ *************** *** 53,59 **** VTERM_KEY_KP_ENTER, VTERM_KEY_KP_EQUAL, ! VTERM_KEY_MAX /* Must be last */ } VTermKey; #define VTERM_KEY_FUNCTION(n) (VTERM_KEY_FUNCTION_0+(n)) --- 55,62 ---- VTERM_KEY_KP_ENTER, VTERM_KEY_KP_EQUAL, ! VTERM_KEY_MAX, /* Must be last */ ! VTERM_N_KEYS = VTERM_KEY_MAX } VTermKey; #define VTERM_KEY_FUNCTION(n) (VTERM_KEY_FUNCTION_0+(n)) *** ../vim-8.0.1638/src/libvterm/src/mouse.c 2017-08-05 18:02:17.162202692 +0200 --- src/libvterm/src/mouse.c 2018-03-11 17:55:59.250467734 +0100 *************** *** 63,71 **** if((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons) || (state->mouse_flags & MOUSE_WANT_MOVE)) { ! int button = state->mouse_buttons & 0x01 ? 1 : ! state->mouse_buttons & 0x02 ? 2 : ! state->mouse_buttons & 0x04 ? 3 : 4; output_mouse(state, button-1 + 0x20, 1, mod, col, row); } } --- 63,71 ---- if((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons) || (state->mouse_flags & MOUSE_WANT_MOVE)) { ! int button = state->mouse_buttons & MOUSE_BUTTON_LEFT ? 1 : ! state->mouse_buttons & MOUSE_BUTTON_MIDDLE ? 2 : ! state->mouse_buttons & MOUSE_BUTTON_RIGHT ? 3 : 4; output_mouse(state, button-1 + 0x20, 1, mod, col, row); } } *** ../vim-8.0.1638/src/libvterm/src/parser.c 2017-07-23 22:07:23.041277153 +0200 --- src/libvterm/src/parser.c 2018-03-25 16:07:46.489469961 +0200 *************** *** 3,190 **** #include #include ! #define CSI_ARGS_MAX 16 ! #define CSI_LEADER_MAX 16 ! #define CSI_INTERMED_MAX 16 static void do_control(VTerm *vt, unsigned char control) { ! if(vt->parser_callbacks && vt->parser_callbacks->control) ! if((*vt->parser_callbacks->control)(control, vt->cbdata)) return; DEBUG_LOG1("libvterm: Unhandled control 0x%02x\n", control); } ! static void do_string_csi(VTerm *vt, const char *args, size_t arglen, char command) { ! int i = 0; ! ! int leaderlen = 0; ! char leader[CSI_LEADER_MAX]; ! int argcount = 1; /* Always at least 1 arg */ ! long csi_args[CSI_ARGS_MAX]; ! int argi; ! int intermedlen = 0; ! char intermed[CSI_INTERMED_MAX]; ! ! /* Extract leader bytes 0x3c to 0x3f */ ! for( ; i < (int)arglen; i++) { ! if(args[i] < 0x3c || args[i] > 0x3f) ! break; ! if(leaderlen < CSI_LEADER_MAX-1) ! leader[leaderlen++] = args[i]; ! } ! ! leader[leaderlen] = 0; ! ! for( ; i < (int)arglen; i++) ! if(args[i] == 0x3b || args[i] == 0x3a) /* ; or : */ ! argcount++; ! ! /* TODO: Consider if these buffers should live in the VTerm struct itself */ ! if(argcount > CSI_ARGS_MAX) ! argcount = CSI_ARGS_MAX; ! ! for(argi = 0; argi < argcount; argi++) ! csi_args[argi] = CSI_ARG_MISSING; ! ! argi = 0; ! for(i = leaderlen; i < (int)arglen && argi < argcount; i++) { ! switch(args[i]) { ! case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: ! case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: ! if(csi_args[argi] == CSI_ARG_MISSING) ! csi_args[argi] = 0; ! csi_args[argi] *= 10; ! csi_args[argi] += args[i] - '0'; ! break; ! case 0x3a: ! csi_args[argi] |= CSI_ARG_FLAG_MORE; ! /* FALLTHROUGH */ ! case 0x3b: ! argi++; ! break; ! default: ! goto done_leader; ! } } ! done_leader: ; ! ! for( ; i < (int)arglen; i++) { ! if((args[i] & 0xf0) != 0x20) ! break; ! if(intermedlen < CSI_INTERMED_MAX-1) ! intermed[intermedlen++] = args[i]; ! } ! intermed[intermedlen] = 0; ! if(i < (int)arglen) { ! DEBUG_LOG2("libvterm: TODO unhandled CSI bytes \"%.*s\"\n", (int)(arglen - i), args + i); ! } ! #if 0 ! printf("Parsed CSI args %.*s as:\n", arglen, args); ! printf(" leader: %s\n", leader); ! for(argi = 0; argi < argcount; argi++) { ! printf(" %lu", CSI_ARG(csi_args[argi])); ! if(!CSI_ARG_HAS_MORE(csi_args[argi])) ! printf("\n"); ! printf(" intermed: %s\n", intermed); ! } ! #endif ! if(vt->parser_callbacks && vt->parser_callbacks->csi) ! if((*vt->parser_callbacks->csi)(leaderlen ? leader : NULL, csi_args, argcount, intermedlen ? intermed : NULL, command, vt->cbdata)) return; ! DEBUG_LOG3("libvterm: Unhandled CSI %.*s %c\n", (int)arglen, args, command); } static void append_strbuffer(VTerm *vt, const char *str, size_t len) { ! if(len > vt->strbuffer_len - vt->strbuffer_cur) { ! len = vt->strbuffer_len - vt->strbuffer_cur; DEBUG_LOG1("Truncating strbuffer preserve to %zd bytes\n", len); } if(len > 0) { ! strncpy(vt->strbuffer + vt->strbuffer_cur, str, len); ! vt->strbuffer_cur += len; } } ! static size_t do_string(VTerm *vt, const char *str_frag, size_t len) { ! size_t eaten; ! if(vt->strbuffer_cur) { ! if(str_frag) ! append_strbuffer(vt, str_frag, len); ! str_frag = vt->strbuffer; ! len = vt->strbuffer_cur; } ! else if(!str_frag) { DEBUG_LOG("parser.c: TODO: No strbuffer _and_ no final fragment???\n"); len = 0; } ! vt->strbuffer_cur = 0; ! ! switch(vt->parser_state) { ! case NORMAL: ! if(vt->parser_callbacks && vt->parser_callbacks->text) ! if((eaten = (*vt->parser_callbacks->text)(str_frag, len, vt->cbdata))) ! return eaten; ! ! DEBUG_LOG1("libvterm: Unhandled text (%zu chars)\n", len); ! return 0; ! case ESC: ! if(len == 1 && str_frag[0] >= 0x40 && str_frag[0] < 0x60) { ! /* C1 emulations using 7bit clean */ ! /* ESC 0x40 == 0x80 */ ! do_control(vt, str_frag[0] + 0x40); ! return 0; ! } ! if(vt->parser_callbacks && vt->parser_callbacks->escape) ! if((*vt->parser_callbacks->escape)(str_frag, len, vt->cbdata)) ! return 0; ! ! DEBUG_LOG1("libvterm: Unhandled escape ESC 0x%02x\n", str_frag[len-1]); ! return 0; ! ! case CSI: ! do_string_csi(vt, str_frag, len - 1, str_frag[len - 1]); ! return 0; ! ! case OSC: ! if(vt->parser_callbacks && vt->parser_callbacks->osc) ! if((*vt->parser_callbacks->osc)(str_frag, len, vt->cbdata)) ! return 0; ! ! DEBUG_LOG2("libvterm: Unhandled OSC %.*s\n", (int)len, str_frag); ! return 0; ! ! case DCS: ! if(vt->parser_callbacks && vt->parser_callbacks->dcs) ! if((*vt->parser_callbacks->dcs)(str_frag, len, vt->cbdata)) ! return 0; ! ! DEBUG_LOG2("libvterm: Unhandled DCS %.*s\n", (int)len, str_frag); ! return 0; ! ! case ESC_IN_OSC: ! case ESC_IN_DCS: ! DEBUG_LOG("libvterm: ARGH! Should never do_string() in ESC_IN_{OSC,DCS}\n"); ! return 0; } - - return 0; } size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) --- 3,125 ---- #include #include ! #undef DEBUG_PARSER ! ! static int 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_LOG1("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.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("\n"); ! printf(" intermed: %s\n", vt->parser.intermed); } ! #endif ! 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.intermedlen ? vt->parser.intermed : NULL, ! command, ! vt->parser.cbdata)) ! return; ! DEBUG_LOG1("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_LOG1("libvterm: Unhandled escape ESC 0x%02x\n", command); } static void append_strbuffer(VTerm *vt, const char *str, size_t len) { ! 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 %zd bytes\n", len); } 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; } } size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) *************** *** 192,220 **** size_t pos = 0; const char *string_start = NULL; /* init to avoid gcc warning */ ! switch(vt->parser_state) { case NORMAL: string_start = NULL; break; ! case ESC: ! case ESC_IN_OSC: ! case ESC_IN_DCS: ! case CSI: ! case OSC: ! case DCS: string_start = bytes; break; } ! #define ENTER_STRING_STATE(st) do { vt->parser_state = st; string_start = bytes + pos + 1; } while(0) ! #define ENTER_NORMAL_STATE() do { vt->parser_state = NORMAL; string_start = NULL; } while(0) for( ; pos < len; pos++) { unsigned char c = bytes[pos]; if(c == 0x00 || c == 0x7f) { /* NUL, DEL */ ! if(vt->parser_state != NORMAL) { ! append_strbuffer(vt, string_start, bytes + pos - string_start); string_start = bytes + pos + 1; } continue; --- 127,156 ---- size_t pos = 0; const char *string_start = NULL; /* init to avoid gcc warning */ ! switch(vt->parser.state) { case NORMAL: + case CSI_LEADER: + case CSI_ARGS: + case CSI_INTERMED: + case ESC: string_start = NULL; break; ! case STRING: ! case ESC_IN_STRING: string_start = bytes; break; } ! #define ENTER_STRING_STATE(st) 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]; if(c == 0x00 || c == 0x7f) { /* NUL, DEL */ ! if(vt->parser.state >= STRING) { ! more_string(vt, string_start, bytes + pos - string_start); string_start = bytes + pos + 1; } continue; *************** *** 224,287 **** continue; } else if(c == 0x1b) { /* ESC */ ! if(vt->parser_state == OSC) ! vt->parser_state = ESC_IN_OSC; ! else if(vt->parser_state == DCS) ! vt->parser_state = ESC_IN_DCS; else ! ENTER_STRING_STATE(ESC); continue; } else if(c == 0x07 && /* BEL, can stand for ST in OSC or DCS state */ ! (vt->parser_state == OSC || vt->parser_state == DCS)) { /* fallthrough */ } else if(c < 0x20) { /* other C0 */ ! if(vt->parser_state != NORMAL) ! append_strbuffer(vt, string_start, bytes + pos - string_start); do_control(vt, c); ! if(vt->parser_state != NORMAL) string_start = bytes + pos + 1; continue; } /* else fallthrough */ ! switch(vt->parser_state) { ! case ESC_IN_OSC: ! case ESC_IN_DCS: if(c == 0x5c) { /* ST */ ! switch(vt->parser_state) { ! case ESC_IN_OSC: vt->parser_state = OSC; break; ! case ESC_IN_DCS: vt->parser_state = DCS; break; ! default: break; ! } ! do_string(vt, string_start, bytes + pos - string_start - 1); ENTER_NORMAL_STATE(); break; } ! vt->parser_state = ESC; ! string_start = bytes + pos; /* else fallthrough */ case ESC: switch(c) { case 0x50: /* DCS */ ! ENTER_STRING_STATE(DCS); break; case 0x5b: /* CSI */ ! ENTER_STRING_STATE(CSI); break; case 0x5d: /* OSC */ ! ENTER_STRING_STATE(OSC); break; default: ! if(c >= 0x30 && c < 0x7f) { ! /* +1 to pos because we want to include this command byte as well */ ! do_string(vt, string_start, bytes + pos - string_start + 1); ENTER_NORMAL_STATE(); } ! else if(c >= 0x20 && c < 0x30) { ! /* intermediate byte */ } else { DEBUG_LOG1("TODO: Unhandled byte %02x in Escape\n", c); --- 160,223 ---- 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); continue; } else if(c == 0x07 && /* BEL, can stand for ST in OSC or DCS state */ ! vt->parser.state == STRING) { /* fallthrough */ } else if(c < 0x20) { /* other C0 */ ! if(vt->parser.state >= STRING) ! more_string(vt, string_start, bytes + pos - string_start); do_control(vt, c); ! if(vt->parser.state >= STRING) 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 */ 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); *************** *** 289,306 **** } break; ! case CSI: ! if(c >= 0x40 && c <= 0x7f) { ! /* +1 to pos because we want to include this command byte as well */ ! do_string(vt, string_start, bytes + pos - string_start + 1); ! ENTER_NORMAL_STATE(); } break; ! case OSC: ! case DCS: if(c == 0x07 || (c == 0x9c && !vt->mode.utf8)) { ! do_string(vt, string_start, bytes + pos - string_start); ENTER_NORMAL_STATE(); } break; --- 225,291 ---- } break; ! 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; ! break; ! } ! ! /* else fallthrough */ ! vt->parser.csi_leader[vt->parser.csi_leaderlen] = 0; ! ! vt->parser.csi_argi = 0; ! vt->parser.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'; ! break; } + if(c == ':') { + vt->parser.csi_args[vt->parser.csi_argi] |= CSI_ARG_FLAG_MORE; + c = ';'; + } + if(c == ';') { + vt->parser.csi_argi++; + vt->parser.csi_args[vt->parser.csi_argi] = CSI_ARG_MISSING; + break; + } + + /* else fallthrough */ + vt->parser.csi_argi++; + vt->parser.intermedlen = 0; + vt->parser.state = CSI_INTERMED; + /* fallthrough */ + 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 STRING: if(c == 0x07 || (c == 0x9c && !vt->mode.utf8)) { ! done_string(vt, string_start, bytes + pos - string_start); ENTER_NORMAL_STATE(); } break; *************** *** 309,321 **** if(c >= 0x80 && c < 0xa0 && !vt->mode.utf8) { switch(c) { case 0x90: /* DCS */ ! ENTER_STRING_STATE(DCS); break; case 0x9b: /* CSI */ ! ENTER_STRING_STATE(CSI); break; case 0x9d: /* OSC */ ! ENTER_STRING_STATE(OSC); break; default: do_control(vt, c); --- 294,308 ---- if(c >= 0x80 && c < 0xa0 && !vt->mode.utf8) { switch(c) { case 0x90: /* DCS */ ! start_string(vt, VTERM_PARSER_DCS); ! ENTER_STRING_STATE(); break; case 0x9b: /* CSI */ ! ENTER_STATE(CSI_LEADER); break; case 0x9d: /* OSC */ ! start_string(vt, VTERM_PARSER_OSC); ! ENTER_STRING_STATE(); break; default: do_control(vt, c); *************** *** 323,346 **** } } else { ! size_t text_eaten = do_string(vt, bytes + pos, len - pos); ! ! if(text_eaten == 0) { ! string_start = bytes + pos; ! goto pause; } ! pos += (text_eaten - 1); /* we'll ++ it again in a moment */ } break; } } - pause: - if(string_start && string_start < len + bytes) { - size_t remaining = len - (string_start - bytes); - append_strbuffer(vt, string_start, remaining); - } - return len; } --- 310,341 ---- } } 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; } } 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; + } *** ../vim-8.0.1638/src/libvterm/src/pen.c 2017-12-01 21:07:16.220989905 +0100 --- src/libvterm/src/pen.c 2018-03-25 14:54:41.690318409 +0200 *************** *** 507,512 **** --- 507,515 ---- case VTERM_ATTR_BACKGROUND: val->color = state->pen.bg; return 1; + + case VTERM_N_ATTRS: + return 0; } return 0; *** ../vim-8.0.1638/src/libvterm/src/screen.c 2017-09-05 23:29:29.025108125 +0200 --- src/libvterm/src/screen.c 2018-03-25 14:54:41.686318433 +0200 *************** *** 429,434 **** --- 429,437 ---- case VTERM_ATTR_BACKGROUND: screen->pen.bg = val->color; return 1; + + case VTERM_N_ATTRS: + return 0; } return 0; *** ../vim-8.0.1638/src/libvterm/src/state.c 2018-03-11 19:30:40.124142765 +0100 --- src/libvterm/src/state.c 2018-03-25 15:33:22.025090186 +0200 *************** *** 268,274 **** if(!npoints) { vterm_allocator_free(state->vt, codepoints); ! return 0; } if(state->gsingle_set && npoints) --- 268,274 ---- if(!npoints) { vterm_allocator_free(state->vt, codepoints); ! return eaten; } if(state->gsingle_set && npoints) *************** *** 781,786 **** --- 781,790 ---- VTERM_PROP_MOUSE_MOVE); break; + case 1004: + state->mode.report_focus = val; + break; + case 1005: state->mouse_protocol = val ? MOUSE_UTF8 : MOUSE_X10; break; *************** *** 861,866 **** --- 865,874 ---- reply = state->mouse_flags == (MOUSE_WANT_CLICK|MOUSE_WANT_MOVE); break; + case 1004: + reply = state->mode.report_focus; + break; + case 1005: reply = state->mouse_protocol == MOUSE_UTF8; break; *************** *** 1728,1733 **** --- 1736,1742 ---- state->mode.origin = 0; state->mode.leftrightmargin = 0; state->mode.bracketpaste = 0; + state->mode.report_focus = 0; state->vt->mode.ctrl8bit = 0; *************** *** 1882,1892 **** --- 1891,1916 ---- if(val->number == VTERM_PROP_MOUSE_MOVE) state->mouse_flags |= MOUSE_WANT_MOVE; return 1; + + case VTERM_N_PROPS: + return 0; } return 0; } + void vterm_state_focus_in(VTermState *state) + { + if(state->mode.report_focus) + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "I"); + } + + void vterm_state_focus_out(VTermState *state) + { + if(state->mode.report_focus) + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "O"); + } + const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row) { return state->lineinfo + row; *** ../vim-8.0.1638/src/libvterm/src/vterm.c 2018-02-24 14:03:49.748678084 +0100 --- src/libvterm/src/vterm.c 2018-03-25 15:33:57.116888731 +0200 *************** *** 47,60 **** vt->rows = rows; vt->cols = cols; ! vt->parser_state = NORMAL; ! vt->parser_callbacks = NULL; ! vt->cbdata = NULL; ! vt->strbuffer_len = 64; ! vt->strbuffer_cur = 0; ! vt->strbuffer = vterm_allocator_malloc(vt, vt->strbuffer_len); vt->outbuffer_len = 200; vt->outbuffer_cur = 0; --- 47,60 ---- vt->rows = rows; vt->cols = cols; ! vt->parser.state = NORMAL; ! vt->parser.callbacks = NULL; ! vt->parser.cbdata = NULL; ! vt->parser.strbuffer_len = 64; ! vt->parser.strbuffer_cur = 0; ! vt->parser.strbuffer = vterm_allocator_malloc(vt, vt->parser.strbuffer_len); vt->outbuffer_len = 200; vt->outbuffer_cur = 0; *************** *** 71,77 **** if(vt->state) vterm_state_free(vt->state); ! vterm_allocator_free(vt, vt->strbuffer); vterm_allocator_free(vt, vt->outbuffer); vterm_allocator_free(vt, vt); --- 71,77 ---- if(vt->state) vterm_state_free(vt->state); ! vterm_allocator_free(vt, vt->parser.strbuffer); vterm_allocator_free(vt, vt->outbuffer); vterm_allocator_free(vt, vt); *************** *** 100,107 **** vt->rows = rows; vt->cols = cols; ! if(vt->parser_callbacks && vt->parser_callbacks->resize) ! (*vt->parser_callbacks->resize)(rows, cols, vt->cbdata); } int vterm_get_utf8(const VTerm *vt) --- 100,107 ---- vt->rows = rows; vt->cols = cols; ! if(vt->parser.callbacks && vt->parser.callbacks->resize) ! (*vt->parser.callbacks->resize)(rows, cols, vt->parser.cbdata); } int vterm_get_utf8(const VTerm *vt) *************** *** 257,273 **** return len; } - void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user) - { - vt->parser_callbacks = callbacks; - vt->cbdata = user; - } - - void *vterm_parser_get_cbdata(VTerm *vt) - { - return vt->cbdata; - } - VTermValueType vterm_get_attr_type(VTermAttr attr) { switch(attr) { --- 257,262 ---- *************** *** 280,285 **** --- 269,276 ---- case VTERM_ATTR_FONT: return VTERM_VALUETYPE_INT; case VTERM_ATTR_FOREGROUND: return VTERM_VALUETYPE_COLOR; case VTERM_ATTR_BACKGROUND: return VTERM_VALUETYPE_COLOR; + + case VTERM_N_ATTRS: return 0; } return 0; /* UNREACHABLE */ } *************** *** 296,301 **** --- 287,294 ---- case VTERM_PROP_CURSORSHAPE: return VTERM_VALUETYPE_INT; case VTERM_PROP_MOUSE: return VTERM_VALUETYPE_INT; case VTERM_PROP_CURSORCOLOR: return VTERM_VALUETYPE_STRING; + + case VTERM_N_PROPS: return 0; } return 0; /* UNREACHABLE */ } *** ../vim-8.0.1638/src/libvterm/src/vterm_internal.h 2018-03-22 20:26:46.706263857 +0100 --- src/libvterm/src/vterm_internal.h 2018-03-25 15:35:30.664353360 +0200 *************** *** 27,32 **** --- 27,37 ---- #define ESC_S "\x1b" + #define INTERMED_MAX 16 + + #define CSI_ARGS_MAX 16 + #define CSI_LEADER_MAX 16 + typedef struct VTermEncoding VTermEncoding; typedef struct { *************** *** 118,123 **** --- 123,129 ---- unsigned int screen:1; unsigned int leftrightmargin:1; unsigned int bracketpaste:1; + unsigned int report_focus:1; } mode; VTermEncodingInstance encoding[4], encoding_utf8; *************** *** 148,153 **** --- 154,166 ---- } saved; }; + typedef enum { + VTERM_PARSER_OSC, + VTERM_PARSER_DCS, + + VTERM_N_PARSER_TYPES + } VTermParserStringType; + struct VTerm { VTermAllocatorFunctions *allocator; *************** *** 161,182 **** unsigned int ctrl8bit:1; } mode; ! enum VTermParserState { ! NORMAL, ! CSI, ! OSC, ! DCS, ! ESC, ! ESC_IN_OSC, ! ESC_IN_DCS ! } parser_state; ! const VTermParserCallbacks *parser_callbacks; ! void *cbdata; /* len == malloc()ed size; cur == number of valid bytes */ - char *strbuffer; - size_t strbuffer_len; - size_t strbuffer_cur; char *outbuffer; size_t outbuffer_len; --- 174,210 ---- unsigned int ctrl8bit:1; } mode; ! struct { ! enum VTermParserState { ! NORMAL, ! CSI_LEADER, ! CSI_ARGS, ! CSI_INTERMED, ! ESC, ! /* below here are the "string states" */ ! STRING, ! ESC_IN_STRING ! } state; ! ! int intermedlen; ! char intermed[INTERMED_MAX]; ! ! int csi_leaderlen; ! char csi_leader[CSI_LEADER_MAX]; ! ! int csi_argi; ! long csi_args[CSI_ARGS_MAX]; ! ! const VTermParserCallbacks *callbacks; ! void *cbdata; ! ! VTermParserStringType stringtype; ! char *strbuffer; ! size_t strbuffer_len; ! size_t strbuffer_cur; ! } parser; /* len == malloc()ed size; cur == number of valid bytes */ char *outbuffer; size_t outbuffer_len; *** ../vim-8.0.1638/src/libvterm/t/10state_putglyph.test 2017-07-07 11:53:29.523876467 +0200 --- src/libvterm/t/10state_putglyph.test 2018-03-25 14:54:41.670318525 +0200 *************** *** 17,22 **** --- 17,28 ---- putglyph 0xc1 1 0,0 putglyph 0xe9 1 0,1 + !UTF-8 split writes + RESET + PUSH "\xC3" + PUSH "\x81" + putglyph 0xc1 1 0,0 + !UTF-8 wide char # U+FF10 = 0xEF 0xBC 0x90 name: FULLWIDTH DIGIT ZERO RESET *** ../vim-8.0.1638/src/libvterm/t/25state_input.test 2017-07-07 11:53:29.523876467 +0200 --- src/libvterm/t/25state_input.test 2018-03-25 14:54:41.670318525 +0200 *************** *** 130,132 **** --- 130,143 ---- output "\e[200~" PASTE END output "\e[201~" + + !Focus reporting disabled + FOCUS IN + FOCUS OUT + + !Focus reporting enabled + PUSH "\e[?1004h" + FOCUS IN + output "\e[I" + FOCUS OUT + output "\e[O" *** ../vim-8.0.1638/src/libvterm/t/harness.c 2017-07-25 21:34:42.061132703 +0200 --- src/libvterm/t/harness.c 2018-03-25 15:36:08.652136578 +0200 *************** *** 233,238 **** --- 233,241 ---- case VTERM_VALUETYPE_COLOR: printf("settermprop %d rgb(%d,%d,%d)\n", prop, val->color.red, val->color.green, val->color.blue); return 1; + + case VTERM_N_VALUETYPES: + return 0; } return 0; *************** *** 316,321 **** --- 319,327 ---- case VTERM_ATTR_BACKGROUND: state_pen.background = val->color; break; + + case VTERM_N_ATTRS: + return 0; } return 1; *************** *** 650,655 **** --- 656,671 ---- else goto abort_line; } + + else if(strstartswith(line, "FOCUS ")) { + char *linep = line + 6; + if(streq(linep, "IN")) + vterm_state_focus_in(state); + else if(streq(linep, "OUT")) + vterm_state_focus_out(state); + else + goto abort_line; + } else if(strstartswith(line, "MOUSEMOVE ")) { char *linep = line + 10; *** ../vim-8.0.1638/src/libvterm/t/26state_query.test 2017-07-07 11:53:29.523876467 +0200 --- src/libvterm/t/26state_query.test 2018-03-25 16:14:58.151055521 +0200 *************** *** 58,62 **** PUSH "\e F" !Truncation on attempted buffer overflow ! PUSH "\e[6n" x 20 ! output "\e[10;10R" x 7 --- 58,62 ---- PUSH "\e F" !Truncation on attempted buffer overflow ! PUSH "\e[6n" x 30 ! output "\e[10;10R" x 24 *** ../vim-8.0.1638/src/version.c 2018-03-24 17:56:09.205107399 +0100 --- src/version.c 2018-03-25 15:50:04.035421169 +0200 *************** *** 768,769 **** --- 768,771 ---- { /* Add new patch number below this line */ + /**/ + 1639, /**/ -- ERROR 047: Keyboard not found. Press RETURN to continue. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///