To: vim_dev@googlegroups.com Subject: Patch 9.0.0774 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0774 Problem: The libvterm code is outdated. Solution: Include libvterm changes from revision 802 to 817. Revert some changes made for C89. Files: src/libvterm/README, src/libvterm/CONTRIBUTING, src/libvterm/Makefile, src/libvterm/doc/seqs.txt, src/libvterm/include/vterm.h, src/libvterm/src/encoding.c, src/libvterm/src/keyboard.c, src/libvterm/src/parser.c, src/libvterm/src/pen.c, src/libvterm/src/screen.c, src/libvterm/src/state.c, src/libvterm/src/unicode.c, src/libvterm/src/vterm.c, src/libvterm/src/vterm_internal.h, src/libvterm/t/harness.c, src/libvterm/t/10state_putglyph.test, src/libvterm/t/13state_edit.test, src/libvterm/t/26state_query.test, src/libvterm/t/30state_pen.test, src/libvterm/t/64screen_pen.test, src/libvterm/t/69screen_reflow.test, src/libvterm/t/run-test.pl, src/terminal.c *** ../vim-9.0.0773/src/libvterm/README 2022-10-16 14:35:41.840813752 +0100 --- src/libvterm/README 2022-10-16 18:20:18.898915023 +0100 *************** *** 7,14 **** https://github.com/neovim/libvterm Modifications: ! - Add a .gitignore file. ! - Convert some code from C99 to C90. - Other changes to support embedding in Vim. To get the latest version of libvterm you need the "bzr" command and do: --- 7,17 ---- https://github.com/neovim/libvterm Modifications: ! - revisions up to 817 have been included ! - Added a .gitignore file. ! - use TRUE and FALSE instead of true and false ! - use int or unsigned int instead of bool ! - Converted some code from C99 to C90. - Other changes to support embedding in Vim. To get the latest version of libvterm you need the "bzr" command and do: *** ../vim-9.0.0773/src/libvterm/CONTRIBUTING 2020-05-17 21:20:28.000000000 +0100 --- src/libvterm/CONTRIBUTING 2022-10-16 16:36:56.330870321 +0100 *************** *** 6,13 **** Launchpad https://launchpad.net/libvterm ! Freenode: ! ##tty or #tickit on irc.freenode.net Email: Paul "LeoNerd" Evans --- 6,13 ---- Launchpad https://launchpad.net/libvterm ! IRC: ! ##tty or #tickit on irc.libera.chat Email: Paul "LeoNerd" Evans *** ../vim-9.0.0773/src/libvterm/Makefile 2021-11-24 17:06:17.000000000 +0000 --- src/libvterm/Makefile 2022-10-16 17:55:10.159371324 +0100 *************** *** 37,43 **** HFILES_INT=$(sort $(wildcard src/*.h)) $(HFILES) VERSION_MAJOR=0 ! VERSION_MINOR=2 VERSION_CURRENT=0 VERSION_REVISION=0 --- 37,43 ---- HFILES_INT=$(sort $(wildcard src/*.h)) $(HFILES) VERSION_MAJOR=0 ! VERSION_MINOR=3 VERSION_CURRENT=0 VERSION_REVISION=0 *** ../vim-9.0.0773/src/libvterm/doc/seqs.txt 2022-10-16 14:35:41.840813752 +0100 --- src/libvterm/doc/seqs.txt 2022-10-16 17:56:53.415392912 +0100 *************** *** 122,127 **** --- 122,128 ---- 123x CSI l = RM, Reset mode 123x CSI ? l = DECRM, DEC reset mode 123x CSI m = SGR, Set Graphic Rendition + CSI ? m = DECSGR, private Set Graphic Rendition 123x CSI n = DSR, Device Status Report 23x 5 = operating status 23x 6 = CPR = cursor position *************** *** 198,203 **** --- 199,207 ---- x SGR 40-47 = Background ANSI x SGR 48 = Background alternative palette x SGR 49 = Background default + SGR 73 = Superscript on + SGR 74 = Subscript on + SGR 75 = Superscript/subscript off x SGR 90-97 = Foreground ANSI high-intensity x SGR 100-107 = Background ANSI high-intensity *** ../vim-9.0.0773/src/libvterm/include/vterm.h 2022-10-16 14:35:41.840813752 +0100 --- src/libvterm/include/vterm.h 2022-10-16 18:24:14.722785995 +0100 *************** *** 12,27 **** #include "vterm_keycodes.h" #define TRUE 1 #define FALSE 0 ! // from stdint.h typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #define VTERM_VERSION_MAJOR 0 ! #define VTERM_VERSION_MINOR 2 #define VTERM_CHECK_VERSION \ vterm_check_version(VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR) --- 12,28 ---- #include "vterm_keycodes.h" + // VIM: use TRUE and FALSE instead of true and false #define TRUE 1 #define FALSE 0 ! // VIM: from stdint.h typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #define VTERM_VERSION_MAJOR 0 ! #define VTERM_VERSION_MINOR 3 #define VTERM_CHECK_VERSION \ vterm_check_version(VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR) *************** *** 131,137 **** VTERM_COLOR_DEFAULT_MASK = 0x06, /** ! * If set, indicates that the color is invalid. */ VTERM_COLOR_INVALID = 0x08 } VTermColorType; --- 132,138 ---- VTERM_COLOR_DEFAULT_MASK = 0x06, /** ! * VIM: If set, indicates that the color is invalid. */ VTERM_COLOR_INVALID = 0x08 } VTermColorType; *************** *** 172,177 **** --- 173,179 ---- */ #define VTERM_COLOR_IS_INVALID(col) (!!((col)->type & VTERM_COLOR_INVALID)) + // VIM: this was a union, but that doesn't always work. typedef struct { /** * Tag indicating which member is actually valid. *************** *** 237,242 **** --- 239,246 ---- VTERM_ATTR_FONT, // number: 10-19 VTERM_ATTR_FOREGROUND, // color: 30-39 90-97 VTERM_ATTR_BACKGROUND, // color: 40-49 100-107 + VTERM_ATTR_SMALL, // bool: 73, 74, 75 + VTERM_ATTR_BASELINE, // number: 73, 74, 75 VTERM_N_ATTRS } VTermAttr; *************** *** 251,257 **** VTERM_PROP_REVERSE, // bool VTERM_PROP_CURSORSHAPE, // number VTERM_PROP_MOUSE, // number ! VTERM_PROP_CURSORCOLOR, // string VTERM_N_PROPS } VTermProp; --- 255,261 ---- VTERM_PROP_REVERSE, // bool VTERM_PROP_CURSORSHAPE, // number VTERM_PROP_MOUSE, // number ! VTERM_PROP_CURSORCOLOR, // VIM - string VTERM_N_PROPS } VTermProp; *************** *** 312,318 **** void (*free)(void *ptr, void *allocdata); } VTermAllocatorFunctions; - /* A convenient shortcut for default cases */ void vterm_check_version(int major, int minor); struct VTermBuilder { --- 316,321 ---- *************** *** 333,339 **** /* A convenient shortcut for default cases */ // Allocate and initialize a new terminal with default allocators. VTerm *vterm_new(int rows, int cols); - /* These shortcuts are generally discouraged in favour of just using vterm_build() */ // Allocate and initialize a new terminal with specified allocators. --- 336,341 ---- *************** *** 396,401 **** --- 398,404 ---- #define CSI_ARG(a) ((a) & CSI_ARG_MASK) /* Can't use -1 to indicate a missing argument; use this instead */ + // VIM: changed 31 to 30 to avoid an overflow warning #define CSI_ARG_MISSING ((1<<30)-1) #define CSI_ARG_IS_MISSING(a) (CSI_ARG(a) == CSI_ARG_MISSING) *************** *** 436,443 **** --- 439,448 ---- int (*bell)(void *user); int (*resize)(int rows, int cols, VTermStateFields *fields, void *user); int (*setlineinfo)(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user); + int (*sb_clear)(void *user); } VTermStateCallbacks; + // VIM: added typedef struct { VTermPos pos; int buttons; *************** *** 478,483 **** --- 483,489 ---- void vterm_state_reset(VTermState *state, int hard); void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos); + // VIM: added void vterm_state_get_mousestate(const VTermState *state, VTermMouseState *mousestate); void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg); void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col); *************** *** 522,527 **** --- 528,535 ---- unsigned int font : 4; /* 0 to 9 */ unsigned int dwl : 1; /* On a DECDWL or DECDHL line */ unsigned int dhl : 2; /* On a DECDHL line (1=top 2=bottom) */ + unsigned int small : 1; + unsigned int baseline : 2; } VTermScreenCellAttrs; enum { *************** *** 531,536 **** --- 539,550 ---- VTERM_UNDERLINE_CURLY, }; + enum { + VTERM_BASELINE_NORMAL, + VTERM_BASELINE_RAISE, + VTERM_BASELINE_LOWER, + }; + typedef struct { uint32_t chars[VTERM_MAX_CHARS_PER_CELL]; char width; *************** *** 551,556 **** --- 565,571 ---- // Return value is unused. int (*sb_pushline)(int cols, const VTermScreenCell *cells, void *user); int (*sb_popline)(int cols, VTermScreenCell *cells, void *user); + int (*sb_clear)(void* user); } VTermScreenCallbacks; // Return the screen of the vterm. *************** *** 566,571 **** --- 581,591 ---- void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermStateFallbacks *fallbacks, void *user); void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen); + void vterm_screen_enable_reflow(VTermScreen *screen, int reflow); + + // Back-compat alias for the brief time it was in 0.3-RC1 + #define vterm_screen_set_reflow vterm_screen_enable_reflow + // Enable support for using the alternate screen if "altscreen" is non-zero. // Before that switching to the alternate screen won't work. // Calling with "altscreen" zero has no effect. *************** *** 606,613 **** VTERM_ATTR_FOREGROUND_MASK = 1 << 7, VTERM_ATTR_BACKGROUND_MASK = 1 << 8, VTERM_ATTR_CONCEAL_MASK = 1 << 9, ! VTERM_ALL_ATTRS_MASK = (1 << 10) - 1 } VTermAttrMask; int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs); --- 626,635 ---- VTERM_ATTR_FOREGROUND_MASK = 1 << 7, VTERM_ATTR_BACKGROUND_MASK = 1 << 8, VTERM_ATTR_CONCEAL_MASK = 1 << 9, + VTERM_ATTR_SMALL_MASK = 1 << 10, + VTERM_ATTR_BASELINE_MASK = 1 << 11, ! VTERM_ALL_ATTRS_MASK = (1 << 12) - 1 } VTermAttrMask; int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs); *** ../vim-9.0.0773/src/libvterm/src/encoding.c 2020-05-22 20:14:56.000000000 +0100 --- src/libvterm/src/encoding.c 2022-10-16 18:28:08.364109247 +0100 *************** *** 49,54 **** --- 49,55 ---- if(data->bytes_remaining) { data->bytes_remaining = 0; cp[(*cpi)++] = UNICODE_INVALID; + // VIM: avoid going over the end if (*cpi >= cplen) break; } *************** *** 226,233 **** /* This ought to be INTERNAL but isn't because it's used by unit testing */ VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation) { ! int i; ! for(i = 0; encodings[i].designation; i++) if(encodings[i].type == type && encodings[i].designation == designation) return encodings[i].enc; return NULL; --- 227,233 ---- /* This ought to be INTERNAL but isn't because it's used by unit testing */ VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation) { ! for(int i = 0; encodings[i].designation; i++) if(encodings[i].type == type && encodings[i].designation == designation) return encodings[i].enc; return NULL; *** ../vim-9.0.0773/src/libvterm/src/keyboard.c 2020-05-22 20:19:33.000000000 +0100 --- src/libvterm/src/keyboard.c 2022-10-16 18:31:40.812946125 +0100 *************** *** 4,9 **** --- 4,10 ---- #include "utf8.h" + // VIM: added int vterm_is_modify_other_keys(VTerm *vt) { return vt->state->mode.modify_other_keys; *************** *** 12,19 **** void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod) { ! int needs_CSIu; ! if (vt->state->mode.modify_other_keys && mod != 0) { vterm_push_output_sprintf_ctrl(vt, C1_CSI, "27;%d;%d~", mod+1, c); return; --- 13,19 ---- void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod) { ! // VIM: added modifyOtherKeys support if (vt->state->mode.modify_other_keys && mod != 0) { vterm_push_output_sprintf_ctrl(vt, C1_CSI, "27;%d;%d~", mod+1, c); return; *************** *** 33,38 **** --- 33,39 ---- return; } + int needs_CSIu; switch(c) { /* Special Ctrl- letters that can't be represented elsewise */ case 'i': case 'j': case 'm': case '[': *************** *** 93,104 **** { KEYCODE_CSI_CURSOR, 'D', 0 }, // LEFT { KEYCODE_CSI_CURSOR, 'C', 0 }, // RIGHT ! { KEYCODE_CSINUM, '~', 2 }, // INS ! { KEYCODE_CSINUM, '~', 3 }, // DEL { KEYCODE_CSI_CURSOR, 'H', 0 }, // HOME { KEYCODE_CSI_CURSOR, 'F', 0 }, // END ! { KEYCODE_CSINUM, '~', 5 }, // PAGEUP ! { KEYCODE_CSINUM, '~', 6 }, // PAGEDOWN }; static keycodes_s keycodes_fn[] = { --- 94,105 ---- { KEYCODE_CSI_CURSOR, 'D', 0 }, // LEFT { KEYCODE_CSI_CURSOR, 'C', 0 }, // RIGHT ! { KEYCODE_CSINUM, '~', 2 }, // INS ! { KEYCODE_CSINUM, '~', 3 }, // DEL { KEYCODE_CSI_CURSOR, 'H', 0 }, // HOME { KEYCODE_CSI_CURSOR, 'F', 0 }, // END ! { KEYCODE_CSINUM, '~', 5 }, // PAGEUP ! { KEYCODE_CSINUM, '~', 6 }, // PAGEDOWN }; static keycodes_s keycodes_fn[] = { *************** *** 107,120 **** { KEYCODE_SS3, 'Q', 0 }, // F2 { KEYCODE_SS3, 'R', 0 }, // F3 { KEYCODE_SS3, 'S', 0 }, // F4 ! { KEYCODE_CSINUM, '~', 15 }, // F5 ! { KEYCODE_CSINUM, '~', 17 }, // F6 ! { KEYCODE_CSINUM, '~', 18 }, // F7 ! { KEYCODE_CSINUM, '~', 19 }, // F8 ! { KEYCODE_CSINUM, '~', 20 }, // F9 ! { KEYCODE_CSINUM, '~', 21 }, // F10 ! { KEYCODE_CSINUM, '~', 23 }, // F11 ! { KEYCODE_CSINUM, '~', 24 }, // F12 }; static keycodes_s keycodes_kp[] = { --- 108,121 ---- { KEYCODE_SS3, 'Q', 0 }, // F2 { KEYCODE_SS3, 'R', 0 }, // F3 { KEYCODE_SS3, 'S', 0 }, // F4 ! { KEYCODE_CSINUM, '~', 15 }, // F5 ! { KEYCODE_CSINUM, '~', 17 }, // F6 ! { KEYCODE_CSINUM, '~', 18 }, // F7 ! { KEYCODE_CSINUM, '~', 19 }, // F8 ! { KEYCODE_CSINUM, '~', 20 }, // F9 ! { KEYCODE_CSINUM, '~', 21 }, // F10 ! { KEYCODE_CSINUM, '~', 23 }, // F11 ! { KEYCODE_CSINUM, '~', 24 }, // F12 }; static keycodes_s keycodes_kp[] = { *************** *** 140,150 **** void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod) { - keycodes_s k; - if(key == VTERM_KEY_NONE) return; if(key < VTERM_KEY_FUNCTION_0) { if(key >= sizeof(keycodes)/sizeof(keycodes[0])) return; --- 141,150 ---- void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod) { if(key == VTERM_KEY_NONE) return; + keycodes_s k; if(key < VTERM_KEY_FUNCTION_0) { if(key >= sizeof(keycodes)/sizeof(keycodes[0])) return; *** ../vim-9.0.0773/src/libvterm/src/parser.c 2021-11-24 18:06:27.000000000 +0000 --- src/libvterm/src/parser.c 2022-10-16 18:34:14.953397598 +0100 *************** *** 142,148 **** 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(IS_STRING_STATE()) { --- 142,147 ---- *************** *** 187,193 **** } // else fallthrough ! 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 --- 186,192 ---- } // 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 *************** *** 247,253 **** vt->parser.v.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) --- 246,252 ---- vt->parser.v.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) *** ../vim-9.0.0773/src/libvterm/src/pen.c 2020-06-29 22:12:33.000000000 +0100 --- src/libvterm/src/pen.c 2022-10-16 18:37:49.997877703 +0100 *************** *** 44,49 **** --- 44,50 ---- static void lookup_default_colour_ansi(long idx, VTermColor *col) { + // VIM: store both RGB color and index vterm_color_rgb( col, ansi_colors[idx].red, ansi_colors[idx].green, ansi_colors[idx].blue); *************** *** 161,187 **** INTERNAL void vterm_state_newpen(VTermState *state) { - int col; - // 90% grey so that pure white is brighter vterm_color_rgb(&state->default_fg, 240, 240, 240); vterm_color_rgb(&state->default_bg, 0, 0, 0); vterm_state_set_default_colors(state, &state->default_fg, &state->default_bg); ! for(col = 0; col < 16; col++) lookup_default_colour_ansi(col, &state->colors[col]); } INTERNAL void vterm_state_resetpen(VTermState *state) { state->pen.bold = 0; setpenattr_bool(state, VTERM_ATTR_BOLD, 0); ! state->pen.underline = 0; setpenattr_int( state, VTERM_ATTR_UNDERLINE, 0); state->pen.italic = 0; setpenattr_bool(state, VTERM_ATTR_ITALIC, 0); state->pen.blink = 0; setpenattr_bool(state, VTERM_ATTR_BLINK, 0); state->pen.reverse = 0; setpenattr_bool(state, VTERM_ATTR_REVERSE, 0); state->pen.conceal = 0; setpenattr_bool(state, VTERM_ATTR_CONCEAL, 0); state->pen.strike = 0; setpenattr_bool(state, VTERM_ATTR_STRIKE, 0); ! state->pen.font = 0; setpenattr_int( state, VTERM_ATTR_FONT, 0); state->pen.fg = state->default_fg; setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->default_fg); state->pen.bg = state->default_bg; setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->default_bg); --- 162,188 ---- INTERNAL void vterm_state_newpen(VTermState *state) { // 90% grey so that pure white is brighter vterm_color_rgb(&state->default_fg, 240, 240, 240); vterm_color_rgb(&state->default_bg, 0, 0, 0); vterm_state_set_default_colors(state, &state->default_fg, &state->default_bg); ! for(int col = 0; col < 16; col++) lookup_default_colour_ansi(col, &state->colors[col]); } INTERNAL void vterm_state_resetpen(VTermState *state) { state->pen.bold = 0; setpenattr_bool(state, VTERM_ATTR_BOLD, 0); ! state->pen.underline = 0; setpenattr_int (state, VTERM_ATTR_UNDERLINE, 0); state->pen.italic = 0; setpenattr_bool(state, VTERM_ATTR_ITALIC, 0); state->pen.blink = 0; setpenattr_bool(state, VTERM_ATTR_BLINK, 0); state->pen.reverse = 0; setpenattr_bool(state, VTERM_ATTR_REVERSE, 0); state->pen.conceal = 0; setpenattr_bool(state, VTERM_ATTR_CONCEAL, 0); state->pen.strike = 0; setpenattr_bool(state, VTERM_ATTR_STRIKE, 0); ! state->pen.font = 0; setpenattr_int (state, VTERM_ATTR_FONT, 0); ! state->pen.small = 0; setpenattr_bool(state, VTERM_ATTR_SMALL, 0); ! state->pen.baseline = 0; setpenattr_int (state, VTERM_ATTR_BASELINE, 0); state->pen.fg = state->default_fg; setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->default_fg); state->pen.bg = state->default_bg; setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->default_bg); *************** *** 195,208 **** else { state->pen = state->saved.pen; ! setpenattr_bool(state, VTERM_ATTR_BOLD, state->pen.bold); ! setpenattr_int( state, VTERM_ATTR_UNDERLINE, state->pen.underline); ! setpenattr_bool(state, VTERM_ATTR_ITALIC, state->pen.italic); ! setpenattr_bool(state, VTERM_ATTR_BLINK, state->pen.blink); ! setpenattr_bool(state, VTERM_ATTR_REVERSE, state->pen.reverse); ! setpenattr_bool(state, VTERM_ATTR_CONCEAL, state->pen.conceal); ! setpenattr_bool(state, VTERM_ATTR_STRIKE, state->pen.strike); ! setpenattr_int( state, VTERM_ATTR_FONT, state->pen.font); setpenattr_col( state, VTERM_ATTR_FOREGROUND, state->pen.fg); setpenattr_col( state, VTERM_ATTR_BACKGROUND, state->pen.bg); } --- 196,212 ---- else { state->pen = state->saved.pen; ! setpenattr_bool(state, VTERM_ATTR_BOLD, state->pen.bold); ! setpenattr_int (state, VTERM_ATTR_UNDERLINE, state->pen.underline); ! setpenattr_bool(state, VTERM_ATTR_ITALIC, state->pen.italic); ! setpenattr_bool(state, VTERM_ATTR_BLINK, state->pen.blink); ! setpenattr_bool(state, VTERM_ATTR_REVERSE, state->pen.reverse); ! setpenattr_bool(state, VTERM_ATTR_CONCEAL, state->pen.conceal); ! setpenattr_bool(state, VTERM_ATTR_STRIKE, state->pen.strike); ! setpenattr_int (state, VTERM_ATTR_FONT, state->pen.font); ! setpenattr_bool(state, VTERM_ATTR_SMALL, state->pen.small); ! setpenattr_int (state, VTERM_ATTR_BASELINE, state->pen.baseline); ! setpenattr_col( state, VTERM_ATTR_FOREGROUND, state->pen.fg); setpenattr_col( state, VTERM_ATTR_BACKGROUND, state->pen.bg); } *************** *** 447,452 **** --- 451,468 ---- setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg); break; + case 73: // Superscript + case 74: // Subscript + case 75: // Superscript/subscript off + state->pen.small = (arg != 75); + state->pen.baseline = + (arg == 73) ? VTERM_BASELINE_RAISE : + (arg == 74) ? VTERM_BASELINE_LOWER : + VTERM_BASELINE_NORMAL; + setpenattr_bool(state, VTERM_ATTR_SMALL, state->pen.small); + setpenattr_int (state, VTERM_ATTR_BASELINE, state->pen.baseline); + break; + case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97: // Foreground colour high-intensity palette value = CSI_ARG(args[argi]) - 90 + 8; *************** *** 544,549 **** --- 560,572 ---- argi = vterm_state_getpen_color(&state->pen.bg, argi, args, FALSE); + if(state->pen.small) { + if(state->pen.baseline == VTERM_BASELINE_RAISE) + args[argi++] = 73; + else if(state->pen.baseline == VTERM_BASELINE_LOWER) + args[argi++] = 74; + } + return argi; } *************** *** 590,595 **** --- 613,626 ---- val->color = state->pen.bg; return 1; + case VTERM_ATTR_SMALL: + val->boolean = state->pen.small; + return 1; + + case VTERM_ATTR_BASELINE: + val->number = state->pen.baseline; + return 1; + case VTERM_N_ATTRS: return 0; } *** ../vim-9.0.0773/src/libvterm/src/screen.c 2022-10-16 14:35:41.840813752 +0100 --- src/libvterm/src/screen.c 2022-10-16 18:58:01.835223223 +0100 *************** *** 10,15 **** --- 10,17 ---- #define UNICODE_SPACE 0x20 #define UNICODE_LINEFEED 0x0a + #undef DEBUG_REFLOW + /* State of the pen at some moment in time, also used in a cell */ typedef struct { *************** *** 24,29 **** --- 26,33 ---- unsigned int conceal : 1; unsigned int strike : 1; unsigned int font : 4; /* 0 to 9 */ + unsigned int small : 1; + unsigned int baseline : 2; /* Extra state storage that isn't strictly pen-related */ unsigned int protected_cell : 1; *************** *** 54,60 **** int rows; int cols; ! int global_reverse; /* Primary and Altscreen. buffers[1] is lazily allocated as needed */ ScreenCell *buffers[2]; --- 58,66 ---- int rows; int cols; ! ! unsigned int global_reverse : 1; ! unsigned int reflow : 1; /* Primary and Altscreen. buffers[1] is lazily allocated as needed */ ScreenCell *buffers[2]; *************** *** 88,98 **** static ScreenCell *alloc_buffer(VTermScreen *screen, int rows, int cols) { ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * rows * cols); - int row; - int col; ! for(row = 0; row < rows; row++) { ! for(col = 0; col < cols; col++) { clearcell(screen, &new_buffer[row * cols + col]); } } --- 94,102 ---- static ScreenCell *alloc_buffer(VTermScreen *screen, int rows, int cols) { ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * rows * cols); ! for(int row = 0; row < rows; row++) { ! for(int col = 0; col < cols; col++) { clearcell(screen, &new_buffer[row * cols + col]); } } *************** *** 168,183 **** static int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user) { - int i; - int col; - VTermRect rect; - VTermScreen *screen = user; ScreenCell *cell = getcell(screen, pos.row, pos.col); if(!cell) return 0; for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) { cell->chars[i] = info->chars[i]; cell->pen = screen->pen; --- 172,184 ---- static int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user) { VTermScreen *screen = user; ScreenCell *cell = getcell(screen, pos.row, pos.col); if(!cell) return 0; + int i; for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) { cell->chars[i] = info->chars[i]; cell->pen = screen->pen; *************** *** 185,191 **** if(i < VTERM_MAX_CHARS_PER_CELL) cell->chars[i] = 0; ! for(col = 1; col < info->width; col++) { ScreenCell *onecell = getcell(screen, pos.row, pos.col + col); if (onecell == NULL) --- 186,192 ---- if(i < VTERM_MAX_CHARS_PER_CELL) cell->chars[i] = 0; ! for(int col = 1; col < info->width; col++) { ScreenCell *onecell = getcell(screen, pos.row, pos.col + col); if (onecell == NULL) *************** *** 193,198 **** --- 194,200 ---- onecell->chars[0] = (uint32_t)-1; } + VTermRect rect; rect.start_row = pos.row; rect.end_row = pos.row+1; rect.start_col = pos.col; *************** *** 225,257 **** dest.start_row == 0 && dest.start_col == 0 && // starts top-left corner dest.end_col == screen->cols && // full width screen->buffer == screen->buffers[BUFIDX_PRIMARY]) { // not altscreen ! int row; ! for(row = 0; row < src.start_row; row++) sb_pushline_from_row(screen, row); } ! { ! int cols = src.end_col - src.start_col; ! int downward = src.start_row - dest.start_row; ! int init_row, test_row, inc_row; ! int row; ! ! if(downward < 0) { ! init_row = dest.end_row - 1; ! test_row = dest.start_row - 1; ! inc_row = -1; ! } ! else { ! init_row = dest.start_row; ! test_row = dest.end_row; ! inc_row = +1; ! } ! for(row = init_row; row != test_row; row += inc_row) ! memmove(getcell(screen, row, dest.start_col), ! getcell(screen, row + downward, src.start_col), ! cols * sizeof(ScreenCell)); } return 1; } --- 227,255 ---- dest.start_row == 0 && dest.start_col == 0 && // starts top-left corner dest.end_col == screen->cols && // full width screen->buffer == screen->buffers[BUFIDX_PRIMARY]) { // not altscreen ! for(int row = 0; row < src.start_row; row++) sb_pushline_from_row(screen, row); } ! int cols = src.end_col - src.start_col; ! int downward = src.start_row - dest.start_row; ! int init_row, test_row, inc_row; ! if(downward < 0) { ! init_row = dest.end_row - 1; ! test_row = dest.start_row - 1; ! inc_row = -1; } + else { + init_row = dest.start_row; + test_row = dest.end_row; + inc_row = +1; + } + + for(int row = init_row; row != test_row; row += inc_row) + memmove(getcell(screen, row, dest.start_col), + getcell(screen, row + downward, src.start_col), + cols * sizeof(ScreenCell)); return 1; } *************** *** 277,288 **** static int erase_internal(VTermRect rect, int selective, void *user) { VTermScreen *screen = user; - int row, col; ! for(row = rect.start_row; row < screen->state->rows && row < rect.end_row; row++) { const VTermLineInfo *info = vterm_state_get_lineinfo(screen->state, row); ! for(col = rect.start_col; col < rect.end_col; col++) { ScreenCell *cell = getcell(screen, row, col); if (cell == NULL) --- 275,285 ---- static int erase_internal(VTermRect rect, int selective, void *user) { VTermScreen *screen = user; ! for(int row = rect.start_row; row < screen->state->rows && row < rect.end_row; row++) { const VTermLineInfo *info = vterm_state_get_lineinfo(screen->state, row); ! for(int col = rect.start_col; col < rect.end_col; col++) { ScreenCell *cell = getcell(screen, row, col); if (cell == NULL) *************** *** 448,453 **** --- 445,456 ---- case VTERM_ATTR_BACKGROUND: screen->pen.bg = val->color; return 1; + case VTERM_ATTR_SMALL: + screen->pen.small = val->boolean; + return 1; + case VTERM_ATTR_BASELINE: + screen->pen.baseline = val->number; + return 1; case VTERM_N_ATTRS: return 0; *************** *** 496,501 **** --- 499,516 ---- return 0; } + /* How many cells are non-blank + * Returns the position of the first blank cell in the trailing blank end */ + static int line_popcount(ScreenCell *buffer, int row, int rows UNUSED, int cols) + { + int col = cols - 1; + while(col >= 0 && buffer[row * cols + col].chars[0] == 0) + col--; + return col + 1; + } + + #define REFLOW (screen->reflow) + static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new_cols, int active, VTermStateFields *statefields) { int old_rows = screen->rows; *************** *** 510,542 **** // Find the final row of old buffer content int old_row = old_rows - 1; int new_row = new_rows - 1; - int col; ! while(new_row >= 0 && old_row >= 0) { ! for(col = 0; col < old_cols && col < new_cols; col++) ! new_buffer[new_row * new_cols + col] = old_buffer[old_row * old_cols + col]; ! for( ; col < new_cols; col++) ! clearcell(screen, &new_buffer[new_row * new_cols + col]); ! ! new_lineinfo[new_row] = old_lineinfo[old_row]; ! ! old_row--; ! new_row--; ! ! if(new_row < 0 && old_row >= 0 && ! new_buffer[(new_rows - 1) * new_cols].chars[0] == 0 && ! (!active || statefields->pos.row < (new_rows - 1))) { ! int moverows = new_rows - 1; ! memmove(&new_buffer[1 * new_cols], &new_buffer[0], moverows * new_cols * sizeof(ScreenCell)); ! new_row++; } } if(old_row >= 0 && bufidx == BUFIDX_PRIMARY) { /* Push spare lines to scrollback buffer */ ! int row; ! for(row = 0; row <= old_row; row++) sb_pushline_from_row(screen, row); if(active) statefields->pos.row -= (old_row + 1); --- 525,674 ---- // Find the final row of old buffer content int old_row = old_rows - 1; int new_row = new_rows - 1; ! VTermPos old_cursor = statefields->pos; ! VTermPos new_cursor = { -1, -1 }; ! ! #ifdef DEBUG_REFLOW ! fprintf(stderr, "Resizing from %dx%d to %dx%d; cursor was at (%d,%d)\n", ! old_cols, old_rows, new_cols, new_rows, old_cursor.col, old_cursor.row); ! #endif ! ! /* Keep track of the final row that is knonw to be blank, so we know what ! * spare space we have for scrolling into ! */ ! int final_blank_row = new_rows; ! ! while(old_row >= 0) { ! int old_row_end = old_row; ! /* TODO: Stop if dwl or dhl */ ! while(REFLOW && old_lineinfo && old_row >= 0 && old_lineinfo[old_row].continuation) ! old_row--; ! int old_row_start = old_row; ! ! int width = 0; ! for(int row = old_row_start; row <= old_row_end; row++) { ! if(REFLOW && row < (old_rows - 1) && old_lineinfo[row + 1].continuation) ! width += old_cols; ! else ! width += line_popcount(old_buffer, row, old_rows, old_cols); ! } ! ! if(final_blank_row == (new_row + 1) && width == 0) ! final_blank_row = new_row; ! ! int new_height = REFLOW ! ? width ? (width + new_cols - 1) / new_cols : 1 ! : 1; ! ! int new_row_end = new_row; ! int new_row_start = new_row - new_height + 1; ! ! old_row = old_row_start; ! int old_col = 0; ! ! int spare_rows = new_rows - final_blank_row; ! ! if(new_row_start < 0 && /* we'd fall off the top */ ! spare_rows >= 0 && /* we actually have spare rows */ ! (!active || new_cursor.row == -1 || (new_cursor.row - new_row_start) < new_rows)) ! { ! /* Attempt to scroll content down into the blank rows at the bottom to ! * make it fit ! */ ! int downwards = -new_row_start; ! if(downwards > spare_rows) ! downwards = spare_rows; ! int rowcount = new_rows - downwards; ! ! #ifdef DEBUG_REFLOW ! fprintf(stderr, " scroll %d rows +%d downwards\n", rowcount, downwards); ! #endif ! ! memmove(&new_buffer[downwards * new_cols], &new_buffer[0], rowcount * new_cols * sizeof(ScreenCell)); ! memmove(&new_lineinfo[downwards], &new_lineinfo[0], rowcount * sizeof(new_lineinfo[0])); ! ! new_row += downwards; ! new_row_start += downwards; ! new_row_end += downwards; ! ! if(new_cursor.row >= 0) ! new_cursor.row += downwards; ! ! final_blank_row += downwards; ! } ! ! #ifdef DEBUG_REFLOW ! fprintf(stderr, " rows [%d..%d] <- [%d..%d] width=%d\n", ! new_row_start, new_row_end, old_row_start, old_row_end, width); ! #endif ! ! if(new_row_start < 0) ! break; ! ! for(new_row = new_row_start, old_row = old_row_start; new_row <= new_row_end; new_row++) { ! int count = width >= new_cols ? new_cols : width; ! width -= count; ! ! int new_col = 0; ! ! while(count) { ! /* TODO: This could surely be done a lot faster by memcpy()'ing the entire range */ ! new_buffer[new_row * new_cols + new_col] = old_buffer[old_row * old_cols + old_col]; ! ! if(old_cursor.row == old_row && old_cursor.col == old_col) ! new_cursor.row = new_row, new_cursor.col = new_col; ! ! old_col++; ! if(old_col == old_cols) { ! old_row++; ! ! if(!REFLOW) { ! new_col++; ! break; ! } ! old_col = 0; ! } ! ! new_col++; ! count--; ! } ! ! if(old_cursor.row == old_row && old_cursor.col >= old_col) { ! new_cursor.row = new_row, new_cursor.col = (old_cursor.col - old_col + new_col); ! if(new_cursor.col >= new_cols) ! new_cursor.col = new_cols-1; ! } ! while(new_col < new_cols) { ! clearcell(screen, &new_buffer[new_row * new_cols + new_col]); ! new_col++; ! } ! ! new_lineinfo[new_row].continuation = (new_row > new_row_start); } + + old_row = old_row_start - 1; + new_row = new_row_start - 1; + } + + if(old_cursor.row <= old_row) { + /* cursor would have moved entirely off the top of the screen; lets just + * bring it within range */ + new_cursor.row = 0, new_cursor.col = old_cursor.col; + if(new_cursor.col >= new_cols) + new_cursor.col = new_cols-1; + } + + /* We really expect the cursor position to be set by now */ + if(active && (new_cursor.row == -1 || new_cursor.col == -1)) { + fprintf(stderr, "screen_resize failed to update cursor position\n"); + abort(); } if(old_row >= 0 && bufidx == BUFIDX_PRIMARY) { /* Push spare lines to scrollback buffer */ ! for(int row = 0; row <= old_row; row++) sb_pushline_from_row(screen, row); if(active) statefields->pos.row -= (old_row + 1); *************** *** 553,561 **** for(pos.col = 0; pos.col < old_cols && pos.col < new_cols; pos.col += screen->sb_buffer[pos.col].width) { VTermScreenCell *src = &screen->sb_buffer[pos.col]; ScreenCell *dst = &new_buffer[pos.row * new_cols + pos.col]; - int i; ! for(i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { dst->chars[i] = src->chars[i]; if(!src->chars[i]) break; --- 685,692 ---- for(pos.col = 0; pos.col < old_cols && pos.col < new_cols; pos.col += screen->sb_buffer[pos.col].width) { VTermScreenCell *src = &screen->sb_buffer[pos.col]; ScreenCell *dst = &new_buffer[pos.row * new_cols + pos.col]; ! for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { dst->chars[i] = src->chars[i]; if(!src->chars[i]) break; *************** *** 569,574 **** --- 700,707 ---- dst->pen.conceal = src->attrs.conceal; dst->pen.strike = src->attrs.strike; dst->pen.font = src->attrs.font; + dst->pen.small = src->attrs.small; + dst->pen.baseline = src->attrs.baseline; dst->pen.fg = src->fg; dst->pen.bg = src->bg; *************** *** 584,598 **** statefields->pos.row++; } } - if(new_row >= 0) { /* Scroll new rows back up to the top and fill in blanks at the bottom */ int moverows = new_rows - new_row - 1; memmove(&new_buffer[0], &new_buffer[(new_row + 1) * new_cols], moverows * new_cols * sizeof(ScreenCell)); memmove(&new_lineinfo[0], &new_lineinfo[new_row + 1], moverows * sizeof(new_lineinfo[0])); for(new_row = moverows; new_row < new_rows; new_row++) { ! for(col = 0; col < new_cols; col++) clearcell(screen, &new_buffer[new_row * new_cols + col]); new_lineinfo[new_row] = (VTermLineInfo){ 0 }; } --- 717,732 ---- statefields->pos.row++; } } if(new_row >= 0) { /* Scroll new rows back up to the top and fill in blanks at the bottom */ int moverows = new_rows - new_row - 1; memmove(&new_buffer[0], &new_buffer[(new_row + 1) * new_cols], moverows * new_cols * sizeof(ScreenCell)); memmove(&new_lineinfo[0], &new_lineinfo[new_row + 1], moverows * sizeof(new_lineinfo[0])); + new_cursor.row -= (new_row + 1); + for(new_row = moverows; new_row < new_rows; new_row++) { ! for(int col = 0; col < new_cols; col++) clearcell(screen, &new_buffer[new_row * new_cols + col]); new_lineinfo[new_row] = (VTermLineInfo){ 0 }; } *************** *** 604,614 **** vterm_allocator_free(screen->vt, old_lineinfo); statefields->lineinfos[bufidx] = new_lineinfo; ! return; ! /* REFLOW TODO: ! * Handle delta. Probably needs to be a full cursorpos that we edit ! */ } static int resize(int new_rows, int new_cols, VTermStateFields *fields, void *user) --- 738,747 ---- vterm_allocator_free(screen->vt, old_lineinfo); statefields->lineinfos[bufidx] = new_lineinfo; ! if(active) ! statefields->pos = new_cursor; ! return; } static int resize(int new_rows, int new_cols, VTermStateFields *fields, void *user) *************** *** 667,678 **** static int setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user) { VTermScreen *screen = user; - int col; - VTermRect rect; if(newinfo->doublewidth != oldinfo->doublewidth || newinfo->doubleheight != oldinfo->doubleheight) { ! for(col = 0; col < screen->cols; col++) { ScreenCell *cell = getcell(screen, row, col); if (cell == NULL) { --- 800,809 ---- static int setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user) { VTermScreen *screen = user; if(newinfo->doublewidth != oldinfo->doublewidth || newinfo->doubleheight != oldinfo->doubleheight) { ! for(int col = 0; col < screen->cols; col++) { ScreenCell *cell = getcell(screen, row, col); if (cell == NULL) { *************** *** 684,689 **** --- 815,821 ---- cell->pen.dhl = newinfo->doubleheight; } + VTermRect rect; rect.start_row = row; rect.end_row = row + 1; rect.start_col = 0; *************** *** 701,706 **** --- 833,848 ---- return 1; } + static int sb_clear(void *user) { + VTermScreen *screen = user; + + if(screen->callbacks && screen->callbacks->sb_clear) + if((*screen->callbacks->sb_clear)(screen->cbdata)) + return 1; + + return 0; + } + static VTermStateCallbacks state_cbs = { &putglyph, // putglyph &movecursor, // movecursor *************** *** 712,718 **** &settermprop, // settermprop &bell, // bell &resize, // resize ! &setlineinfo // setlineinfo }; /* --- 854,861 ---- &settermprop, // settermprop &bell, // bell &resize, // resize ! &setlineinfo, // setlineinfo ! &sb_clear, //sb_clear }; /* *************** *** 722,735 **** static VTermScreen *screen_new(VTerm *vt) { VTermState *state = vterm_obtain_state(vt); ! VTermScreen *screen; ! int rows, cols; ! ! if (state == NULL) return NULL; ! screen = vterm_allocator_malloc(vt, sizeof(VTermScreen)); if (screen == NULL) return NULL; vterm_get_size(vt, &rows, &cols); --- 865,877 ---- static VTermScreen *screen_new(VTerm *vt) { VTermState *state = vterm_obtain_state(vt); ! if(!state) return NULL; ! ! VTermScreen *screen = vterm_allocator_malloc(vt, sizeof(VTermScreen)); if (screen == NULL) return NULL; + int rows, cols; vterm_get_size(vt, &rows, &cols); *************** *** 743,748 **** --- 885,893 ---- screen->rows = rows; screen->cols = cols; + screen->global_reverse = FALSE; + screen->reflow = FALSE; + screen->callbacks = NULL; screen->cbdata = NULL; *************** *** 785,791 **** { size_t outpos = 0; int padding = 0; - int row, col; #define PUT(c) \ if(utf8) { \ --- 930,935 ---- *************** *** 802,811 **** outpos++; \ } ! for(row = rect.start_row; row < rect.end_row; row++) { ! for(col = rect.start_col; col < rect.end_col; col++) { ScreenCell *cell = getcell(screen, row, col); - int i; if (cell == NULL) { --- 946,954 ---- outpos++; \ } ! for(int row = rect.start_row; row < rect.end_row; row++) { ! for(int col = rect.start_col; col < rect.end_col; col++) { ScreenCell *cell = getcell(screen, row, col); if (cell == NULL) { *************** *** 824,830 **** PUT(UNICODE_SPACE); padding--; } ! for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) { PUT(cell->chars[i]); } } --- 967,973 ---- PUT(UNICODE_SPACE); padding--; } ! for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) { PUT(cell->chars[i]); } } *************** *** 853,864 **** int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell) { ScreenCell *intcell = getcell(screen, pos.row, pos.col); - int i; if(!intcell) return 0; ! for(i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { cell->chars[i] = intcell->chars[i]; if(!intcell->chars[i]) break; --- 996,1006 ---- int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell) { ScreenCell *intcell = getcell(screen, pos.row, pos.col); if(!intcell) return 0; ! for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { cell->chars[i] = intcell->chars[i]; if(!intcell->chars[i]) break; *************** *** 872,877 **** --- 1014,1021 ---- cell->attrs.conceal = intcell->pen.conceal; cell->attrs.strike = intcell->pen.strike; cell->attrs.font = intcell->pen.font; + cell->attrs.small = intcell->pen.small; + cell->attrs.baseline = intcell->pen.baseline; cell->attrs.dwl = intcell->pen.dwl; cell->attrs.dhl = intcell->pen.dhl; *************** *** 919,929 **** VTermScreen *vterm_obtain_screen(VTerm *vt) { ! if(!vt->screen) ! vt->screen = screen_new(vt); return vt->screen; } void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen) { if(!screen->buffers[BUFIDX_ALTSCREEN] && altscreen) { --- 1063,1087 ---- VTermScreen *vterm_obtain_screen(VTerm *vt) { ! if(vt->screen) ! return vt->screen; ! ! vt->screen = screen_new(vt); return vt->screen; } + void vterm_screen_enable_reflow(VTermScreen *screen, int reflow) + { + screen->reflow = reflow; + } + + // Removed, causes a compiler warning and isn't used + // #undef vterm_screen_set_reflow + // void vterm_screen_set_reflow(VTermScreen *screen, int reflow) + // { + // vterm_screen_enable_reflow(screen, reflow); + // } + void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen) { if(!screen->buffers[BUFIDX_ALTSCREEN] && altscreen) { *************** *** 1000,1013 **** return 1; if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_is_equal(&a->pen.bg, &b->pen.bg)) return 1; return 0; } int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs) { - int col; - ScreenCell *target = getcell(screen, pos.row, pos.col); // TODO: bounds check --- 1158,1173 ---- return 1; if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_is_equal(&a->pen.bg, &b->pen.bg)) return 1; + if((attrs & VTERM_ATTR_SMALL_MASK) && (a->pen.small != b->pen.small)) + return 1; + if((attrs & VTERM_ATTR_BASELINE_MASK) && (a->pen.baseline != b->pen.baseline)) + return 1; return 0; } int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs) { ScreenCell *target = getcell(screen, pos.row, pos.col); // TODO: bounds check *************** *** 1019,1024 **** --- 1179,1186 ---- if(extent->end_col < 0) extent->end_col = screen->cols; + int col; + for(col = pos.col - 1; col >= extent->start_col; col--) if(attrs_differ(attrs, target, getcell(screen, pos.row, col))) break; *** ../vim-9.0.0773/src/libvterm/src/state.c 2022-10-16 14:35:41.840813752 +0100 --- src/libvterm/src/state.c 2022-10-16 19:07:43.515621165 +0100 *************** *** 387,395 **** } #endif if (i == glyph_starts || this_width > width) ! width = this_width; } chars[glyph_ends - glyph_starts] = 0; i--; --- 387,398 ---- } #endif if (i == glyph_starts || this_width > width) ! width = this_width; // TODO: should be += ? } + while(i < npoints && vterm_unicode_is_combining(codepoints[i])) + i++; + chars[glyph_ends - glyph_starts] = 0; i--; *************** *** 1149,1154 **** --- 1152,1163 ---- set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); erase(state, rect, selective); break; + + case 3: + if(state->callbacks && state->callbacks->sb_clear) + if((*state->callbacks->sb_clear)(state->cbdata)) + return 1; + break; } break; *************** *** 1391,1396 **** --- 1400,1428 ---- vterm_state_setpen(state, args, argcount); break; + case LEADER('?', 0x6d): // DECSGR + /* No actual DEC terminal recognised these, but some printers did. These + * are alternative ways to request subscript/superscript/off + */ + for(int argi = 0; argi < argcount; argi++) { + long arg; + switch(arg = CSI_ARG(args[argi])) { + case 4: // Superscript on + arg = 73; + vterm_state_setpen(state, &arg, 1); + break; + case 5: // Subscript on + arg = 74; + vterm_state_setpen(state, &arg, 1); + break; + case 24: // Super+subscript off + arg = 75; + vterm_state_setpen(state, &arg, 1); + break; + } + } + break; + case LEADER('>', 0x6d): // xterm resource modifyOtherKeys if (argcount == 2 && args[0] == 4) state->mode.modify_other_keys = args[1] == 2; *************** *** 1857,1867 **** VTerm *vt = state->vt; char *tmp = state->tmp.decrqss; - size_t i = 0; if(frag.initial) tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; while(i < sizeof(state->tmp.decrqss)-1 && tmp[i]) i++; while(i < sizeof(state->tmp.decrqss)-1 && frag.len--) --- 1889,1899 ---- VTerm *vt = state->vt; char *tmp = state->tmp.decrqss; if(frag.initial) tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; + size_t i = 0; while(i < sizeof(state->tmp.decrqss)-1 && tmp[i]) i++; while(i < sizeof(state->tmp.decrqss)-1 && frag.len--) *************** *** 1877,1890 **** long args[20]; int argc = vterm_state_getpen(state, args, sizeof(args)/sizeof(args[0])); size_t cur = 0; - int argi; cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, vt->mode.ctrl8bit ? "\x90" "1$r" : ESC_S "P" "1$r"); // DCS 1$r ... if(cur >= vt->tmpbuffer_len) return; ! for(argi = 0; argi < argc; argi++) { cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, argi == argc - 1 ? "%ld" : CSI_ARG_HAS_MORE(args[argi]) ? "%ld:" : --- 1909,1921 ---- long args[20]; int argc = vterm_state_getpen(state, args, sizeof(args)/sizeof(args[0])); size_t cur = 0; cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, vt->mode.ctrl8bit ? "\x90" "1$r" : ESC_S "P" "1$r"); // DCS 1$r ... if(cur >= vt->tmpbuffer_len) return; ! for(int argi = 0; argi < argc; argi++) { cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, argi == argc - 1 ? "%ld" : CSI_ARG_HAS_MORE(args[argi]) ? "%ld:" : *************** *** 1996,2010 **** { VTermState *state = user; VTermPos oldpos = state->pos; - VTermStateFields fields; if(cols != state->cols) { - int col; unsigned char *newtabstops = vterm_allocator_malloc(state->vt, (cols + 7) / 8); if (newtabstops == NULL) return 0; /* TODO: This can all be done much more efficiently bytewise */ for(col = 0; col < state->cols && col < cols; col++) { unsigned char mask = 1 << (col & 7); if(state->tabstops[col >> 3] & mask) --- 2027,2040 ---- { VTermState *state = user; VTermPos oldpos = state->pos; if(cols != state->cols) { unsigned char *newtabstops = vterm_allocator_malloc(state->vt, (cols + 7) / 8); if (newtabstops == NULL) return 0; /* TODO: This can all be done much more efficiently bytewise */ + int col; for(col = 0; col < state->cols && col < cols; col++) { unsigned char mask = 1 << (col & 7); if(state->tabstops[col >> 3] & mask) *************** *** 2033,2045 **** if(state->scrollregion_right > -1) UBOUND(state->scrollregion_right, state->cols); fields.pos = state->pos; fields.lineinfos[0] = state->lineinfos[0]; fields.lineinfos[1] = state->lineinfos[1]; if(state->callbacks && state->callbacks->resize) { (*state->callbacks->resize)(rows, cols, &fields, state->cbdata); - state->pos = fields.pos; state->lineinfos[0] = fields.lineinfos[0]; --- 2063,2075 ---- if(state->scrollregion_right > -1) UBOUND(state->scrollregion_right, state->cols); + VTermStateFields fields; fields.pos = state->pos; fields.lineinfos[0] = state->lineinfos[0]; fields.lineinfos[1] = state->lineinfos[1]; if(state->callbacks && state->callbacks->resize) { (*state->callbacks->resize)(rows, cols, &fields, state->cbdata); state->pos = fields.pos; state->lineinfos[0] = fields.lineinfos[0]; *************** *** 2111,2121 **** */ VTermState *vterm_obtain_state(VTerm *vt) { - VTermState *state; if(vt->state) return vt->state; ! state = vterm_state_new(vt); if (state == NULL) return NULL; vt->state = state; --- 2141,2150 ---- */ VTermState *vterm_obtain_state(VTerm *vt) { if(vt->state) return vt->state; ! VTermState *state = vterm_state_new(vt); if (state == NULL) return NULL; vt->state = state; *************** *** 2127,2134 **** void vterm_state_reset(VTermState *state, int hard) { - VTermEncoding *default_enc; - state->scrollregion_top = 0; state->scrollregion_bottom = -1; state->scrollregion_left = 0; --- 2156,2161 ---- *************** *** 2149,2185 **** state->vt->mode.ctrl8bit = 0; ! { ! int col; ! for(col = 0; col < state->cols; col++) ! if(col % 8 == 0) ! set_col_tabstop(state, col); ! else ! clear_col_tabstop(state, col); ! } ! { ! int row; ! for(row = 0; row < state->rows; row++) ! set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); ! } if(state->callbacks && state->callbacks->initpen) (*state->callbacks->initpen)(state->cbdata); vterm_state_resetpen(state); ! default_enc = state->vt->mode.utf8 ? vterm_lookup_encoding(ENC_UTF8, 'u') : vterm_lookup_encoding(ENC_SINGLE_94, 'B'); ! { ! int i; ! for(i = 0; i < 4; i++) { ! state->encoding[i].enc = default_enc; ! if(default_enc->init) ! (*default_enc->init)(default_enc, state->encoding[i].data); ! } } state->gl_set = 0; --- 2176,2203 ---- state->vt->mode.ctrl8bit = 0; ! for(int col = 0; col < state->cols; col++) ! if(col % 8 == 0) ! set_col_tabstop(state, col); ! else ! clear_col_tabstop(state, col); ! for(int row = 0; row < state->rows; row++) ! set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); if(state->callbacks && state->callbacks->initpen) (*state->callbacks->initpen)(state->cbdata); vterm_state_resetpen(state); ! VTermEncoding *default_enc = state->vt->mode.utf8 ? vterm_lookup_encoding(ENC_UTF8, 'u') : vterm_lookup_encoding(ENC_SINGLE_94, 'B'); ! for(int i = 0; i < 4; i++) { ! state->encoding[i].enc = default_enc; ! if(default_enc->init) ! (*default_enc->init)(default_enc, state->encoding[i].data); } state->gl_set = 0; *************** *** 2194,2205 **** settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BLOCK); if(hard) { - VTermRect rect = { 0, 0, 0, 0 }; - state->pos.row = 0; state->pos.col = 0; state->at_phantom = 0; rect.end_row = state->rows; rect.end_col = state->cols; erase(state, rect, 0); --- 2212,2222 ---- settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BLOCK); if(hard) { state->pos.row = 0; state->pos.col = 0; state->at_phantom = 0; + VTermRect rect = { 0, 0, 0, 0 }; rect.end_row = state->rows; rect.end_col = state->cols; erase(state, rect, 0); *** ../vim-9.0.0773/src/libvterm/src/unicode.c 2020-05-22 20:50:28.000000000 +0100 --- src/libvterm/src/unicode.c 2022-10-16 18:12:20.047158323 +0100 *************** *** 452,471 **** } #endif ! #if 0 // unused ! static int mk_wcswidth(const uint32_t *pwcs, size_t n) ! { ! int w, width = 0; ! ! for (;*pwcs && n-- > 0; pwcs++) ! if ((w = mk_wcwidth(*pwcs)) < 0) ! return -1; ! else ! width += w; ! ! return width; ! } /* * The following functions are the same as mk_wcwidth() and --- 452,515 ---- } #endif ! /* sorted list of non-overlapping intervals of East Asian Ambiguous ! * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */ ! static const struct interval ambiguous[] = { ! { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 }, ! { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 }, ! { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 }, ! { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 }, ! { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED }, ! { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA }, ! { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 }, ! { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B }, ! { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 }, ! { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 }, ! { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 }, ! { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE }, ! { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 }, ! { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA }, ! { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 }, ! { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB }, ! { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB }, ! { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 }, ! { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 }, ! { 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 }, ! { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 }, ! { 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 }, ! { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 }, ! { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 }, ! { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC }, ! { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 }, ! { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 }, ! { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 }, ! { 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 }, ! { 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 }, ! { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 }, ! { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B }, ! { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 }, ! { 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 }, ! { 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E }, ! { 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 }, ! { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 }, ! { 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F }, ! { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 }, ! { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF }, ! { 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B }, ! { 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 }, ! { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 }, ! { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 }, ! { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 }, ! { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 }, ! { 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 }, ! { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 }, ! { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 }, ! { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F }, ! { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF }, ! { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD } ! }; + #ifdef USE_MK_WCWIDTH_CJK /* * The following functions are the same as mk_wcwidth() and *************** *** 478,542 **** */ static int mk_wcwidth_cjk(uint32_t ucs) { - #endif - /* sorted list of non-overlapping intervals of East Asian Ambiguous - * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */ - static const struct interval ambiguous[] = { - { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 }, - { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 }, - { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 }, - { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 }, - { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED }, - { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA }, - { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 }, - { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B }, - { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 }, - { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 }, - { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 }, - { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE }, - { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 }, - { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA }, - { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 }, - { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB }, - { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB }, - { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 }, - { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 }, - { 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 }, - { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 }, - { 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 }, - { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 }, - { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 }, - { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC }, - { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 }, - { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 }, - { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 }, - { 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 }, - { 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 }, - { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 }, - { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B }, - { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 }, - { 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 }, - { 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E }, - { 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 }, - { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 }, - { 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F }, - { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 }, - { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF }, - { 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B }, - { 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 }, - { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 }, - { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 }, - { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 }, - { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 }, - { 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 }, - { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 }, - { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 }, - { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F }, - { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF }, - { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD } - }; - #if 0 - /* binary search in table of non-spacing characters */ if (bisearch(ucs, ambiguous, sizeof(ambiguous) / sizeof(struct interval) - 1)) --- 522,527 ---- *************** *** 545,563 **** return mk_wcwidth(ucs); } - - static int mk_wcswidth_cjk(const uint32_t *pwcs, size_t n) - { - int w, width = 0; - - for (;*pwcs && n-- > 0; pwcs++) - if ((w = mk_wcwidth_cjk(*pwcs)) < 0) - return -1; - else - width += w; - - return width; - } #endif INTERNAL int vterm_unicode_is_ambiguous(uint32_t codepoint) --- 530,535 ---- *** ../vim-9.0.0773/src/libvterm/src/vterm.c 2022-10-16 14:35:41.840813752 +0100 --- src/libvterm/src/vterm.c 2022-10-16 19:14:38.139885762 +0100 *************** *** 134,139 **** --- 134,142 ---- void vterm_set_size(VTerm *vt, int rows, int cols) { + if(rows < 1 || cols < 1) + return; + vt->rows = rows; vt->cols = cols; *************** *** 201,207 **** INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...) { size_t cur; - va_list args; if(ctrl >= 0x80 && !vt->mode.ctrl8bit) cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, --- 204,209 ---- *************** *** 213,218 **** --- 215,221 ---- return; vterm_push_output_bytes(vt, vt->tmpbuffer, cur); + va_list args; va_start(args, fmt); vterm_push_output_vsprintf(vt, fmt, args); va_end(args); *************** *** 221,227 **** INTERNAL void vterm_push_output_sprintf_str(VTerm *vt, unsigned char ctrl, int term, const char *fmt, ...) { size_t cur; - va_list args; if(ctrl) { if(ctrl >= 0x80 && !vt->mode.ctrl8bit) --- 224,229 ---- *************** *** 236,241 **** --- 238,244 ---- vterm_push_output_bytes(vt, vt->tmpbuffer, cur); } + va_list args; va_start(args, fmt); vterm_push_output_vsprintf(vt, fmt, args); va_end(args); *************** *** 292,297 **** --- 295,302 ---- 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_ATTR_SMALL: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_BASELINE: return VTERM_VALUETYPE_INT; case VTERM_N_ATTRS: return 0; } *************** *** 396,403 **** int init_row, test_row, init_col, test_col; int inc_row, inc_col; - VTermPos pos; - if(downward < 0) { init_row = dest.end_row - 1; test_row = dest.start_row - 1; --- 401,406 ---- *************** *** 420,425 **** --- 423,429 ---- inc_col = +1; } + VTermPos pos; for(pos.row = init_row; pos.row != test_row; pos.row += inc_row) for(pos.col = init_col; pos.col != test_col; pos.col += inc_col) { VTermPos srcpos; *** ../vim-9.0.0773/src/libvterm/src/vterm_internal.h 2022-10-16 14:35:41.840813752 +0100 --- src/libvterm/src/vterm_internal.h 2022-10-16 16:56:13.194822674 +0100 *************** *** 60,65 **** --- 60,67 ---- unsigned int conceal:1; unsigned int strike:1; unsigned int font:4; /* To store 0-9 */ + unsigned int small:1; + unsigned int baseline:2; }; struct VTermState *** ../vim-9.0.0773/src/libvterm/t/harness.c 2022-10-16 14:35:41.840813752 +0100 --- src/libvterm/t/harness.c 2022-10-16 18:00:30.459392805 +0100 *************** *** 1,6 **** --- 1,7 ---- #include "vterm.h" #include "../src/vterm_internal.h" // We pull in some internal bits too + #include #include #include *************** *** 409,414 **** --- 410,417 ---- int conceal; int strike; int font; + int small; + int baseline; VTermColor foreground; VTermColor background; } state_pen; *************** *** 439,444 **** --- 442,453 ---- case VTERM_ATTR_FONT: state_pen.font = val->number; break; + case VTERM_ATTR_SMALL: + state_pen.small = val->boolean; + break; + case VTERM_ATTR_BASELINE: + state_pen.baseline = val->number; + break; case VTERM_ATTR_FOREGROUND: state_pen.foreground = val->color; break; *************** *** 458,463 **** --- 467,481 ---- return 1; } + static int want_state_scrollback = 0; + static int state_sb_clear(void *user UNUSED) { + if(!want_state_scrollback) + return 1; + + printf("sb_clear\n"); + return 0; + } + VTermStateCallbacks state_cbs = { state_putglyph, // putglyph movecursor, // movecursor *************** *** 470,475 **** --- 488,494 ---- NULL, // bell NULL, // resize state_setlineinfo, // setlineinfo + state_sb_clear, // sb_clear }; static int selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user UNUSED) *************** *** 592,597 **** --- 611,625 ---- return 1; } + static int screen_sb_clear(void *user UNUSED) + { + if(!want_screen_scrollback) + return 1; + + printf("sb_clear\n"); + return 0; + } + VTermScreenCallbacks screen_cbs = { screen_damage, // damage moverect, // moverect *************** *** 600,606 **** NULL, // bell NULL, // resize screen_sb_pushline, // sb_pushline ! screen_sb_popline // sb_popline }; int main(int argc UNUSED, char **argv UNUSED) --- 628,635 ---- NULL, // bell NULL, // resize screen_sb_pushline, // sb_pushline ! screen_sb_popline, // sb_popline ! screen_sb_clear, // sb_clear }; int main(int argc UNUSED, char **argv UNUSED) *************** *** 629,640 **** --- 658,671 ---- } else if(streq(line, "WANTPARSER")) { + assert(vt); vterm_parser_set_callbacks(vt, &parser_cbs, NULL); } else if(strstartswith(line, "WANTSTATE") && (line[9] == '\0' || line[9] == ' ')) { int i = 9; int sense = 1; + assert(vt); if(!state) { state = vterm_obtain_state(vt); vterm_state_set_callbacks(state, &state_cbs, NULL); *************** *** 671,676 **** --- 702,710 ---- case 'f': vterm_state_set_unrecognised_fallbacks(state, sense ? &fallbacks : NULL, NULL); break; + case 'b': + want_state_scrollback = sense; + break; default: fprintf(stderr, "Unrecognised WANTSTATE flag '%c'\n", line[i]); } *************** *** 679,684 **** --- 713,719 ---- else if(strstartswith(line, "WANTSCREEN") && (line[10] == '\0' || line[10] == ' ')) { int i = 10; int sense = 1; + assert(vt); if(!screen) screen = vterm_obtain_screen(vt); vterm_screen_set_callbacks(screen, &screen_cbs, NULL); *************** *** 712,717 **** --- 747,755 ---- case 'b': want_screen_scrollback = sense; break; + case 'r': + vterm_screen_enable_reflow(screen, sense); + break; default: fprintf(stderr, "Unrecognised WANTSCREEN flag '%c'\n", line[i]); } *************** *** 743,748 **** --- 781,788 ---- else if(strstartswith(line, "PUSH ")) { char *bytes = line + 5; size_t len = inplace_hex2bytes(bytes); + assert(len); + size_t written = vterm_input_write(vt, bytes, len); if(written < len) fprintf(stderr, "! short write\n"); *************** *** 759,764 **** --- 799,805 ---- else if(strstartswith(line, "ENCIN ")) { char *bytes = line + 6; size_t len = inplace_hex2bytes(bytes); + assert(len); uint32_t cp[1024]; int cpi = 0; *************** *** 814,819 **** --- 855,861 ---- } else if(strstartswith(line, "FOCUS ")) { + assert(state); char *linep = line + 6; if(streq(linep, "IN")) vterm_state_focus_in(state); *************** *** 869,874 **** --- 911,918 ---- } frag.len = inplace_hex2bytes(linep); frag.str = linep; + assert(frag.len); + linep += frag.len * 2; while(linep[0] == ' ') linep++; *************** *** 879,884 **** --- 923,929 ---- } else if(strstartswith(line, "DAMAGEMERGE ")) { + assert(screen); char *linep = line + 12; while(linep[0] == ' ') linep++; *************** *** 893,903 **** --- 938,950 ---- } else if(strstartswith(line, "DAMAGEFLUSH")) { + assert(screen); vterm_screen_flush_damage(screen); } else if(line[0] == '?') { if(streq(line, "?cursor")) { + assert(state); VTermPos pos; vterm_state_get_cursorpos(state, &pos); if(pos.row != state_pos.row) *************** *** 910,915 **** --- 957,963 ---- printf("%d,%d\n", state_pos.row, state_pos.col); } else if(strstartswith(line, "?pen ")) { + assert(state); VTermValue val; char *linep = line + 5; while(linep[0] == ' ') *************** *** 965,970 **** --- 1013,1036 ---- else printf("%d\n", state_pen.font); } + else if(streq(linep, "small")) { + vterm_state_get_penattr(state, VTERM_ATTR_SMALL, &val); + if(val.boolean != state_pen.small) + printf("! pen small mismatch; state=%s, event=%s\n", + BOOLSTR(val.boolean), BOOLSTR(state_pen.small)); + else + printf("%s\n", BOOLSTR(state_pen.small)); + } + else if(streq(linep, "baseline")) { + vterm_state_get_penattr(state, VTERM_ATTR_BASELINE, &val); + if(val.number != state_pen.baseline) + printf("! pen baseline mismatch: state=%d, event=%d\n", + val.number, state_pen.baseline); + else + printf("%s\n", state_pen.baseline == VTERM_BASELINE_RAISE ? "raise" + : state_pen.baseline == VTERM_BASELINE_LOWER ? "lower" + : "normal"); + } else if(streq(linep, "foreground")) { print_color(&state_pen.foreground); printf("\n"); *************** *** 977,982 **** --- 1043,1049 ---- printf("?\n"); } else if(strstartswith(line, "?lineinfo ")) { + assert(state); char *linep = line + 10; int row; const VTermLineInfo *info; *************** *** 996,1001 **** --- 1063,1069 ---- printf("\n"); } else if(strstartswith(line, "?screen_chars ")) { + assert(screen); char *linep = line + 13; VTermRect rect; size_t len; *************** *** 1028,1033 **** --- 1096,1102 ---- } } else if(strstartswith(line, "?screen_text ")) { + assert(screen); char *linep = line + 12; VTermRect rect; size_t len; *************** *** 1067,1072 **** --- 1136,1142 ---- } } else if(strstartswith(line, "?screen_cell ")) { + assert(screen); char *linep = line + 12; int i; VTermPos pos; *************** *** 1090,1095 **** --- 1160,1169 ---- if(cell.attrs.blink) printf("K"); if(cell.attrs.reverse) printf("R"); if(cell.attrs.font) printf("F%d", cell.attrs.font); + if(cell.attrs.small) printf("S"); + if(cell.attrs.baseline) printf( + cell.attrs.baseline == VTERM_BASELINE_RAISE ? "^" : + "_"); printf("} "); if(cell.attrs.dwl) printf("dwl "); if(cell.attrs.dhl) printf("dhl-%s ", cell.attrs.dhl == 2 ? "bottom" : "top"); *************** *** 1102,1107 **** --- 1176,1182 ---- printf("\n"); } else if(strstartswith(line, "?screen_eol ")) { + assert(screen); VTermPos pos; char *linep = line + 12; while(linep[0] == ' ') *************** *** 1113,1118 **** --- 1188,1194 ---- printf("%d\n", vterm_screen_is_eol(screen, pos)); } else if(strstartswith(line, "?screen_attrs_extent ")) { + assert(screen); VTermPos pos; VTermRect rect; char *linep = line + 21; *** ../vim-9.0.0773/src/libvterm/t/10state_putglyph.test 2020-05-17 14:50:36.000000000 +0100 --- src/libvterm/t/10state_putglyph.test 2022-10-16 17:43:03.887560542 +0100 *************** *** 52,57 **** --- 52,63 ---- putglyph 0x65,0x301 1 0,0 putglyph 0x5a 1 0,1 + !Spare combining chars get truncated + RESET + PUSH "e" . "\xCC\x81" x 10 + putglyph 0x65,0x301,0x301,0x301,0x301,0x301 1 0,0 + # and nothing more + RESET PUSH "e" putglyph 0x65 1 0,0 *** ../vim-9.0.0773/src/libvterm/t/13state_edit.test 2017-06-24 15:44:02.000000000 +0100 --- src/libvterm/t/13state_edit.test 2022-10-16 16:31:27.283019951 +0100 *************** *** 1,6 **** INIT UTF8 1 ! WANTSTATE se !ICH RESET --- 1,6 ---- INIT UTF8 1 ! WANTSTATE seb !ICH RESET *************** *** 242,247 **** --- 242,251 ---- erase 0..25,0..80 ?cursor = 1,1 + !ED 3 + PUSH "\e[3J" + sb_clear + !SED RESET erase 0..25,0..80 *** ../vim-9.0.0773/src/libvterm/t/26state_query.test 2022-10-16 14:35:41.844813763 +0100 --- src/libvterm/t/26state_query.test 2022-10-16 17:56:08.831385596 +0100 *************** *** 9,15 **** !XTVERSION RESET PUSH "\e[>q" ! output "\eP>|libvterm(0.2)\e\\" !DSR RESET --- 9,15 ---- !XTVERSION RESET PUSH "\e[>q" ! output "\eP>|libvterm(0.3)\e\\" !DSR RESET *** ../vim-9.0.0773/src/libvterm/t/30state_pen.test 2020-05-20 19:47:52.000000000 +0100 --- src/libvterm/t/30state_pen.test 2022-10-16 16:56:46.410816452 +0100 *************** *** 112,114 **** --- 112,125 ---- PUSH "\e[m\e[37;1m" ?pen bold = on ?pen foreground = idx(15) + + !Super/Subscript + PUSH "\e[73m" + ?pen small = on + ?pen baseline = raise + PUSH "\e[74m" + ?pen small = on + ?pen baseline = lower + PUSH "\e[75m" + ?pen small = off + ?pen baseline = normal *** ../vim-9.0.0773/src/libvterm/t/64screen_pen.test 2020-05-21 18:36:24.000000000 +0100 --- src/libvterm/t/64screen_pen.test 2022-10-16 16:47:29.926848023 +0100 *************** *** 35,40 **** --- 35,46 ---- PUSH "\e[42mH\e[m" ?screen_cell 0,7 = {0x48} width=1 attrs={} fg=rgb(240,240,240) bg=idx(2) + !Super/subscript + PUSH "x\e[74m0\e[73m2\e[m" + ?screen_cell 0,8 = {0x78} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) + ?screen_cell 0,9 = {0x30} width=1 attrs={S_} fg=rgb(240,240,240) bg=rgb(0,0,0) + ?screen_cell 0,10 = {0x32} width=1 attrs={S^} fg=rgb(240,240,240) bg=rgb(0,0,0) + !EL sets reverse and colours to end of line PUSH "\e[H\e[7;33;44m\e[K" ?screen_cell 0,0 = {} width=1 attrs={R} fg=idx(3) bg=idx(4) *** ../vim-9.0.0773/src/libvterm/t/69screen_reflow.test 2022-10-16 19:25:58.364308066 +0100 --- src/libvterm/t/69screen_reflow.test 2022-10-16 17:49:57.943197373 +0100 *************** *** 0 **** --- 1,79 ---- + INIT + # Run these tests on a much smaller default screen, so debug output is + # nowhere near as noisy + RESIZE 5,10 + WANTSTATE + WANTSCREEN r + RESET + + !Resize wider reflows wide lines + RESET + PUSH "A"x12 + ?screen_row 0 = "AAAAAAAAAA" + ?screen_row 1 = "AA" + ?lineinfo 1 = cont + ?cursor = 1,2 + RESIZE 5,15 + ?screen_row 0 = "AAAAAAAAAAAA" + ?screen_row 1 = + ?lineinfo 1 = + ?cursor = 0,12 + RESIZE 5,20 + ?screen_row 0 = "AAAAAAAAAAAA" + ?screen_row 1 = + ?lineinfo 1 = + ?cursor = 0,12 + + !Resize narrower can create continuation lines + RESET + RESIZE 5,10 + PUSH "ABCDEFGHI" + ?screen_row 0 = "ABCDEFGHI" + ?screen_row 1 = "" + ?lineinfo 1 = + ?cursor = 0,9 + RESIZE 5,8 + ?screen_row 0 = "ABCDEFGH" + ?screen_row 1 = "I" + ?lineinfo 1 = cont + ?cursor = 1,1 + RESIZE 5,6 + ?screen_row 0 = "ABCDEF" + ?screen_row 1 = "GHI" + ?lineinfo 1 = cont + ?cursor = 1,3 + + !Shell wrapped prompt behaviour + RESET + RESIZE 5,10 + PUSH "PROMPT GOES HERE\r\n> \r\n\r\nPROMPT GOES HERE\r\n> " + ?screen_row 0 = "> " + ?screen_row 1 = "" + ?screen_row 2 = "PROMPT GOE" + ?screen_row 3 = "S HERE" + ?lineinfo 3 = cont + ?screen_row 4 = "> " + ?cursor = 4,2 + RESIZE 5,11 + ?screen_row 0 = "> " + ?screen_row 1 = "" + ?screen_row 2 = "PROMPT GOES" + ?screen_row 3 = " HERE" + ?lineinfo 3 = cont + ?screen_row 4 = "> " + ?cursor = 4,2 + RESIZE 5,12 + ?screen_row 0 = "> " + ?screen_row 1 = "" + ?screen_row 2 = "PROMPT GOES " + ?screen_row 3 = "HERE" + ?lineinfo 3 = cont + ?screen_row 4 = "> " + ?cursor = 4,2 + RESIZE 5,16 + ?screen_row 0 = "> " + ?screen_row 1 = "" + ?screen_row 2 = "PROMPT GOES HERE" + ?lineinfo 3 = + ?screen_row 3 = "> " + ?cursor = 3,2 *** ../vim-9.0.0773/src/libvterm/t/run-test.pl 2022-10-16 14:35:41.840813752 +0100 --- src/libvterm/t/run-test.pl 2022-10-16 16:37:48.162846316 +0100 *************** *** 124,130 **** 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|selection-query) / ) { # no conversion } elsif( $line =~ m/^(selection-set) (.*?) (\[?)(.*?)(\]?)$/ ) { --- 124,130 ---- 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|sb_clear|settermprop|setmousefunc|selection-query) ?/ ) { # no conversion } elsif( $line =~ m/^(selection-set) (.*?) (\[?)(.*?)(\]?)$/ ) { *** ../vim-9.0.0773/src/terminal.c 2022-10-15 11:47:54.217416750 +0100 --- src/terminal.c 2022-10-16 16:34:44.094931092 +0100 *************** *** 3447,3453 **** handle_bell, // bell handle_resize, // resize handle_pushline, // sb_pushline ! NULL // sb_popline }; /* --- 3447,3454 ---- handle_bell, // bell handle_resize, // resize handle_pushline, // sb_pushline ! NULL, // sb_popline ! NULL // sb_clear }; /* *** ../vim-9.0.0773/src/version.c 2022-10-16 14:53:30.981598163 +0100 --- src/version.c 2022-10-16 19:23:36.680220701 +0100 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 774, /**/ -- If an elephant is left tied to a parking meter, the parking fee has to be paid just as it would for a vehicle. [real standing law in Florida, United States of America] /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///