To: vim_dev@googlegroups.com Subject: Patch 8.2.0787 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0787 Problem: Libvterm code lags behind the upstream version. Solution: Include revisions 741 - 742. Files: Filelist, src/libvterm/src/screen.c *** ../vim-8.2.0786/Filelist 2020-05-17 16:28:47.087869402 +0200 --- Filelist 2020-05-17 22:29:13.015974064 +0200 *************** *** 301,306 **** --- 301,307 ---- src/libvterm/LICENSE \ src/libvterm/Makefile \ src/libvterm/README \ + src/libvterm/CONTRIBUTING \ src/libvterm/tbl2inc_c.pl \ src/libvterm/vterm.pc.in \ src/libvterm/doc/URLs \ *** ../vim-8.2.0786/src/libvterm/src/screen.c 2019-12-04 22:07:58.000000000 +0100 --- src/libvterm/src/screen.c 2020-05-17 22:57:44.159481763 +0200 *************** *** 37,44 **** ScreenPen pen; } ScreenCell; - static int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell); - struct VTermScreen { VTerm *vt; --- 37,42 ---- *************** *** 58,63 **** --- 56,63 ---- int global_reverse; // Primary and Altscreen. buffers[1] is lazily allocated as needed + #define BUFIDX_PRIMARY 0 + #define BUFIDX_ALTSCREEN 1 ScreenCell *buffers[2]; // buffer will == buffers[0] or buffers[1], depending on altscreen *************** *** 69,74 **** --- 69,80 ---- ScreenPen pen; }; + static void clearcell(const VTermScreen *screen, ScreenCell *cell) + { + cell->chars[0] = 0; + cell->pen = screen->pen; + } + static ScreenCell *getcell(const VTermScreen *screen, int row, int col) { if(row < 0 || row >= screen->rows) *************** *** 80,107 **** return screen->buffer + (screen->cols * row) + col; } ! static ScreenCell *realloc_buffer(VTermScreen *screen, ScreenCell *buffer, int new_rows, int new_cols) { ! ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols); ! int row, col; ! ! if (new_buffer == NULL) ! return NULL; ! for(row = 0; row < new_rows; row++) { ! for(col = 0; col < new_cols; col++) { ! ScreenCell *new_cell = new_buffer + row*new_cols + col; ! if(buffer && row < screen->rows && col < screen->cols) ! *new_cell = buffer[row * screen->cols + col]; ! else { ! new_cell->chars[0] = 0; ! new_cell->pen = screen->pen; ! } } } - vterm_allocator_free(screen->vt, buffer); - return new_buffer; } --- 86,103 ---- return screen->buffer + (screen->cols * row) + 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++) { ! clearcell(screen, &new_buffer[row * cols + col]); } } return new_buffer; } *************** *** 207,227 **** return 1; } static int moverect_internal(VTermRect dest, VTermRect src, void *user) { VTermScreen *screen = user; if(screen->callbacks && screen->callbacks->sb_pushline && ! dest.start_row == 0 && dest.start_col == 0 && // starts top-left corner ! dest.end_col == screen->cols && // full width ! screen->buffer == screen->buffers[0]) { // not altscreen ! VTermPos pos; ! for(pos.row = 0; pos.row < src.start_row; pos.row++) { ! for(pos.col = 0; pos.col < screen->cols; pos.col++) ! (void)vterm_screen_get_cell(screen, pos, screen->sb_buffer + pos.col); ! ! (screen->callbacks->sb_pushline)(screen->cols, screen->sb_buffer, screen->cbdata); ! } } { --- 203,229 ---- return 1; } + static void sb_pushline_from_row(VTermScreen *screen, int row) + { + VTermPos pos; + pos.row = row; + for(pos.col = 0; pos.col < screen->cols; pos.col++) + vterm_screen_get_cell(screen, pos, screen->sb_buffer + pos.col); + + (screen->callbacks->sb_pushline)(screen->cols, screen->sb_buffer, screen->cbdata); + } + static int moverect_internal(VTermRect dest, VTermRect src, void *user) { VTermScreen *screen = user; if(screen->callbacks && screen->callbacks->sb_pushline && ! dest.start_row == 0 && dest.start_col == 0 && // starts top-left corner ! dest.end_col == screen->cols && // full width ! screen->buffer == screen->buffers[BUFIDX_PRIMARY]) { // not altscreen ! int row; ! for(row = 0; row < src.start_row; row++) ! sb_pushline_from_row(screen, row); } { *************** *** 446,455 **** switch(prop) { case VTERM_PROP_ALTSCREEN: ! if(val->boolean && !screen->buffers[1]) return 0; ! screen->buffer = val->boolean ? screen->buffers[1] : screen->buffers[0]; // only send a damage event on disable; because during enable there's an // erase that sends a damage anyway if(!val->boolean) --- 448,457 ---- switch(prop) { case VTERM_PROP_ALTSCREEN: ! if(val->boolean && !screen->buffers[BUFIDX_ALTSCREEN]) return 0; ! screen->buffer = val->boolean ? screen->buffers[BUFIDX_ALTSCREEN] : screen->buffers[BUFIDX_PRIMARY]; // only send a damage event on disable; because during enable there's an // erase that sends a damage anyway if(!val->boolean) *************** *** 479,574 **** return 0; } ! static int resize(int new_rows, int new_cols, VTermPos *delta, void *user) { - VTermScreen *screen = user; - - int is_altscreen = (screen->buffers[1] && screen->buffer == screen->buffers[1]); - int old_rows = screen->rows; int old_cols = screen->cols; - int first_blank_row; ! if(!is_altscreen && new_rows < old_rows) { ! // Fewer rows - determine if we're going to scroll at all, and if so, push ! // those lines to scrollback ! VTermPos pos = { 0, 0 }; ! VTermPos cursor = screen->state->pos; ! // Find the first blank row after the cursor. ! for(pos.row = old_rows - 1; pos.row >= new_rows; pos.row--) ! if(!vterm_screen_is_eol(screen, pos) || cursor.row == pos.row) break; ! first_blank_row = pos.row + 1; ! if(first_blank_row > new_rows) { ! VTermRect rect = {0,0,0,0}; ! rect.end_row = old_rows; ! rect.end_col = old_cols; ! scrollrect(rect, first_blank_row - new_rows, 0, user); ! vterm_screen_flush_damage(screen); ! delta->row -= first_blank_row - new_rows; } } ! screen->buffers[0] = realloc_buffer(screen, screen->buffers[0], new_rows, new_cols); ! if(screen->buffers[1]) ! screen->buffers[1] = realloc_buffer(screen, screen->buffers[1], new_rows, new_cols); ! screen->buffer = is_altscreen ? screen->buffers[1] : screen->buffers[0]; ! screen->rows = new_rows; ! screen->cols = new_cols; ! vterm_allocator_free(screen->vt, screen->sb_buffer); ! screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols); if(new_cols > old_cols) { ! VTermRect rect; ! rect.start_row = 0; ! rect.end_row = old_rows; ! rect.start_col = old_cols; ! rect.end_col = new_cols; ! damagerect(screen, rect); } ! if(new_rows > old_rows) { ! if(!is_altscreen && screen->callbacks && screen->callbacks->sb_popline) { ! int rows = new_rows - old_rows; ! while(rows) { ! VTermRect rect = {0,0,0,0}; ! VTermPos pos = { 0, 0 }; ! if(!(screen->callbacks->sb_popline(screen->cols, screen->sb_buffer, screen->cbdata))) ! break; ! ! rect.end_row = screen->rows; ! rect.end_col = screen->cols; ! scrollrect(rect, -1, 0, user); ! ! for(pos.col = 0; pos.col < screen->cols; pos.col += screen->sb_buffer[pos.col].width) ! vterm_screen_set_cell(screen, pos, screen->sb_buffer + pos.col); ! rect.end_row = 1; ! damagerect(screen, rect); ! vterm_screen_flush_damage(screen); ! rows--; ! delta->row++; ! } ! } ! { ! VTermRect rect; ! rect.start_row = old_rows; ! rect.end_row = new_rows; ! rect.start_col = 0; ! rect.end_col = new_cols; ! damagerect(screen, rect); ! } } if(screen->callbacks && screen->callbacks->resize) return (*screen->callbacks->resize)(new_rows, new_cols, screen->cbdata); --- 481,630 ---- return 0; } ! static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new_cols, int active, VTermPos *delta) { int old_rows = screen->rows; int old_cols = screen->cols; ! ScreenCell *old_buffer = screen->buffers[bufidx]; ! ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols); ! ! /* Find the final row of old buffer content */ ! int old_row; ! int col; ! int new_row; ! ! for(old_row = old_rows - 1; old_row > 0; old_row--) { ! if(active && (old_row == screen->state->pos.row)) ! /* The line with the active cursor is never "blank" */ ! goto found_oldrow; ! for(col = 0; col < old_cols; col++) ! if(old_buffer[old_row * old_cols + col].chars[0]) ! /* This row is not blank */ ! goto found_oldrow; ! } ! old_row = 0; ! found_oldrow: ! ; ! ! new_row = new_rows - 1; ! ! 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]); ! ! old_row--; ! new_row--; ! } ! ! if(old_row >= 0 && bufidx == BUFIDX_PRIMARY) { ! /* Push spare lines to scrollback buffer */ ! int row; ! for(row = 0; row <= old_row; row++) ! sb_pushline_from_row(screen, row); ! if(delta) ! delta->row -= (old_row + 1); ! } ! if(new_row >= 0 && bufidx == BUFIDX_PRIMARY && ! screen->callbacks && screen->callbacks->sb_popline) { ! /* Try to backfill rows by popping scrollback buffer */ ! while(new_row >= 0) { ! VTermPos pos; ! if(!(screen->callbacks->sb_popline(old_cols, screen->sb_buffer, screen->cbdata))) break; ! pos.row = new_row; ! 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++) { ! dst->chars[i] = src->chars[i]; ! if(!src->chars[i]) ! break; ! } ! ! dst->pen.bold = src->attrs.bold; ! dst->pen.underline = src->attrs.underline; ! dst->pen.italic = src->attrs.italic; ! dst->pen.blink = src->attrs.blink; ! dst->pen.reverse = src->attrs.reverse ^ screen->global_reverse; ! dst->pen.strike = src->attrs.strike; ! dst->pen.font = src->attrs.font; ! ! dst->pen.fg = src->fg; ! dst->pen.bg = src->bg; ! ! if(src->width == 2 && pos.col < (new_cols-1)) ! (dst + 1)->chars[0] = (uint32_t) -1; ! } ! new_row--; ! if(delta) ! delta->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)); ! 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]); ! } ! } ! vterm_allocator_free(screen->vt, old_buffer); ! screen->buffers[bufidx] = new_buffer; ! return; ! /* REFLOW TODO: ! * Handle delta. Probably needs to be a full cursorpos that we edit ! */ ! } ! ! static int resize(int new_rows, int new_cols, VTermPos *delta, void *user) ! { ! VTermScreen *screen = user; ! ! int altscreen_active = (screen->buffers[BUFIDX_ALTSCREEN] && screen->buffer == screen->buffers[BUFIDX_ALTSCREEN]); ! ! int old_cols = screen->cols; if(new_cols > old_cols) { ! /* Ensure that ->sb_buffer is large enough for a new or and old row */ ! if(screen->sb_buffer) ! vterm_allocator_free(screen->vt, screen->sb_buffer); ! ! screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols); } ! resize_buffer(screen, 0, new_rows, new_cols, !altscreen_active, altscreen_active ? NULL : delta); ! if(screen->buffers[BUFIDX_ALTSCREEN]) ! resize_buffer(screen, 1, new_rows, new_cols, altscreen_active, altscreen_active ? delta : NULL); ! screen->buffer = altscreen_active ? screen->buffers[BUFIDX_ALTSCREEN] : screen->buffers[BUFIDX_PRIMARY]; ! screen->rows = new_rows; ! screen->cols = new_cols; ! if(new_cols <= old_cols) { ! if(screen->sb_buffer) ! vterm_allocator_free(screen->vt, screen->sb_buffer); ! screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols); } + /* TODO: Maaaaybe we can optimise this if there's no reflow happening */ + damagescreen(screen); + if(screen->callbacks && screen->callbacks->resize) return (*screen->callbacks->resize)(new_rows, new_cols, screen->cbdata); *************** *** 651,658 **** screen->callbacks = NULL; screen->cbdata = NULL; ! screen->buffers[0] = realloc_buffer(screen, NULL, rows, cols); ! screen->buffer = screen->buffers[0]; screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * cols); if (screen->buffer == NULL || screen->sb_buffer == NULL) { --- 707,716 ---- screen->callbacks = NULL; screen->cbdata = NULL; ! screen->buffers[BUFIDX_PRIMARY] = alloc_buffer(screen, rows, cols); ! ! screen->buffer = screen->buffers[BUFIDX_PRIMARY]; ! screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * cols); if (screen->buffer == NULL || screen->sb_buffer == NULL) { *************** *** 667,674 **** INTERNAL void vterm_screen_free(VTermScreen *screen) { ! vterm_allocator_free(screen->vt, screen->buffers[0]); ! vterm_allocator_free(screen->vt, screen->buffers[1]); vterm_allocator_free(screen->vt, screen->sb_buffer); vterm_allocator_free(screen->vt, screen); } --- 725,734 ---- INTERNAL void vterm_screen_free(VTermScreen *screen) { ! vterm_allocator_free(screen->vt, screen->buffers[BUFIDX_PRIMARY]); ! if(screen->buffers[BUFIDX_ALTSCREEN]) ! vterm_allocator_free(screen->vt, screen->buffers[BUFIDX_ALTSCREEN]); ! vterm_allocator_free(screen->vt, screen->sb_buffer); vterm_allocator_free(screen->vt, screen); } *************** *** 798,838 **** return 1; } - /* - * Copy external to internal representation of a screen cell - * static because it's only used internally for sb_popline during resize - */ - static int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell) - { - ScreenCell *intcell = getcell(screen, pos.row, pos.col); - int i; - - if(!intcell) - return 0; - - for(i = 0; ; i++) { - intcell->chars[i] = cell->chars[i]; - if(!cell->chars[i]) - break; - } - - intcell->pen.bold = cell->attrs.bold; - intcell->pen.underline = cell->attrs.underline; - intcell->pen.italic = cell->attrs.italic; - intcell->pen.blink = cell->attrs.blink; - intcell->pen.reverse = cell->attrs.reverse ^ screen->global_reverse; - intcell->pen.strike = cell->attrs.strike; - intcell->pen.font = cell->attrs.font; - - intcell->pen.fg = cell->fg; - intcell->pen.bg = cell->bg; - - if(cell->width == 2) - getcell(screen, pos.row, pos.col + 1)->chars[0] = (uint32_t)-1; - - return 1; - } - int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos) { // This cell is EOL if this and every cell to the right is black --- 858,863 ---- *************** *** 855,865 **** void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen) { ! if(!screen->buffers[1] && altscreen) { int rows, cols; vterm_get_size(screen->vt, &rows, &cols); ! screen->buffers[1] = realloc_buffer(screen, NULL, rows, cols); } } --- 880,890 ---- void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen) { ! if(!screen->buffers[BUFIDX_ALTSCREEN] && altscreen) { int rows, cols; vterm_get_size(screen->vt, &rows, &cols); ! screen->buffers[BUFIDX_ALTSCREEN] = alloc_buffer(screen, rows, cols); } } *** ../vim-8.2.0786/src/version.c 2020-05-17 22:33:49.943137285 +0200 --- src/version.c 2020-05-17 23:00:26.775030687 +0200 *************** *** 748,749 **** --- 748,751 ---- { /* Add new patch number below this line */ + /**/ + 787, /**/ -- I have a watch cat! Just break in and she'll watch. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///