# HG changeset patch # User Bram Moolenaar # Date 1665945007 -7200 # Node ID 82336c3b679d620c142a1392e7d2e275c25bfb44 # Parent 2db86b9d26dfa13df111a622573fa853677cf028 patch 9.0.0774: the libvterm code is outdated Commit: https://github.com/vim/vim/commit/6a12d26f3404e45ce25cf9152857e355b28f392a Author: Bram Moolenaar Date: Sun Oct 16 19:26:52 2022 +0100 patch 9.0.0774: the libvterm code is outdated Problem: The libvterm code is outdated. Solution: Include libvterm changes from revision 802 to 817. Revert some changes made for C89. diff --git a/src/libvterm/CONTRIBUTING b/src/libvterm/CONTRIBUTING --- a/src/libvterm/CONTRIBUTING +++ b/src/libvterm/CONTRIBUTING @@ -6,8 +6,8 @@ The main resources for this library are: Launchpad https://launchpad.net/libvterm - Freenode: - ##tty or #tickit on irc.freenode.net + IRC: + ##tty or #tickit on irc.libera.chat Email: Paul "LeoNerd" Evans diff --git a/src/libvterm/Makefile b/src/libvterm/Makefile --- a/src/libvterm/Makefile +++ b/src/libvterm/Makefile @@ -37,7 +37,7 @@ INCFILES=$(TBLFILES:.tbl=.inc) HFILES_INT=$(sort $(wildcard src/*.h)) $(HFILES) VERSION_MAJOR=0 -VERSION_MINOR=2 +VERSION_MINOR=3 VERSION_CURRENT=0 VERSION_REVISION=0 diff --git a/src/libvterm/README b/src/libvterm/README --- a/src/libvterm/README +++ b/src/libvterm/README @@ -7,8 +7,11 @@ The original can be found: https://github.com/neovim/libvterm Modifications: -- Add a .gitignore file. -- Convert some code from C99 to C90. +- 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: diff --git a/src/libvterm/doc/seqs.txt b/src/libvterm/doc/seqs.txt --- a/src/libvterm/doc/seqs.txt +++ b/src/libvterm/doc/seqs.txt @@ -122,6 +122,7 @@ 123x CSI ? h = DECSM, DEC set 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,6 +199,9 @@ 123x SGR 7 = Reverse on 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 diff --git a/src/libvterm/include/vterm.h b/src/libvterm/include/vterm.h --- a/src/libvterm/include/vterm.h +++ b/src/libvterm/include/vterm.h @@ -12,16 +12,17 @@ extern "C" { #include "vterm_keycodes.h" +// VIM: use TRUE and FALSE instead of true and false #define TRUE 1 #define FALSE 0 -// from stdint.h +// 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 2 +#define VTERM_VERSION_MINOR 3 #define VTERM_CHECK_VERSION \ vterm_check_version(VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR) @@ -131,7 +132,7 @@ typedef enum { VTERM_COLOR_DEFAULT_MASK = 0x06, /** - * If set, indicates that the color is invalid. + * VIM: If set, indicates that the color is invalid. */ VTERM_COLOR_INVALID = 0x08 } VTermColorType; @@ -172,6 +173,7 @@ typedef enum { */ #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,6 +239,8 @@ typedef enum { 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,7 +255,7 @@ typedef enum { VTERM_PROP_REVERSE, // bool VTERM_PROP_CURSORSHAPE, // number VTERM_PROP_MOUSE, // number - VTERM_PROP_CURSORCOLOR, // string + VTERM_PROP_CURSORCOLOR, // VIM - string VTERM_N_PROPS } VTermProp; @@ -312,7 +316,6 @@ typedef struct { void (*free)(void *ptr, void *allocdata); } VTermAllocatorFunctions; -/* A convenient shortcut for default cases */ void vterm_check_version(int major, int minor); struct VTermBuilder { @@ -333,7 +336,6 @@ VTerm *vterm_build(const struct VTermBui /* 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. @@ -396,6 +398,7 @@ void vterm_mouse_button(VTerm *vt, int b #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,8 +439,10 @@ typedef struct { 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,6 +483,7 @@ void *vterm_state_get_unrecognised_fbdat 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,6 +528,8 @@ typedef struct { 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,6 +539,12 @@ enum { 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,6 +565,7 @@ typedef struct { // 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,6 +581,11 @@ void *vterm_screen_get_cbdata(VTermScree 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,8 +626,10 @@ typedef enum { 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 << 10) - 1 + VTERM_ALL_ATTRS_MASK = (1 << 12) - 1 } VTermAttrMask; int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs); diff --git a/src/libvterm/src/encoding.c b/src/libvterm/src/encoding.c --- a/src/libvterm/src/encoding.c +++ b/src/libvterm/src/encoding.c @@ -49,6 +49,7 @@ static void decode_utf8(VTermEncoding *e if(data->bytes_remaining) { data->bytes_remaining = 0; cp[(*cpi)++] = UNICODE_INVALID; + // VIM: avoid going over the end if (*cpi >= cplen) break; } @@ -226,8 +227,7 @@ encodings[] = { /* 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++) + for(int i = 0; encodings[i].designation; i++) if(encodings[i].type == type && encodings[i].designation == designation) return encodings[i].enc; return NULL; diff --git a/src/libvterm/src/keyboard.c b/src/libvterm/src/keyboard.c --- a/src/libvterm/src/keyboard.c +++ b/src/libvterm/src/keyboard.c @@ -4,6 +4,7 @@ #include "utf8.h" +// VIM: added int vterm_is_modify_other_keys(VTerm *vt) { return vt->state->mode.modify_other_keys; @@ -12,8 +13,7 @@ int vterm_is_modify_other_keys(VTerm *vt void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod) { - int needs_CSIu; - + // 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,6 +33,7 @@ void vterm_keyboard_unichar(VTerm *vt, u return; } + int needs_CSIu; switch(c) { /* Special Ctrl- letters that can't be represented elsewise */ case 'i': case 'j': case 'm': case '[': @@ -93,12 +94,12 @@ static keycodes_s keycodes[] = { { KEYCODE_CSI_CURSOR, 'D', 0 }, // LEFT { KEYCODE_CSI_CURSOR, 'C', 0 }, // RIGHT - { KEYCODE_CSINUM, '~', 2 }, // INS - { KEYCODE_CSINUM, '~', 3 }, // DEL + { 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 + { KEYCODE_CSINUM, '~', 5 }, // PAGEUP + { KEYCODE_CSINUM, '~', 6 }, // PAGEDOWN }; static keycodes_s keycodes_fn[] = { @@ -107,14 +108,14 @@ static keycodes_s keycodes_fn[] = { { 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 + { 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,11 +141,10 @@ static keycodes_s keycodes_kp[] = { void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod) { - keycodes_s k; - if(key == VTERM_KEY_NONE) return; + keycodes_s k; if(key < VTERM_KEY_FUNCTION_0) { if(key >= sizeof(keycodes)/sizeof(keycodes[0])) return; diff --git a/src/libvterm/src/parser.c b/src/libvterm/src/parser.c --- a/src/libvterm/src/parser.c +++ b/src/libvterm/src/parser.c @@ -142,7 +142,6 @@ size_t vterm_input_write(VTerm *vt, cons 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()) { @@ -187,7 +186,7 @@ size_t vterm_input_write(VTerm *vt, cons } // else fallthrough - string_len = bytes + pos - string_start; + 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,7 +246,7 @@ size_t vterm_input_write(VTerm *vt, cons vt->parser.v.csi.argi++; vt->parser.intermedlen = 0; vt->parser.state = CSI_INTERMED; - // fallthrough + // FALLTHROUGH case CSI_INTERMED: if(is_intermed(c)) { if(vt->parser.intermedlen < INTERMED_MAX-1) diff --git a/src/libvterm/src/pen.c b/src/libvterm/src/pen.c --- a/src/libvterm/src/pen.c +++ b/src/libvterm/src/pen.c @@ -44,6 +44,7 @@ static int ramp24[] = { 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,27 +162,27 @@ static void set_pen_col_ansi(VTermState 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++) + 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.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.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,14 +196,17 @@ INTERNAL void vterm_state_savepen(VTermS 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_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,6 +451,18 @@ INTERNAL void vterm_state_setpen(VTermSt 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,6 +560,13 @@ INTERNAL int vterm_state_getpen(VTermSta 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,6 +613,14 @@ int vterm_state_get_penattr(const VTermS 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; } diff --git a/src/libvterm/src/screen.c b/src/libvterm/src/screen.c --- a/src/libvterm/src/screen.c +++ b/src/libvterm/src/screen.c @@ -10,6 +10,8 @@ #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,6 +26,8 @@ typedef struct 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,7 +58,9 @@ struct VTermScreen int rows; int cols; - int global_reverse; + + unsigned int global_reverse : 1; + unsigned int reflow : 1; /* Primary and Altscreen. buffers[1] is lazily allocated as needed */ ScreenCell *buffers[2]; @@ -88,11 +94,9 @@ static ScreenCell *getcell(const VTermSc 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++) { + for(int row = 0; row < rows; row++) { + for(int col = 0; col < cols; col++) { clearcell(screen, &new_buffer[row * cols + col]); } } @@ -168,16 +172,13 @@ static void damagescreen(VTermScreen *sc 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; + 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,7 +186,7 @@ static int putglyph(VTermGlyphInfo *info if(i < VTERM_MAX_CHARS_PER_CELL) cell->chars[i] = 0; - for(col = 1; col < info->width; col++) + for(int col = 1; col < info->width; col++) { ScreenCell *onecell = getcell(screen, pos.row, pos.col + col); if (onecell == NULL) @@ -193,6 +194,7 @@ static int putglyph(VTermGlyphInfo *info 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,33 +227,29 @@ static int moverect_internal(VTermRect d 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++) + 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; - int row; + int cols = src.end_col - src.start_col; + int downward = src.start_row - dest.start_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; - } + 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(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)); - } + 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,12 +275,11 @@ static int moverect_user(VTermRect dest, 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++) { + 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(col = rect.start_col; col < rect.end_col; col++) { + for(int col = rect.start_col; col < rect.end_col; col++) { ScreenCell *cell = getcell(screen, row, col); if (cell == NULL) @@ -448,6 +445,12 @@ static int setpenattr(VTermAttr attr, VT 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,6 +499,18 @@ static int bell(void *user) 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,33 +525,150 @@ static void resize_buffer(VTermScreen *s // Find the final row of old buffer content int old_row = old_rows - 1; int new_row = new_rows - 1; - int col; + + 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; - 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]); + 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; - new_lineinfo[new_row] = old_lineinfo[old_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; - old_row--; - new_row--; + 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; + } - 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_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_row++; + 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 */ - int row; - for(row = 0; row <= old_row; row++) + for(int row = 0; row <= old_row; row++) sb_pushline_from_row(screen, row); if(active) statefields->pos.row -= (old_row + 1); @@ -553,9 +685,8 @@ static void resize_buffer(VTermScreen *s 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++) { + for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { dst->chars[i] = src->chars[i]; if(!src->chars[i]) break; @@ -569,6 +700,8 @@ static void resize_buffer(VTermScreen *s 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,15 +717,16 @@ static void resize_buffer(VTermScreen *s 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(col = 0; col < new_cols; col++) + for(int col = 0; col < new_cols; col++) clearcell(screen, &new_buffer[new_row * new_cols + col]); new_lineinfo[new_row] = (VTermLineInfo){ 0 }; } @@ -604,11 +738,10 @@ static void resize_buffer(VTermScreen *s vterm_allocator_free(screen->vt, old_lineinfo); statefields->lineinfos[bufidx] = new_lineinfo; - return; + if(active) + statefields->pos = new_cursor; - /* REFLOW TODO: - * Handle delta. Probably needs to be a full cursorpos that we edit - */ + return; } static int resize(int new_rows, int new_cols, VTermStateFields *fields, void *user) @@ -667,12 +800,10 @@ static int resize(int new_rows, int new_ 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++) { + for(int col = 0; col < screen->cols; col++) { ScreenCell *cell = getcell(screen, row, col); if (cell == NULL) { @@ -684,6 +815,7 @@ static int setlineinfo(int row, const VT cell->pen.dhl = newinfo->doubleheight; } + VTermRect rect; rect.start_row = row; rect.end_row = row + 1; rect.start_col = 0; @@ -701,6 +833,16 @@ static int setlineinfo(int row, const VT 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,7 +854,8 @@ static VTermStateCallbacks state_cbs = { &settermprop, // settermprop &bell, // bell &resize, // resize - &setlineinfo // setlineinfo + &setlineinfo, // setlineinfo + &sb_clear, //sb_clear }; /* @@ -722,14 +865,13 @@ static VTermStateCallbacks state_cbs = { static VTermScreen *screen_new(VTerm *vt) { VTermState *state = vterm_obtain_state(vt); - VTermScreen *screen; - int rows, cols; + if(!state) + return NULL; - if (state == NULL) - return NULL; - screen = vterm_allocator_malloc(vt, sizeof(VTermScreen)); + VTermScreen *screen = vterm_allocator_malloc(vt, sizeof(VTermScreen)); if (screen == NULL) return NULL; + int rows, cols; vterm_get_size(vt, &rows, &cols); @@ -743,6 +885,9 @@ static VTermScreen *screen_new(VTerm *vt screen->rows = rows; screen->cols = cols; + screen->global_reverse = FALSE; + screen->reflow = FALSE; + screen->callbacks = NULL; screen->cbdata = NULL; @@ -785,7 +930,6 @@ static size_t _get_chars(const VTermScre { size_t outpos = 0; int padding = 0; - int row, col; #define PUT(c) \ if(utf8) { \ @@ -802,10 +946,9 @@ static size_t _get_chars(const VTermScre outpos++; \ } - for(row = rect.start_row; row < rect.end_row; row++) { - for(col = rect.start_col; col < rect.end_col; col++) { + 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); - int i; if (cell == NULL) { @@ -824,7 +967,7 @@ static size_t _get_chars(const VTermScre PUT(UNICODE_SPACE); padding--; } - for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) { + for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) { PUT(cell->chars[i]); } } @@ -853,12 +996,11 @@ size_t vterm_screen_get_text(const VTerm 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++) { + for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { cell->chars[i] = intcell->chars[i]; if(!intcell->chars[i]) break; @@ -872,6 +1014,8 @@ int vterm_screen_get_cell(const VTermScr 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,11 +1063,25 @@ int vterm_screen_is_eol(const VTermScree VTermScreen *vterm_obtain_screen(VTerm *vt) { - if(!vt->screen) - vt->screen = screen_new(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,14 +1158,16 @@ static int attrs_differ(VTermAttrMask at 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) { - int col; - ScreenCell *target = getcell(screen, pos.row, pos.col); // TODO: bounds check @@ -1019,6 +1179,8 @@ int vterm_screen_get_attrs_extent(const 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; diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -387,9 +387,12 @@ static int on_text(const char bytes[], s } #endif if (i == glyph_starts || this_width > width) - width = this_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,6 +1152,12 @@ static int on_csi(const char *leader, co 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,6 +1400,29 @@ static int on_csi(const char *leader, co 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,11 +1889,11 @@ static void request_status_string(VTermS 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; + size_t i = 0; while(i < sizeof(state->tmp.decrqss)-1 && tmp[i]) i++; while(i < sizeof(state->tmp.decrqss)-1 && frag.len--) @@ -1877,14 +1909,13 @@ static void request_status_string(VTermS 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++) { + 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,15 +2027,14 @@ static int on_resize(int rows, int cols, { 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 */ + int col; for(col = 0; col < state->cols && col < cols; col++) { unsigned char mask = 1 << (col & 7); if(state->tabstops[col >> 3] & mask) @@ -2033,13 +2063,13 @@ static int on_resize(int rows, int cols, 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,11 +2141,10 @@ static const VTermParserCallbacks parser */ VTermState *vterm_obtain_state(VTerm *vt) { - VTermState *state; if(vt->state) return vt->state; - state = vterm_state_new(vt); + VTermState *state = vterm_state_new(vt); if (state == NULL) return NULL; vt->state = state; @@ -2127,8 +2156,6 @@ VTermState *vterm_obtain_state(VTerm *vt void vterm_state_reset(VTermState *state, int hard) { - VTermEncoding *default_enc; - state->scrollregion_top = 0; state->scrollregion_bottom = -1; state->scrollregion_left = 0; @@ -2149,37 +2176,28 @@ void vterm_state_reset(VTermState *state 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); - } + 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); - default_enc = state->vt->mode.utf8 ? + VTermEncoding *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); - } + 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,12 +2212,11 @@ void vterm_state_reset(VTermState *state 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; + VTermRect rect = { 0, 0, 0, 0 }; rect.end_row = state->rows; rect.end_col = state->cols; erase(state, rect, 0); diff --git a/src/libvterm/src/unicode.c b/src/libvterm/src/unicode.c --- a/src/libvterm/src/unicode.c +++ b/src/libvterm/src/unicode.c @@ -452,20 +452,64 @@ static int mk_wcwidth(uint32_t ucs) } #endif -#if 0 // unused -static int mk_wcswidth(const uint32_t *pwcs, size_t n) -{ - int w, width = 0; +/* 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 } +}; - for (;*pwcs && n-- > 0; pwcs++) - if ((w = mk_wcwidth(*pwcs)) < 0) - return -1; - else - width += w; - - return width; -} - +#ifdef USE_MK_WCWIDTH_CJK /* * The following functions are the same as mk_wcwidth() and @@ -478,65 +522,6 @@ static int mk_wcswidth(const uint32_t *p */ 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)) @@ -545,19 +530,6 @@ static int mk_wcwidth_cjk(uint32_t ucs) 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) diff --git a/src/libvterm/src/vterm.c b/src/libvterm/src/vterm.c --- a/src/libvterm/src/vterm.c +++ b/src/libvterm/src/vterm.c @@ -134,6 +134,9 @@ void vterm_get_size(const VTerm *vt, int void vterm_set_size(VTerm *vt, int rows, int cols) { + if(rows < 1 || cols < 1) + return; + vt->rows = rows; vt->cols = cols; @@ -201,7 +204,6 @@ INTERNAL void vterm_push_output_sprintf( 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, @@ -213,6 +215,7 @@ INTERNAL void vterm_push_output_sprintf_ 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,7 +224,6 @@ INTERNAL void vterm_push_output_sprintf_ 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) @@ -236,6 +238,7 @@ INTERNAL void vterm_push_output_sprintf_ 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,6 +295,8 @@ VTermValueType vterm_get_attr_type(VTerm 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,8 +401,6 @@ void vterm_copy_cells(VTermRect dest, 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; @@ -420,6 +423,7 @@ void vterm_copy_cells(VTermRect dest, 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; diff --git a/src/libvterm/src/vterm_internal.h b/src/libvterm/src/vterm_internal.h --- a/src/libvterm/src/vterm_internal.h +++ b/src/libvterm/src/vterm_internal.h @@ -60,6 +60,8 @@ struct VTermPen 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 diff --git a/src/libvterm/t/10state_putglyph.test b/src/libvterm/t/10state_putglyph.test --- a/src/libvterm/t/10state_putglyph.test +++ b/src/libvterm/t/10state_putglyph.test @@ -52,6 +52,12 @@ PUSH "\xCC\x81Z" 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 diff --git a/src/libvterm/t/13state_edit.test b/src/libvterm/t/13state_edit.test --- a/src/libvterm/t/13state_edit.test +++ b/src/libvterm/t/13state_edit.test @@ -1,6 +1,6 @@ INIT UTF8 1 -WANTSTATE se +WANTSTATE seb !ICH RESET @@ -242,6 +242,10 @@ PUSH "\e[2J" erase 0..25,0..80 ?cursor = 1,1 +!ED 3 +PUSH "\e[3J" + sb_clear + !SED RESET erase 0..25,0..80 diff --git a/src/libvterm/t/26state_query.test b/src/libvterm/t/26state_query.test --- a/src/libvterm/t/26state_query.test +++ b/src/libvterm/t/26state_query.test @@ -9,7 +9,7 @@ PUSH "\e[c" !XTVERSION RESET PUSH "\e[>q" - output "\eP>|libvterm(0.2)\e\\" + output "\eP>|libvterm(0.3)\e\\" !DSR RESET diff --git a/src/libvterm/t/30state_pen.test b/src/libvterm/t/30state_pen.test --- a/src/libvterm/t/30state_pen.test +++ b/src/libvterm/t/30state_pen.test @@ -112,3 +112,14 @@ PUSH "\e[m\e[1;37m" 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 diff --git a/src/libvterm/t/64screen_pen.test b/src/libvterm/t/64screen_pen.test --- a/src/libvterm/t/64screen_pen.test +++ b/src/libvterm/t/64screen_pen.test @@ -35,6 +35,12 @@ PUSH "\e[31mG\e[m" 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) diff --git a/src/libvterm/t/69screen_reflow.test b/src/libvterm/t/69screen_reflow.test new file mode 100644 --- /dev/null +++ b/src/libvterm/t/69screen_reflow.test @@ -0,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 diff --git a/src/libvterm/t/harness.c b/src/libvterm/t/harness.c --- a/src/libvterm/t/harness.c +++ b/src/libvterm/t/harness.c @@ -1,6 +1,7 @@ #include "vterm.h" #include "../src/vterm_internal.h" // We pull in some internal bits too +#include #include #include @@ -409,6 +410,8 @@ static struct { int conceal; int strike; int font; + int small; + int baseline; VTermColor foreground; VTermColor background; } state_pen; @@ -439,6 +442,12 @@ static int state_setpenattr(VTermAttr at 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,6 +467,15 @@ static int state_setlineinfo(int row UNU 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,6 +488,7 @@ VTermStateCallbacks state_cbs = { NULL, // bell NULL, // resize state_setlineinfo, // setlineinfo + state_sb_clear, // sb_clear }; static int selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user UNUSED) @@ -592,6 +611,15 @@ static int screen_sb_popline(int cols, V 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,7 +628,8 @@ VTermScreenCallbacks screen_cbs = { NULL, // bell NULL, // resize screen_sb_pushline, // sb_pushline - screen_sb_popline // sb_popline + screen_sb_popline, // sb_popline + screen_sb_clear, // sb_clear }; int main(int argc UNUSED, char **argv UNUSED) @@ -629,12 +658,14 @@ int main(int argc UNUSED, char **argv UN } 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,6 +702,9 @@ int main(int argc UNUSED, char **argv UN 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,6 +713,7 @@ int main(int argc UNUSED, char **argv UN 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,6 +747,9 @@ int main(int argc UNUSED, char **argv UN 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,6 +781,8 @@ int main(int argc UNUSED, char **argv UN 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,6 +799,7 @@ int main(int argc UNUSED, char **argv UN 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,6 +855,7 @@ int main(int argc UNUSED, char **argv UN } else if(strstartswith(line, "FOCUS ")) { + assert(state); char *linep = line + 6; if(streq(linep, "IN")) vterm_state_focus_in(state); @@ -869,6 +911,8 @@ int main(int argc UNUSED, char **argv UN } frag.len = inplace_hex2bytes(linep); frag.str = linep; + assert(frag.len); + linep += frag.len * 2; while(linep[0] == ' ') linep++; @@ -879,6 +923,7 @@ int main(int argc UNUSED, char **argv UN } else if(strstartswith(line, "DAMAGEMERGE ")) { + assert(screen); char *linep = line + 12; while(linep[0] == ' ') linep++; @@ -893,11 +938,13 @@ int main(int argc UNUSED, char **argv UN } 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,6 +957,7 @@ int main(int argc UNUSED, char **argv UN 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,6 +1013,24 @@ int main(int argc UNUSED, char **argv UN 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,6 +1043,7 @@ int main(int argc UNUSED, char **argv UN printf("?\n"); } else if(strstartswith(line, "?lineinfo ")) { + assert(state); char *linep = line + 10; int row; const VTermLineInfo *info; @@ -996,6 +1063,7 @@ int main(int argc UNUSED, char **argv UN printf("\n"); } else if(strstartswith(line, "?screen_chars ")) { + assert(screen); char *linep = line + 13; VTermRect rect; size_t len; @@ -1028,6 +1096,7 @@ int main(int argc UNUSED, char **argv UN } } else if(strstartswith(line, "?screen_text ")) { + assert(screen); char *linep = line + 12; VTermRect rect; size_t len; @@ -1067,6 +1136,7 @@ int main(int argc UNUSED, char **argv UN } } else if(strstartswith(line, "?screen_cell ")) { + assert(screen); char *linep = line + 12; int i; VTermPos pos; @@ -1090,6 +1160,10 @@ int main(int argc UNUSED, char **argv UN 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,6 +1176,7 @@ int main(int argc UNUSED, char **argv UN printf("\n"); } else if(strstartswith(line, "?screen_eol ")) { + assert(screen); VTermPos pos; char *linep = line + 12; while(linep[0] == ' ') @@ -1113,6 +1188,7 @@ int main(int argc UNUSED, char **argv UN 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; diff --git a/src/libvterm/t/run-test.pl b/src/libvterm/t/run-test.pl --- a/src/libvterm/t/run-test.pl +++ b/src/libvterm/t/run-test.pl @@ -124,7 +124,7 @@ sub do_line 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) / ) { + 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) (.*?) (\[?)(.*?)(\]?)$/ ) { diff --git a/src/terminal.c b/src/terminal.c --- a/src/terminal.c +++ b/src/terminal.c @@ -3447,7 +3447,8 @@ static VTermScreenCallbacks screen_callb handle_bell, // bell handle_resize, // resize handle_pushline, // sb_pushline - NULL // sb_popline + NULL, // sb_popline + NULL // sb_clear }; /* diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 774, +/**/ 773, /**/ 772,