# HG changeset patch # User Bram Moolenaar # Date 1665927904 -7200 # Node ID 2d2758ffd9593adfeddcf37632c7bbd208f5122b # Parent 3295247d97a5492c8a40023fb2fd50736ffcd7f2 patch 9.0.0772: the libvterm code is outdated Commit: https://github.com/vim/vim/commit/501e77766cd30d8f4bfeb04a67aff1865b5f5a41 Author: Bram Moolenaar Date: Sun Oct 16 14:35:46 2022 +0100 patch 9.0.0772: the libvterm code is outdated Problem: The libvterm code is outdated. Solution: Include libvterm changes from revision 790 to 801. diff --git a/src/libvterm/README b/src/libvterm/README --- a/src/libvterm/README +++ b/src/libvterm/README @@ -8,7 +8,7 @@ The original can be found: Modifications: - Add a .gitignore file. -- Convert from C99 to C90. +- 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: 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 @@ -132,6 +132,7 @@ 123x CSI n = DSR, Device St 1 or 2 = block 3 or 4 = underline 5 or 6 = I-beam to left + x CSI > q = XTVERSION, request version string 23x CSI " q = DECSCA, select character attributes 123x CSI r = DECSTBM x CSI s = DECSLRM 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 @@ -26,6 +26,11 @@ typedef unsigned int uint32_t; #define VTERM_CHECK_VERSION \ vterm_check_version(VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR) +/* Any cell can contain at most one basic printing character and 5 combining + * characters. This number could be changed but will be ABI-incompatible if + * you do */ +#define VTERM_MAX_CHARS_PER_CELL 6 + typedef struct VTerm VTerm; typedef struct VTermState VTermState; typedef struct VTermScreen VTermScreen; @@ -297,6 +302,7 @@ typedef struct { */ typedef struct { VTermPos pos; /* current cursor position */ + VTermLineInfo *lineinfos[2]; /* [1] may be NULL */ } VTermStateFields; typedef struct { @@ -306,11 +312,30 @@ 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 { + int ver; /* currently unused but reserved for some sort of ABI version flag */ + + int rows, cols; + + const VTermAllocatorFunctions *allocator; + void *allocdata; + + /* Override default sizes for various structures */ + size_t outbuffer_len; /* default: 4096 */ + size_t tmpbuffer_len; /* default: 4096 */ +}; + +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. VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata); @@ -507,7 +532,6 @@ enum { }; typedef struct { -#define VTERM_MAX_CHARS_PER_CELL 6 uint32_t chars[VTERM_MAX_CHARS_PER_CELL]; char width; VTermScreenCellAttrs attrs; 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 @@ -502,7 +502,10 @@ static void resize_buffer(VTermScreen *s int old_cols = screen->cols; ScreenCell *old_buffer = screen->buffers[bufidx]; + VTermLineInfo *old_lineinfo = statefields->lineinfos[bufidx]; + ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols); + VTermLineInfo *new_lineinfo = vterm_allocator_malloc(screen->vt, sizeof(new_lineinfo[0]) * new_rows); // Find the final row of old buffer content int old_row = old_rows - 1; @@ -515,6 +518,8 @@ static void resize_buffer(VTermScreen *s 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--; @@ -584,15 +589,21 @@ static void resize_buffer(VTermScreen *s /* 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(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 }; + } } vterm_allocator_free(screen->vt, old_buffer); screen->buffers[bufidx] = new_buffer; + vterm_allocator_free(screen->vt, old_lineinfo); + statefields->lineinfos[bufidx] = new_lineinfo; + return; /* REFLOW TODO: @@ -606,6 +617,7 @@ static int resize(int new_rows, int new_ int altscreen_active = (screen->buffers[BUFIDX_ALTSCREEN] && screen->buffer == screen->buffers[BUFIDX_ALTSCREEN]); + int old_rows = screen->rows; int old_cols = screen->cols; if(new_cols > old_cols) { @@ -619,6 +631,17 @@ static int resize(int new_rows, int new_ resize_buffer(screen, 0, new_rows, new_cols, !altscreen_active, fields); if(screen->buffers[BUFIDX_ALTSCREEN]) resize_buffer(screen, 1, new_rows, new_cols, altscreen_active, fields); + else if(new_rows != old_rows) { + /* We don't need a full resize of the altscreen because it isn't enabled + * but we should at least keep the lineinfo the right size */ + vterm_allocator_free(screen->vt, fields->lineinfos[BUFIDX_ALTSCREEN]); + + VTermLineInfo *new_lineinfo = vterm_allocator_malloc(screen->vt, sizeof(new_lineinfo[0]) * new_rows); + for(int row = 0; row < new_rows; row++) + new_lineinfo[row] = (VTermLineInfo){ 0 }; + + fields->lineinfos[BUFIDX_ALTSCREEN] = new_lineinfo; + } screen->buffer = altscreen_active ? screen->buffers[BUFIDX_ALTSCREEN] : screen->buffers[BUFIDX_PRIMARY]; 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 @@ -280,7 +280,6 @@ static void set_lineinfo(VTermState *sta static int on_text(const char bytes[], size_t len, void *user) { VTermState *state = user; - uint32_t *codepoints; int npoints = 0; size_t eaten = 0; VTermEncodingInstance *encoding; @@ -290,9 +289,8 @@ static int on_text(const char bytes[], s // We'll have at most len codepoints, plus one from a previous incomplete // sequence. - codepoints = vterm_allocator_malloc(state->vt, (len + 1) * sizeof(uint32_t)); - if (codepoints == NULL) - return 0; + uint32_t *codepoints = (uint32_t *)(state->vt->tmpbuffer); + size_t maxpoints = (state->vt->tmpbuffer_len) / sizeof(uint32_t); encoding = state->gsingle_set ? &state->encoding[state->gsingle_set] : @@ -301,7 +299,7 @@ static int on_text(const char bytes[], s &state->encoding[state->gr_set]; (*encoding->enc->decode)(encoding->enc, encoding->data, - codepoints, &npoints, state->gsingle_set ? 1 : (int)len, + codepoints, &npoints, state->gsingle_set ? 1 : (int)maxpoints, bytes, &eaten, len); /* There's a chance an encoding (e.g. UTF-8) hasn't found enough bytes yet @@ -309,7 +307,6 @@ static int on_text(const char bytes[], s */ if(!npoints) { - vterm_allocator_free(state->vt, codepoints); return (int)eaten; } @@ -363,13 +360,14 @@ static int on_text(const char bytes[], s int glyph_starts = i; int glyph_ends; int width = 0; - uint32_t *chars; - - for(glyph_ends = i + 1; glyph_ends < npoints; glyph_ends++) + + for(glyph_ends = i + 1; + (glyph_ends < npoints) && (glyph_ends < glyph_starts + VTERM_MAX_CHARS_PER_CELL); + glyph_ends++) if(!vterm_unicode_is_combining(codepoints[glyph_ends])) break; - chars = vterm_allocator_malloc(state->vt, (glyph_ends - glyph_starts + 1) * sizeof(uint32_t)); + uint32_t *chars = vterm_allocator_malloc(state->vt, (VTERM_MAX_CHARS_PER_CELL + 1) * sizeof(uint32_t)); if (chars == NULL) break; @@ -461,7 +459,6 @@ static int on_text(const char bytes[], s } #endif - vterm_allocator_free(state->vt, codepoints); return (int)eaten; } @@ -952,6 +949,12 @@ static void request_dec_mode(VTermState vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "?%d;%d$y", num, reply ? 1 : 2); } +static void request_version_string(VTermState *state) +{ + vterm_push_output_sprintf_str(state->vt, C1_DCS, TRUE, ">|libvterm(%d.%d)", + VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR); +} + static int on_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user) { VTermState *state = user; @@ -1423,6 +1426,10 @@ static int on_csi(const char *leader, co request_dec_mode(state, CSI_ARG(args[0])); break; + case LEADER('>', 0x71): // XTVERSION - xterm query version string + request_version_string(state); + break; + case INTERMED(' ', 0x71): // DECSCUSR - DEC set cursor shape val = CSI_ARG_OR(args[0], 1); @@ -2018,33 +2025,6 @@ static int on_resize(int rows, int cols, state->tabstops = newtabstops; } - if(rows != state->rows) { - int bufidx; - for(bufidx = BUFIDX_PRIMARY; bufidx <= BUFIDX_ALTSCREEN; bufidx++) { - int row; - VTermLineInfo *oldlineinfo = state->lineinfos[bufidx]; - VTermLineInfo *newlineinfo; - if(!oldlineinfo) - continue; - - newlineinfo = vterm_allocator_malloc(state->vt, rows * sizeof(VTermLineInfo)); - - for(row = 0; row < state->rows && row < rows; row++) { - newlineinfo[row] = oldlineinfo[row]; - } - - for( ; row < rows; row++) { - VTermLineInfo lineInfo = {0x0}; - newlineinfo[row] = lineInfo; - } - - vterm_allocator_free(state->vt, state->lineinfos[bufidx]); - state->lineinfos[bufidx] = newlineinfo; - } - - state->lineinfo = state->lineinfos[state->mode.alt_screen ? BUFIDX_ALTSCREEN : BUFIDX_PRIMARY]; - } - state->rows = rows; state->cols = cols; @@ -2054,11 +2034,44 @@ static int on_resize(int rows, int cols, UBOUND(state->scrollregion_right, state->cols); fields.pos = state->pos; - - if(state->callbacks && state->callbacks->resize) + 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->pos = fields.pos; + + state->lineinfos[0] = fields.lineinfos[0]; + state->lineinfos[1] = fields.lineinfos[1]; + } + else { + if(rows != state->rows) { + for(int bufidx = BUFIDX_PRIMARY; bufidx <= BUFIDX_ALTSCREEN; bufidx++) { + VTermLineInfo *oldlineinfo = state->lineinfos[bufidx]; + if(!oldlineinfo) + continue; + + VTermLineInfo *newlineinfo = vterm_allocator_malloc(state->vt, rows * sizeof(VTermLineInfo)); + + int row; + for(row = 0; row < state->rows && row < rows; row++) { + newlineinfo[row] = oldlineinfo[row]; + } + + for( ; row < rows; row++) { + newlineinfo[row] = (VTermLineInfo){ + .doublewidth = 0, + }; + } + + vterm_allocator_free(state->vt, state->lineinfos[bufidx]); + state->lineinfos[bufidx] = newlineinfo; + } + } + } + + state->lineinfo = state->lineinfos[state->mode.alt_screen ? BUFIDX_ALTSCREEN : BUFIDX_PRIMARY]; if(state->at_phantom && state->pos.col < cols-1) { state->at_phantom = 0; 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 @@ -34,21 +34,39 @@ static VTermAllocatorFunctions default_a VTerm *vterm_new(int rows, int cols) { - return vterm_new_with_allocator(rows, cols, &default_allocator, NULL); + struct VTermBuilder builder; + memset(&builder, 0, sizeof(builder)); + builder.rows = rows; + builder.cols = cols; + return vterm_build(&builder); } VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata) { - /* Need to bootstrap using the allocator function directly */ - VTerm *vt = (*funcs->malloc)(sizeof(VTerm), allocdata); + struct VTermBuilder builder; + memset(&builder, 0, sizeof(builder)); + builder.rows = rows; + builder.cols = cols; + builder.allocator = funcs; + builder.allocdata = allocdata; + return vterm_build(&builder); +} + +/* A handy macro for defaulting values out of builder fields */ +#define DEFAULT(v, def) ((v) ? (v) : (def)) - if (vt == NULL) - return NULL; - vt->allocator = funcs; - vt->allocdata = allocdata; +VTerm *vterm_build(const struct VTermBuilder *builder) +{ + const VTermAllocatorFunctions *allocator = DEFAULT(builder->allocator, &default_allocator); - vt->rows = rows; - vt->cols = cols; + /* Need to bootstrap using the allocator function directly */ + VTerm *vt = (*allocator->malloc)(sizeof(VTerm), builder->allocdata); + + vt->allocator = allocator; + vt->allocdata = builder->allocdata; + + vt->rows = builder->rows; + vt->cols = builder->cols; vt->parser.state = NORMAL; @@ -58,11 +76,11 @@ VTerm *vterm_new_with_allocator(int rows vt->outfunc = NULL; vt->outdata = NULL; - vt->outbuffer_len = 200; + vt->outbuffer_len = DEFAULT(builder->outbuffer_len, 4096); vt->outbuffer_cur = 0; vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len); - vt->tmpbuffer_len = 64; + vt->tmpbuffer_len = DEFAULT(builder->tmpbuffer_len, 4096); vt->tmpbuffer = vterm_allocator_malloc(vt, vt->tmpbuffer_len); if (vt->tmpbuffer == NULL 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 @@ -182,7 +182,7 @@ struct VTermState struct VTerm { - VTermAllocatorFunctions *allocator; + const VTermAllocatorFunctions *allocator; void *allocdata; int rows; 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 @@ -6,6 +6,11 @@ RESET PUSH "\e[c" output "\e[?1;2c" +!XTVERSION +RESET +PUSH "\e[>q" + output "\eP>|libvterm(0.2)\e\\" + !DSR RESET PUSH "\e[5n" @@ -57,6 +62,6 @@ PUSH "\e[5n" output "\x{9b}0n" PUSH "\e F" -!Truncation on attempted buffer overflow -PUSH "\e[6n" x 30 - output "\e[10;10R" x 25 +#!Truncation on attempted buffer overflow +#PUSH "\e[6n" x 30 +# output "\e[10;10R" x 25 diff --git a/src/libvterm/t/60screen_ascii.test b/src/libvterm/t/60screen_ascii.test --- a/src/libvterm/t/60screen_ascii.test +++ b/src/libvterm/t/60screen_ascii.test @@ -18,11 +18,11 @@ PUSH "ABC" ?screen_eol 0,3 = 1 PUSH "\e[H" movecursor 0,0 - ?screen_chars 0,0,1,80 = "ABC" + ?screen_row 0 = "ABC" ?screen_text 0,0,1,80 = 0x41,0x42,0x43 PUSH "E" movecursor 0,1 - ?screen_chars 0,0,1,80 = "EBC" + ?screen_row 0 = "EBC" ?screen_text 0,0,1,80 = 0x45,0x42,0x43 WANTSCREEN -c @@ -30,14 +30,14 @@ WANTSCREEN -c !Erase RESET PUSH "ABCDE\e[H\e[K" - ?screen_chars 0,0,1,80 = + ?screen_row 0 = "" ?screen_text 0,0,1,80 = !Copycell RESET PUSH "ABC\e[H\e[@" PUSH "1" - ?screen_chars 0,0,1,80 = "1ABC" + ?screen_row 0 = "1ABC" RESET PUSH "ABC\e[H\e[P" @@ -48,7 +48,7 @@ PUSH "ABC\e[H\e[P" !Space padding RESET PUSH "Hello\e[CWorld" - ?screen_chars 0,0,1,80 = "Hello World" + ?screen_row 0 = "Hello World" ?screen_text 0,0,1,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64 !Linefeed padding @@ -60,10 +60,10 @@ PUSH "Hello\r\nWorld" !Altscreen RESET PUSH "P" - ?screen_chars 0,0,1,80 = "P" + ?screen_row 0 = "P" PUSH "\e[?1049h" - ?screen_chars 0,0,1,80 = + ?screen_row 0 = "" PUSH "\e[2K\e[HA" - ?screen_chars 0,0,1,80 = "A" + ?screen_row 0 = "A" PUSH "\e[?1049l" - ?screen_chars 0,0,1,80 = "P" + ?screen_row 0 = "P" diff --git a/src/libvterm/t/61screen_unicode.test b/src/libvterm/t/61screen_unicode.test --- a/src/libvterm/t/61screen_unicode.test +++ b/src/libvterm/t/61screen_unicode.test @@ -7,7 +7,7 @@ WANTSCREEN # U+00E9 = 0xC3 0xA9 name: LATIN SMALL LETTER E WITH ACUTE RESET PUSH "\xC3\x81\xC3\xA9" - ?screen_chars 0,0,1,80 = 0xc1,0xe9 + ?screen_row 0 = 0xc1,0xe9 ?screen_text 0,0,1,80 = 0xc3,0x81,0xc3,0xa9 ?screen_cell 0,0 = {0xc1} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) @@ -16,7 +16,7 @@ PUSH "\xC3\x81\xC3\xA9" RESET PUSH "0123\e[H" PUSH "\xEF\xBC\x90" - ?screen_chars 0,0,1,80 = 0xff10,0x32,0x33 + ?screen_row 0 = 0xff10,0x32,0x33 ?screen_text 0,0,1,80 = 0xef,0xbc,0x90,0x32,0x33 ?screen_cell 0,0 = {0xff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) @@ -25,7 +25,7 @@ PUSH "\xEF\xBC\x90" RESET PUSH "0123\e[H" PUSH "e\xCC\x81" - ?screen_chars 0,0,1,80 = 0x65,0x301,0x31,0x32,0x33 + ?screen_row 0 = 0x65,0x301,0x31,0x32,0x33 ?screen_text 0,0,1,80 = 0x65,0xcc,0x81,0x31,0x32,0x33 ?screen_cell 0,0 = {0x65,0x301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) diff --git a/src/libvterm/t/62screen_damage.test b/src/libvterm/t/62screen_damage.test --- a/src/libvterm/t/62screen_damage.test +++ b/src/libvterm/t/62screen_damage.test @@ -152,4 +152,4 @@ PUSH "\e[25H\r\nABCDE\b\b\b\e[2P\r\n" DAMAGEFLUSH moverect 1..25,0..80 -> 0..24,0..80 damage 24..25,0..80 - ?screen_chars 23,0,24,5 = "ABE" + ?screen_row 23 = "ABE" diff --git a/src/libvterm/t/63screen_resize.test b/src/libvterm/t/63screen_resize.test --- a/src/libvterm/t/63screen_resize.test +++ b/src/libvterm/t/63screen_resize.test @@ -28,20 +28,20 @@ PUSH "E" RESET RESIZE 25,80 PUSH "Top\e[10HLine 10" - ?screen_chars 0,0,1,80 = "Top" - ?screen_chars 9,0,10,80 = "Line 10" + ?screen_row 0 = "Top" + ?screen_row 9 = "Line 10" ?cursor = 9,7 RESIZE 20,80 - ?screen_chars 0,0,1,80 = "Top" - ?screen_chars 9,0,10,80 = "Line 10" + ?screen_row 0 = "Top" + ?screen_row 9 = "Line 10" ?cursor = 9,7 !Resize shorter with content must scroll RESET RESIZE 25,80 PUSH "Top\e[25HLine 25\e[15H" - ?screen_chars 0,0,1,80 = "Top" - ?screen_chars 24,0,25,80 = "Line 25" + ?screen_row 0 = "Top" + ?screen_row 24 = "Line 25" ?cursor = 14,0 WANTSCREEN b RESIZE 20,80 @@ -50,8 +50,8 @@ RESIZE 20,80 sb_pushline 80 = sb_pushline 80 = sb_pushline 80 = - ?screen_chars 0,0,1,80 = - ?screen_chars 19,0,20,80 = "Line 25" + ?screen_row 0 = "" + ?screen_row 19 = "Line 25" ?cursor = 9,0 !Resize shorter does not lose line with cursor @@ -62,11 +62,11 @@ RESIZE 25,80 WANTSCREEN b PUSH "\e[24HLine 24\r\nLine 25\r\n" sb_pushline 80 = - ?screen_chars 23,0,24,10 = "Line 25" + ?screen_row 23 = "Line 25" ?cursor = 24,0 RESIZE 24,80 sb_pushline 80 = - ?screen_chars 22,0,23,10 = "Line 25" + ?screen_row 22 = "Line 25" ?cursor = 23,0 !Resize shorter does not send the cursor to a negative row @@ -90,8 +90,8 @@ RESET WANTSCREEN -b RESIZE 25,80 PUSH "Line 1\e[25HBottom\e[15H" - ?screen_chars 0,0,1,80 = "Line 1" - ?screen_chars 24,0,25,80 = "Bottom" + ?screen_row 0 = "Line 1" + ?screen_row 24 = "Bottom" ?cursor = 14,0 WANTSCREEN b RESIZE 30,80 @@ -100,9 +100,9 @@ RESIZE 30,80 sb_popline 80 sb_popline 80 sb_popline 80 - ?screen_chars 0,0,1,80 = "ABCDE" - ?screen_chars 5,0,6,80 = "Line 1" - ?screen_chars 29,0,30,80 = "Bottom" + ?screen_row 0 = "ABCDE" + ?screen_row 5 = "Line 1" + ?screen_row 29 = "Bottom" ?cursor = 19,0 WANTSCREEN -b @@ -112,6 +112,6 @@ WANTSCREEN a RESIZE 25,80 PUSH "Main screen\e[?1049h\e[HAlt screen" RESIZE 30,80 - ?screen_chars 0,0,1,3 = "Alt" + ?screen_row 0 = "Alt screen" PUSH "\e[?1049l" - ?screen_chars 0,0,1,3 = "Mai" + ?screen_row 0 = "Main screen" diff --git a/src/libvterm/t/65screen_protect.test b/src/libvterm/t/65screen_protect.test --- a/src/libvterm/t/65screen_protect.test +++ b/src/libvterm/t/65screen_protect.test @@ -4,13 +4,13 @@ WANTSCREEN !Selective erase RESET PUSH "A\e[1\"qB\e[\"qC" - ?screen_chars 0,0,1,3 = 0x41,0x42,0x43 + ?screen_row 0 = "ABC" PUSH "\e[G\e[?J" - ?screen_chars 0,0,1,3 = 0x20,0x42 + ?screen_row 0 = " B" !Non-selective erase RESET PUSH "A\e[1\"qB\e[\"qC" - ?screen_chars 0,0,1,3 = 0x41,0x42,0x43 + ?screen_row 0 = "ABC" PUSH "\e[G\e[J" - ?screen_chars 0,0,1,3 = + ?screen_row 0 = "" 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 @@ -1001,7 +1001,14 @@ int main(int argc UNUSED, char **argv UN size_t len; while(linep[0] == ' ') linep++; - if(sscanf(linep, "%d,%d,%d,%d", &rect.start_row, &rect.start_col, &rect.end_row, &rect.end_col) < 4) { + if(sscanf(linep, "%d,%d,%d,%d", &rect.start_row, &rect.start_col, &rect.end_row, &rect.end_col) == 4) + ; // fine + else if(sscanf(linep, "%d", &rect.start_row) == 1) { + rect.end_row = rect.start_row + 1; + rect.start_col = 0; + vterm_get_size(vt, NULL, &rect.end_col); + } + else { printf("! screen_chars unrecognised input\n"); goto abort_line; } 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 @@ -139,17 +139,23 @@ sub do_line # ?screen_row assertion is emulated here elsif( $line =~ s/^\?screen_row\s+(\d+)\s*=\s*// ) { my $row = $1; - my $row1 = $row + 1; - my $want = eval($line); + my $want; + + if( $line =~ m/^"/ ) { + $want = eval($line); + } + else { + # Turn 0xDD,0xDD,... directly into bytes + $want = pack "C*", map { hex } split m/,/, $line; + } do_onetest if defined $command; - # TODO: may not be 80 - $hin->print( "\?screen_chars $row,0,$row1,80\n" ); + $hin->print( "\?screen_chars $row\n" ); my $response = <$hout>; chomp $response; - $response = pack "C*", map hex, split m/,/, $response; + $response = pack "C*", map { hex } split m/,/, $response; if( $response ne $want ) { print "# line $linenum: Assert ?screen_row $row failed:\n" . "# Expected: $want\n" . 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 */ /**/ + 772, +/**/ 771, /**/ 770,