diff options
author | Bram Moolenaar <Bram@vim.org> | 2022-10-16 19:26:52 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-10-16 19:26:52 +0100 |
commit | 6a12d26f3404e45ce25cf9152857e355b28f392a (patch) | |
tree | 7866a4154ea9964e8026ac282d9407e20c4df861 | |
parent | d094e580b0873d67c2d30f60c9fd43c9a0044149 (diff) |
patch 9.0.0774: the libvterm code is outdatedv9.0.0774
Problem: The libvterm code is outdated.
Solution: Include libvterm changes from revision 802 to 817. Revert some
changes made for C89.
-rw-r--r-- | src/libvterm/CONTRIBUTING | 4 | ||||
-rw-r--r-- | src/libvterm/Makefile | 2 | ||||
-rw-r--r-- | src/libvterm/README | 7 | ||||
-rw-r--r-- | src/libvterm/doc/seqs.txt | 4 | ||||
-rw-r--r-- | src/libvterm/include/vterm.h | 36 | ||||
-rw-r--r-- | src/libvterm/src/encoding.c | 4 | ||||
-rw-r--r-- | src/libvterm/src/keyboard.c | 32 | ||||
-rw-r--r-- | src/libvterm/src/parser.c | 5 | ||||
-rw-r--r-- | src/libvterm/src/pen.c | 57 | ||||
-rw-r--r-- | src/libvterm/src/screen.c | 322 | ||||
-rw-r--r-- | src/libvterm/src/state.c | 85 | ||||
-rw-r--r-- | src/libvterm/src/unicode.c | 142 | ||||
-rw-r--r-- | src/libvterm/src/vterm.c | 12 | ||||
-rw-r--r-- | src/libvterm/src/vterm_internal.h | 2 | ||||
-rw-r--r-- | src/libvterm/t/10state_putglyph.test | 6 | ||||
-rw-r--r-- | src/libvterm/t/13state_edit.test | 6 | ||||
-rw-r--r-- | src/libvterm/t/26state_query.test | 2 | ||||
-rw-r--r-- | src/libvterm/t/30state_pen.test | 11 | ||||
-rw-r--r-- | src/libvterm/t/64screen_pen.test | 6 | ||||
-rw-r--r-- | src/libvterm/t/69screen_reflow.test | 79 | ||||
-rw-r--r-- | src/libvterm/t/harness.c | 78 | ||||
-rw-r--r-- | src/libvterm/t/run-test.pl | 2 | ||||
-rw-r--r-- | src/terminal.c | 3 | ||||
-rw-r--r-- | src/version.c | 2 |
24 files changed, 655 insertions, 254 deletions
diff --git a/src/libvterm/CONTRIBUTING b/src/libvterm/CONTRIBUTING index 2100d1e510..e9a8f0c331 100644 --- 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 <leonerd@leonerd.org.uk> diff --git a/src/libvterm/Makefile b/src/libvterm/Makefile index 2f83e0d68c..ba4a3157ed 100644 --- 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 index 8e9341d070..264128445d 100644 --- 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 index 02a9fe51f6..27f28b91b6 100644 --- a/src/libvterm/doc/seqs.txt +++ b/src/libvterm/doc/seqs.txt @@ -122,6 +122,7 @@ x = xterm 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 @@ x = xterm 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 index 21295a62a9..e5887c8714 100644 --- 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 VTermBuilder *builder); /* 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 button, int pressed, VTermModifier mod); #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_fbdata(VTermState *state); 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(VTermScreen *screen); 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 index 694ed6a0ca..817344f333 100644 --- a/src/libvterm/src/encoding.c +++ b/src/libvterm/src/encoding.c @@ -49,6 +49,7 @@ static void decode_utf8(VTermEncoding *enc UNUSED, void *data_, 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 index 87288fe970..c04984abab 100644 --- 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, uint32_t c, VTermModifier mod) 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 index 0d4422cf49..d4cd0dc477 100644 --- a/src/libvterm/src/parser.c +++ b/src/libvterm/src/parser.c @@ -142,7 +142,6 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) 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, const char *bytes, size_t len) } // 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, const char *bytes, size_t len) 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 index c5a0b71c5d..1c6cd4e488 100644 --- 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 *state, VTermAttr attr, long col) 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(VTermState *state, int save) 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(VTermState *state, const long args[], int argco 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(VTermState *state, long args[], int argcount UNU 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 VTermState *state, VTermAttr attr, VTermValue 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 index 25ddb13991..069306ab95 100644 --- 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 VTermScreen *screen, int row, int col) 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 *screen) 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, VTermPos pos, void *user) 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, VTermPos pos, void *user) 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,34 +227,30 @@ static int moverect_internal(VTermRect dest, VTermRect src, void *user) 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; - - 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 cols = src.end_col - src.start_col; + int downward = src.start_row - dest.start_row; - 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)); + 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,12 +275,11 @@ static int moverect_user(VTermRect dest, VTermRect src, void *user) 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, VTermValue *val, void *user) 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 *screen, int bufidx, int new_rows, int new // 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]); + VTermPos old_cursor = statefields->pos; + VTermPos new_cursor = { -1, -1 }; - new_lineinfo[new_row] = old_lineinfo[old_row]; +#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 - old_row--; - new_row--; + /* 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_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)); + if(new_cursor.row >= 0) + new_cursor.row += downwards; - 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; + } + + 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 */ - 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 *screen, int bufidx, int new_rows, int new 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]; |