diff options
| -rw-r--r-- | runtime/doc/ui.txt | 8 | ||||
| -rw-r--r-- | src/nvim/highlight_defs.h | 11 | ||||
| -rw-r--r-- | src/nvim/message.c | 4 | ||||
| -rw-r--r-- | src/nvim/move.c | 4 | ||||
| -rw-r--r-- | src/nvim/screen.c | 99 | ||||
| -rw-r--r-- | src/nvim/tui/tui.c | 200 | ||||
| -rw-r--r-- | src/nvim/ugrid.c | 25 | ||||
| -rw-r--r-- | src/nvim/ugrid.h | 14 | 
8 files changed, 163 insertions, 202 deletions
diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt index 3477e53545..c021f236c8 100644 --- a/runtime/doc/ui.txt +++ b/runtime/doc/ui.txt @@ -325,14 +325,14 @@ numerical highlight `id`:s to the actual attributes.  		+-------------------------+ src_top    |  		| src (moved up) and dst  |            |  		|-------------------------| dst_bot    | -		| src (cleared)           |            | +		| src (invalid)           |            |  		+=========================+ src_bot  <  	If `rows` is less than zero, move a rectangle in the SR down, this can  	happen while scrolling up.  >  		+=========================+ src_top -		| src (cleared)           |            | +		| src (invalid)           |            |  		|------------------------ | dst_top    |  		| src (moved down) and dst|            |  		+-------------------------+ src_bot    | @@ -348,6 +348,10 @@ numerical highlight `id`:s to the actual attributes.  	end-exclusive, which is consistent with API conventions, but different  	from `set_scroll_region` which was end-inclusive. +	The scrolled-in area will be filled using |ui-event-grid_line| directly +	after the scroll event. The UI thus doesn't need to clear this area as +	part of handling the scroll event. +  ==============================================================================  Legacy Grid Events (cell based)					   *ui-grid-old* diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h index 09d20c75ea..0790793c94 100644 --- a/src/nvim/highlight_defs.h +++ b/src/nvim/highlight_defs.h @@ -37,17 +37,6 @@ typedef struct attr_entry {    .cterm_bg_color = 0, \  } -// sentinel value that compares unequal to any valid highlight -#define HLATTRS_INVALID (HlAttrs) { \ -  .rgb_ae_attr = -1, \ -  .cterm_ae_attr = -1, \ -  .rgb_fg_color = -1, \ -  .rgb_bg_color = -1, \ -  .rgb_sp_color = -1, \ -  .cterm_fg_color = 0, \ -  .cterm_bg_color = 0, \ -} -  /// Values for index in highlight_attr[].  /// When making changes, also update hlf_names below!  typedef enum { diff --git a/src/nvim/message.c b/src/nvim/message.c index edce30e6fa..10f4905fb2 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1896,6 +1896,9 @@ static void msg_scroll_up(void)    } else {      screen_del_lines(0, 1, (int)Rows, 0, Columns);    } +  // TODO(bfredl): when msgsep display is properly batched, this fill should be +  // eliminated. +  screen_fill(Rows-1, Rows, 0, (int)Columns, ' ', ' ', 0);  }  /* @@ -2311,6 +2314,7 @@ static int do_more_prompt(int typed_char)            if (toscroll == -1                && screen_ins_lines(0, 1, (int)Rows, 0, (int)Columns) == OK) { +            screen_fill(0, 1, 0, (int)Columns, ' ', ' ', 0);              // display line at top              (void)disp_sb_line(0, mp);            } else { diff --git a/src/nvim/move.c b/src/nvim/move.c index bddcefc8ec..3a29851ee6 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -918,9 +918,9 @@ void curs_columns(      extra = ((int)prev_skipcol - (int)curwin->w_skipcol) / width;      if (extra > 0) { -      win_ins_lines(curwin, 0, extra, false); +      win_ins_lines(curwin, 0, extra);      } else if (extra < 0) { -      win_del_lines(curwin, 0, -extra, false); +      win_del_lines(curwin, 0, -extra);      }    } else {      curwin->w_skipcol = 0; diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 46aa771a89..d1453b56d2 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -888,10 +888,7 @@ static void win_update(win_T *wp)            // Try to insert the correct number of lines.            // If not the last window, delete the lines at the bottom.            // win_ins_lines may fail when the terminal can't do it. -          if (i > 0) { -            check_for_delay(false); -          } -          if (win_ins_lines(wp, 0, i, false) == OK) { +          if (win_ins_lines(wp, 0, i) == OK) {              if (wp->w_lines_valid != 0) {                /* Need to update rows that are new, stop at the                 * first one that scrolled down. */ @@ -949,8 +946,7 @@ static void win_update(win_T *wp)          /* ... but don't delete new filler lines. */          row -= wp->w_topfill;          if (row > 0) { -          check_for_delay(false); -          if (win_del_lines(wp, 0, row, false) == OK) { +          if (win_del_lines(wp, 0, row) == OK) {              bot_start = wp->w_height - row;            } else {              mid_start = 0;                      // redraw all lines @@ -1305,8 +1301,7 @@ static void win_update(win_T *wp)              if (row - xtra_rows >= wp->w_height - 2) {                mod_bot = MAXLNUM;              } else { -              check_for_delay(false); -              if (win_del_lines(wp, row, -xtra_rows, false) == FAIL) { +              if (win_del_lines(wp, row, -xtra_rows) == FAIL) {                  mod_bot = MAXLNUM;                } else {                    bot_start = wp->w_height + xtra_rows; @@ -1319,8 +1314,7 @@ static void win_update(win_T *wp)              if (row + xtra_rows >= wp->w_height - 2) {                mod_bot = MAXLNUM;              } else { -              check_for_delay(false); -              if (win_ins_lines(wp, row + old_rows, xtra_rows, false) == FAIL) { +              if (win_ins_lines(wp, row + old_rows, xtra_rows) == FAIL) {                  mod_bot = MAXLNUM;                } else if (top_end > row + old_rows) {                  // Scrolled the part at the top that requires @@ -1513,8 +1507,7 @@ static void win_update(win_T *wp)        wp->w_botline = lnum;      }    } else { -    draw_vsep_win(wp, row); -    if (eof) {                  /* we hit the end of the file */ +    if (eof) {  // we hit the end of the file        wp->w_botline = buf->b_ml.ml_line_count + 1;        j = diff_check_fill(wp, wp->w_botline);        if (j > 0 && !wp->w_botfill) { @@ -1538,6 +1531,10 @@ static void win_update(win_T *wp)      win_draw_end(wp, fill_eob, ' ', row, wp->w_height, HLF_EOB);    } +  if (wp->w_redr_type >= REDRAW_TOP) { +    draw_vsep_win(wp, 0); +  } +    /* Reset the type of redrawing required, the window has been updated. */    wp->w_redr_type = 0;    wp->w_old_topfill = wp->w_topfill; @@ -4262,7 +4259,6 @@ win_line (            && filler_todo <= 0            ) {          win_draw_end(wp, '@', ' ', row, wp->w_height, HLF_AT); -        draw_vsep_win(wp, row);          row = endrow;        } @@ -4348,7 +4344,6 @@ static void screen_line(int row, int coloff, int endcol, int clear_width,    unsigned max_off_from;    unsigned max_off_to;    int col = 0; -  int hl;    bool redraw_this;                         // Does character need redraw?    bool redraw_next;                         // redraw_this for next character    bool clear_next = false; @@ -4474,24 +4469,10 @@ static void screen_line(int row, int coloff, int endcol, int clear_width,      }    } -  if (clear_width > 0) { -    // For a window that's left of another, draw the separator char. -    if (col + coloff < Columns && wp->w_vsep_width > 0) { -      int c = fillchar_vsep(wp, &hl); -      schar_T sc; -      schar_from_char(sc, c); - -      if (schar_cmp(ScreenLines[off_to], sc) -          || ScreenAttrs[off_to] != hl) { -        schar_copy(ScreenLines[off_to], sc); -        ScreenAttrs[off_to] = hl; -        if (start_dirty == -1) { -          start_dirty = col; -        } -        end_dirty = col+1; -      } -    } else -      LineWraps[row] = FALSE; +  if (clear_width > 0 || wp->w_width != Columns) { +    // If we cleared after the end of the line, it did not wrap. +    // For vsplit, line wrapping is not possible. +    LineWraps[row] = false;    }    if (clear_end < end_dirty) { @@ -6071,10 +6052,10 @@ static void screenclear2(void)      return;    } -  /* blank out ScreenLines */ -  for (i = 0; i < Rows; ++i) { -    lineclear(LineOffset[i], (int)Columns); -    LineWraps[i] = FALSE; +  // blank out ScreenLines +  for (i = 0; i < Rows; i++) { +    lineclear(LineOffset[i], (int)Columns, true); +    LineWraps[i] = false;    }    ui_call_grid_clear(1);  // clear the display @@ -6098,12 +6079,13 @@ static void screenclear2(void)  /*   * Clear one line in ScreenLines.   */ -static void lineclear(unsigned off, int width) +static void lineclear(unsigned off, int width, bool valid)  {    for (int col = 0; col < width; col++) {      schar_from_ascii(ScreenLines[off + col], ' ');    } -  (void)memset(ScreenAttrs + off, 0, (size_t)width * sizeof(sattr_T)); +  int fill = valid ? 0 : -1; +  (void)memset(ScreenAttrs + off, fill, (size_t)width * sizeof(sattr_T));  }  /// Copy part of a Screenline for vertically split window. @@ -6139,53 +6121,36 @@ void setcursor(void)  }  /// Insert 'line_count' lines at 'row' in window 'wp'. -/// If 'invalid' is TRUE the wp->w_lines[].wl_lnum is invalidated. -/// If 'mayclear' is TRUE the screen will be cleared if it is faster than -/// scrolling.  /// Returns FAIL if the lines are not inserted, OK for success. -int win_ins_lines(win_T *wp, int row, int line_count, int invalid) +int win_ins_lines(win_T *wp, int row, int line_count)  { -  if (wp->w_height < 5) { -    return FAIL; -  } - -  return win_do_lines(wp, row, line_count, invalid, false); +  return win_do_lines(wp, row, line_count, false);  }  /// Delete "line_count" window lines at "row" in window "wp". -/// If "invalid" is TRUE curwin->w_lines[] is invalidated. -/// If "mayclear" is TRUE the screen will be cleared if it is faster than -/// scrolling  /// Return OK for success, FAIL if the lines are not deleted. -int win_del_lines(win_T *wp, int row, int line_count, int invalid) +int win_del_lines(win_T *wp, int row, int line_count)  { -  return win_do_lines(wp, row, line_count, invalid, true); +  return win_do_lines(wp, row, line_count, true);  }  // Common code for win_ins_lines() and win_del_lines().  // Returns OK or FAIL when the work has been done. -static int win_do_lines(win_T *wp, int row, int line_count, -                        int invalid, int del) +static int win_do_lines(win_T *wp, int row, int line_count, int del)  { -  if (invalid) { -    wp->w_lines_valid = 0; -  } -    if (!redrawing() || line_count <= 0) {      return FAIL;    } -  // Delete all remaining lines +  // No lines are being moved, just draw over the entire area    if (row + line_count >= wp->w_height) { -    screen_fill(wp->w_winrow + row, wp->w_winrow + wp->w_height, -                wp->w_wincol, W_ENDCOL(wp), -                ' ', ' ', 0);      return OK;    }    // when scrolling, the message on the command line should be cleared,    // otherwise it will stay there forever. -  clear_cmdline = TRUE; +  check_for_delay(false); +  clear_cmdline = true;    int retval;    if (del) { @@ -6237,7 +6202,7 @@ int screen_ins_lines(int row, int line_count, int end, int col, int width)          linecopy(j + line_count, j, col, width);        }        j += line_count; -      lineclear(LineOffset[j] + col, width); +      lineclear(LineOffset[j] + col, width, false);        LineWraps[j] = false;      } else {        j = end - 1 - i; @@ -6248,7 +6213,7 @@ int screen_ins_lines(int row, int line_count, int end, int col, int width)        }        LineOffset[j + line_count] = temp;        LineWraps[j + line_count] = false; -      lineclear(temp, (int)Columns); +      lineclear(temp, (int)Columns, false);      }    } @@ -6283,7 +6248,7 @@ int screen_del_lines(int row, int line_count, int end, int col, int width)          linecopy(j - line_count, j, col, width);        }        j -= line_count; -      lineclear(LineOffset[j] + col, width); +      lineclear(LineOffset[j] + col, width, false);        LineWraps[j] = false;      } else {        // whole width, moving the line pointers is faster @@ -6295,7 +6260,7 @@ int screen_del_lines(int row, int line_count, int end, int col, int width)        }        LineOffset[j - line_count] = temp;        LineWraps[j - line_count] = false; -      lineclear(temp, (int)Columns); +      lineclear(temp, (int)Columns, false);      }    } diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index fc7d31edb0..b6986b77e9 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -94,6 +94,7 @@ typedef struct {    bool can_change_scroll_region;    bool can_set_lr_margin;    bool can_set_left_right_margin; +  bool can_erase_chars;    bool immediate_wrap_after_last_column;    bool bce;    bool mouse_enabled; @@ -103,7 +104,8 @@ typedef struct {    cursorentry_T cursor_shapes[SHAPE_IDX_COUNT];    HlAttrs clear_attrs;    kvec_t(HlAttrs) attrs; -  HlAttrs print_attrs; +  int print_attr_id; +  bool has_bg;    bool default_attr;    ModeShape showing_mode;    struct { @@ -119,6 +121,7 @@ typedef struct {      int set_cursor_style, reset_cursor_style;      int enter_undercurl_mode, exit_undercurl_mode, set_underline_color;    } unibi_ext; +  char *space_buf;  } TUIData;  static bool volatile got_winch = false; @@ -184,6 +187,7 @@ static void terminfo_start(UI *ui)    data->scroll_region_is_full_screen = true;    data->bufpos = 0;    data->default_attr = false; +  data->has_bg = false;    data->is_invisible = true;    data->busy = false;    data->cork = false; @@ -239,6 +243,7 @@ static void terminfo_start(UI *ui)    data->can_set_left_right_margin =      !!unibi_get_str(data->ut, unibi_set_left_margin_parm)      && !!unibi_get_str(data->ut, unibi_set_right_margin_parm); +  data->can_erase_chars = !!unibi_get_str(data->ut, unibi_erase_chars);    data->immediate_wrap_after_last_column =      terminfo_is_term_family(term, "cygwin")      || terminfo_is_term_family(term, "interix"); @@ -302,7 +307,7 @@ static void terminfo_stop(UI *ui)  static void tui_terminal_start(UI *ui)  {    TUIData *data = ui->data; -  data->print_attrs = HLATTRS_INVALID; +  data->print_attr_id = -1;    ugrid_init(&data->grid);    terminfo_start(ui);    update_size(ui); @@ -401,6 +406,7 @@ static void tui_main(UIBridgeData *bridge, UI *ui)    loop_close(&tui_loop, false);    kv_destroy(data->invalid_regions);    kv_destroy(data->attrs); +  xfree(data->space_buf);    xfree(data);  } @@ -435,8 +441,17 @@ static void sigwinch_cb(SignalWatcher *watcher, int signum, void *data)    ui_schedule_refresh();  } -static bool attrs_differ(HlAttrs a1, HlAttrs a2, bool rgb) +static bool attrs_differ(UI *ui, int id1, int id2, bool rgb)  { +  TUIData *data = ui->data; +  if (id1 == id2) { +    return false; +  } else if (id1 < 0 || id2 < 0) { +    return true; +  } +  HlAttrs a1 = kv_A(data->attrs, (size_t)id1); +  HlAttrs a2 = kv_A(data->attrs, (size_t)id2); +    if (rgb) {      return a1.rgb_fg_color != a2.rgb_fg_color        || a1.rgb_bg_color != a2.rgb_bg_color @@ -451,21 +466,16 @@ static bool attrs_differ(HlAttrs a1, HlAttrs a2, bool rgb)    }  } -static bool no_bg(UI *ui, HlAttrs attrs) -{ -  return  ui->rgb ? attrs.rgb_bg_color == -1 -                  : attrs.cterm_bg_color == 0; -} - -static void update_attrs(UI *ui, HlAttrs attrs) +static void update_attrs(UI *ui, int attr_id)  {    TUIData *data = ui->data; -  if (!attrs_differ(attrs, data->print_attrs, ui->rgb)) { +  if (!attrs_differ(ui, attr_id, data->print_attr_id, ui->rgb)) { +    data->print_attr_id = attr_id;      return;    } - -  data->print_attrs = attrs; +  data->print_attr_id = attr_id; +  HlAttrs attrs = kv_A(data->attrs, (size_t)attr_id);    int fg = ui->rgb ? attrs.rgb_fg_color : (attrs.cterm_fg_color - 1);    if (fg == -1) { @@ -479,6 +489,8 @@ static void update_attrs(UI *ui, HlAttrs attrs)                   : (data->clear_attrs.cterm_bg_color - 1);    } +  data->has_bg = bg != -1; +    int attr = ui->rgb ? attrs.rgb_ae_attr : attrs.cterm_ae_attr;    bool bold = attr & HL_BOLD;    bool italic = attr & HL_ITALIC; @@ -595,7 +607,7 @@ static void print_cell(UI *ui, UCell *ptr)      // Printing the next character finally advances the cursor.      final_column_wrap(ui);    } -  update_attrs(ui, kv_A(data->attrs, ptr->attr)); +  update_attrs(ui, ptr->attr);    out(ui, ptr->data, strlen(ptr->data));    grid->col++;    if (data->immediate_wrap_after_last_column) { @@ -611,8 +623,8 @@ static bool cheap_to_print(UI *ui, int row, int col, int next)    UCell *cell = grid->cells[row] + col;    while (next) {      next--; -    if (attrs_differ(kv_A(data->attrs, cell->attr), -                     data->print_attrs, ui->rgb)) { +    if (attrs_differ(ui, cell->attr, +                     data->print_attr_id, ui->rgb)) {        if (data->default_attr) {          return false;        } @@ -662,7 +674,7 @@ static void cursor_goto(UI *ui, int row, int col)        int n = col - grid->col;        if (n <= (row == grid->row ? 4 : 2)            && cheap_to_print(ui, grid->row, grid->col, n)) { -        UGRID_FOREACH_CELL(grid, grid->row, grid->row, grid->col, col - 1, { +        UGRID_FOREACH_CELL(grid, grid->row, grid->col, col, {            print_cell(ui, cell);          });        } @@ -734,50 +746,47 @@ safe_move:  }  static void clear_region(UI *ui, int top, int bot, int left, int right, -                         HlAttrs attrs) +                         int attr_id)  {    TUIData *data = ui->data;    UGrid *grid = &data->grid; -  bool cleared = false; +  update_attrs(ui, attr_id);    // non-BCE terminals can't clear with non-default background color -  bool can_clear = data->bce || no_bg(ui, attrs); - -  if (can_clear && right == ui->width -1) { -    // Background is set to the default color and the right edge matches the -    // screen end, try to use terminal codes for clearing the requested area. -    update_attrs(ui, attrs); -    if (left == 0) { -      if (bot == ui->height - 1) { -        if (top == 0) { -          unibi_out(ui, unibi_clear_screen); -          ugrid_goto(&data->grid, top, left); -        } else { -          cursor_goto(ui, top, 0); -          unibi_out(ui, unibi_clr_eos); -        } -        cleared = true; -      } +  bool can_clear = data->bce || !data->has_bg; + +  // Background is set to the default color and the right edge matches the +  // screen end, try to use terminal codes for clearing the requested area. +  if (can_clear && left == 0 && right == ui->width && bot == ui->height) { +    if (top == 0) { +      unibi_out(ui, unibi_clear_screen); +      ugrid_goto(&data->grid, top, left); +    } else { +      cursor_goto(ui, top, 0); +      unibi_out(ui, unibi_clr_eos);      } +  } else { +    int width = right-left; -    if (!cleared) { -      // iterate through each line and clear with clr_eol -      for (int row = top; row <= bot; row++) { -        cursor_goto(ui, row, left); +    // iterate through each line and clear +    for (int row = top; row < bot; row++) { +      cursor_goto(ui, row, left); +      if (can_clear && right == ui->width) {          unibi_out(ui, unibi_clr_eol); +      } else if (data->can_erase_chars && can_clear && width >= 5) { +        UNIBI_SET_NUM_VAR(data->params[0], width); +        unibi_out(ui, unibi_erase_chars); +      } else { +        out(ui, data->space_buf, (size_t)width); +        grid->col += width; +        if (data->immediate_wrap_after_last_column) { +          // Printing at the right margin immediately advances the cursor. +          final_column_wrap(ui); +        }        } -      cleared = true;      }    } - -  if (!cleared) { -    // could not clear using faster terminal codes, refresh the whole region -    UGRID_FOREACH_CELL(grid, top, bot, left, right, { -      cursor_goto(ui, row, col); -      print_cell(ui, cell); -    }); -  }  }  static void set_scroll_region(UI *ui, int top, int bot, int left, int right) @@ -838,12 +847,16 @@ static void tui_grid_resize(UI *ui, Integer g, Integer width, Integer height)    UGrid *grid = &data->grid;    ugrid_resize(grid, (int)width, (int)height); +  xfree(data->space_buf); +  data->space_buf = xmalloc((size_t)width * sizeof(*data->space_buf)); +  memset(data->space_buf, ' ', (size_t)width); +    // resize might not always be followed by a clear before flush    // so clip the invalid region    for (size_t i = 0; i < kv_size(data->invalid_regions); i++) {      Rect *r = &kv_A(data->invalid_regions, i); -    r->bot = MIN(r->bot, grid->height-1); -    r->right = MIN(r->right, grid->width-1); +    r->bot = MIN(r->bot, grid->height); +    r->right = MIN(r->right, grid->width);    }    if (!got_winch) {  // Try to resize the terminal window. @@ -866,8 +879,7 @@ static void tui_grid_clear(UI *ui, Integer g)    UGrid *grid = &data->grid;    ugrid_clear(grid);    kv_size(data->invalid_regions) = 0; -  clear_region(ui, 0, grid->height-1, 0, grid->width-1, -               data->clear_attrs); +  clear_region(ui, 0, grid->height, 0, grid->width, 0);  }  static void tui_grid_cursor_goto(UI *ui, Integer grid, Integer row, Integer col) @@ -1025,9 +1037,7 @@ static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, Integer endrow,    data->scroll_region_is_full_screen = fullwidth          && top == 0 && bot == ui->height-1; -  int clear_top, clear_bot; -  ugrid_scroll(grid, top, bot, left, right, (int)rows, -               &clear_top, &clear_bot); +  ugrid_scroll(grid, top, bot, left, right, (int)rows);    bool can_scroll = data->scroll_region_is_full_screen                      || (data->can_change_scroll_region @@ -1041,8 +1051,6 @@ static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, Integer endrow,        set_scroll_region(ui, top, bot, left, right);      }      cursor_goto(ui, top, left); -    // also set default color attributes or some terminals can become funny -    update_attrs(ui, data->clear_attrs);      if (rows > 0) {        if (rows == 1) { @@ -1064,16 +1072,14 @@ static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, Integer endrow,      if (!data->scroll_region_is_full_screen) {        reset_scroll_region(ui, fullwidth);      } - -    if (!(data->bce || no_bg(ui, data->clear_attrs))) { -      // Scrolling will leave wrong background in the cleared area on non-BCE -      // terminals. Update the cleared area. -      clear_region(ui, clear_top, clear_bot, left, right, -                   data->clear_attrs); -    }    } else { -    // Mark the entire scroll region as invalid for redrawing later -    invalidate(ui, top, bot, left, right); +    // Mark the moved region as invalid for redrawing later +    if (rows > 0) { +      endrow = endrow - rows; +    } else { +      startrow = startrow - rows; +    } +    invalidate(ui, (int)startrow, (int)endrow, (int)startcol, (int)endcol);    }  } @@ -1106,8 +1112,8 @@ static void tui_default_colors_set(UI *ui, Integer rgb_fg, Integer rgb_bg,    data->clear_attrs.cterm_fg_color = (int)cterm_fg;    data->clear_attrs.cterm_bg_color = (int)cterm_bg; -  data->print_attrs = HLATTRS_INVALID; -  invalidate(ui, 0, data->grid.height-1, 0, data->grid.width-1); +  data->print_attr_id = -1; +  invalidate(ui, 0, data->grid.height, 0, data->grid.width);  }  static void tui_flush(UI *ui) @@ -1129,11 +1135,27 @@ static void tui_flush(UI *ui)    while (kv_size(data->invalid_regions)) {      Rect r = kv_pop(data->invalid_regions); -    assert(r.bot < grid->height && r.right < grid->width); -    UGRID_FOREACH_CELL(grid, r.top, r.bot, r.left, r.right, { -      cursor_goto(ui, row, col); -      print_cell(ui, cell); -    }); +    assert(r.bot <= grid->height && r.right <= grid->width); + +    for (int row = r.top; row < r.bot; row++) { +      int clear_attr = grid->cells[row][r.right-1].attr; +      int clear_col; +      for (clear_col = r.right; clear_col > 0; clear_col--) { +        UCell *cell = &grid->cells[row][clear_col-1]; +        if (!(cell->data[0] == ' ' && cell->data[1] == NUL +              && cell->attr == clear_attr)) { +          break; +        } +      } + +      UGRID_FOREACH_CELL(grid, row, r.left, clear_col, { +        cursor_goto(ui, row, col); +        print_cell(ui, cell); +      }); +      if (clear_col < r.right) { +        clear_region(ui, row, row+1, clear_col, r.right, clear_attr); +      } +    }    }    cursor_goto(ui, data->row, data->col); @@ -1218,8 +1240,8 @@ static void tui_option_set(UI *ui, String name, Object value)    if (strequal(name.data, "termguicolors")) {      ui->rgb = value.data.boolean; -    data->print_attrs = HLATTRS_INVALID; -    invalidate(ui, 0, data->grid.height-1, 0, data->grid.width-1); +    data->print_attr_id = -1; +    invalidate(ui, 0, data->grid.height, 0, data->grid.width);    }  } @@ -1235,18 +1257,16 @@ static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol,      assert((size_t)attrs[c-startcol] < kv_size(data->attrs));      grid->cells[linerow][c].attr = attrs[c-startcol];    } -  UGRID_FOREACH_CELL(grid, (int)linerow, (int)linerow, (int)startcol, -                     (int)endcol-1, { -    cursor_goto(ui, row, col); +  UGRID_FOREACH_CELL(grid, (int)linerow, (int)startcol, (int)endcol, { +    cursor_goto(ui, (int)linerow, col);      print_cell(ui, cell);    });    if (clearcol > endcol) { -    HlAttrs cl_attrs = kv_A(data->attrs, (size_t)clearattr);      ugrid_clear_chunk(grid, (int)linerow, (int)endcol, (int)clearcol,                        (sattr_T)clearattr); -    clear_region(ui, (int)linerow, (int)linerow, (int)endcol, (int)clearcol-1, -                 cl_attrs); +    clear_region(ui, (int)linerow, (int)linerow+1, (int)endcol, (int)clearcol, +                 (int)clearattr);    }    if (wrap && ui->width == grid->width && linerow + 1 < grid->height) { @@ -1269,27 +1289,17 @@ static void invalidate(UI *ui, int top, int bot, int left, int right)  {    TUIData *data = ui->data;    Rect *intersects = NULL; -  // Increase dimensions before comparing to ensure adjacent regions are -  // treated as intersecting -  --top; -  ++bot; -  --left; -  ++right;    for (size_t i = 0; i < kv_size(data->invalid_regions); i++) {      Rect *r = &kv_A(data->invalid_regions, i); -    if (!(top > r->bot || bot < r->top -          || left > r->right || right < r->left)) { +    // adjacent regions are treated as overlapping +    if (!(top > r->bot || bot < r->top) +        && !(left > r->right || right < r->left)) {        intersects = r;        break;      }    } -  ++top; -  --bot; -  ++left; -  --right; -    if (intersects) {      // If top/bot/left/right intersects with a invalid rect, we replace it      // by the union diff --git a/src/nvim/ugrid.c b/src/nvim/ugrid.c index b741a61d8c..f5bd35a48e 100644 --- a/src/nvim/ugrid.c +++ b/src/nvim/ugrid.c @@ -52,8 +52,7 @@ void ugrid_goto(UGrid *grid, int row, int col)    grid->col = col;  } -void ugrid_scroll(UGrid *grid, int top, int bot, int left, int right, -                  int count, int *clear_top, int *clear_bot) +void ugrid_scroll(UGrid *grid, int top, int bot, int left, int right, int count)  {    // Compute start/stop/step for the loop below    int start, stop, step; @@ -76,26 +75,18 @@ void ugrid_scroll(UGrid *grid, int top, int bot, int left, int right,      memcpy(target_row, source_row,             sizeof(UCell) * (size_t)(right - left + 1));    } - -  // clear cells in the emptied region, -  if (count > 0) { -    *clear_top = stop; -    *clear_bot = stop + count - 1; -  } else { -    *clear_bot = stop; -    *clear_top = stop + count + 1; -  } -  clear_region(grid, *clear_top, *clear_bot, left, right, 0);  }  static void clear_region(UGrid *grid, int top, int bot, int left, int right,                           sattr_T attr)  { -  UGRID_FOREACH_CELL(grid, top, bot, left, right, { -    cell->data[0] = ' '; -    cell->data[1] = 0; -    cell->attr = attr; -  }); +  for (int row = top; row <= bot; row++) { +    UGRID_FOREACH_CELL(grid, row, left, right+1, { +      cell->data[0] = ' '; +      cell->data[1] = 0; +      cell->attr = attr; +    }); +  }  }  static void destroy_cells(UGrid *grid) diff --git a/src/nvim/ugrid.h b/src/nvim/ugrid.h index af78fe91c5..33a706b8c0 100644 --- a/src/nvim/ugrid.h +++ b/src/nvim/ugrid.h @@ -22,15 +22,13 @@ struct ugrid {  // -V:UGRID_FOREACH_CELL:625 -#define UGRID_FOREACH_CELL(grid, top, bot, left, right, code) \ +#define UGRID_FOREACH_CELL(grid, row, startcol, endcol, code) \    do { \ -    for (int row = top; row <= bot; row++) { \ -      UCell *row_cells = (grid)->cells[row]; \ -      for (int col = left; col <= right; col++) { \ -        UCell *cell = row_cells + col; \ -        (void)(cell); \ -        code; \ -      } \ +    UCell *row_cells = (grid)->cells[row]; \ +    for (int col = startcol; col < endcol; col++) { \ +      UCell *cell = row_cells + col; \ +      (void)(cell); \ +      code; \      } \    } while (0)  | 
