aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Linse <bjorn.linse@gmail.com>2018-11-03 14:40:22 +0100
committerBjörn Linse <bjorn.linse@gmail.com>2018-11-11 09:54:03 +0100
commit520ec3dbfd208c99f9b184ab0a4baeab9a93b556 (patch)
treea2322de3b3b5bde4eb9ba5157818d537c86db85f
parentf8639dc99cb085432b14da086af316176152bc1f (diff)
downloadrneovim-520ec3dbfd208c99f9b184ab0a4baeab9a93b556.tar.gz
rneovim-520ec3dbfd208c99f9b184ab0a4baeab9a93b556.tar.bz2
rneovim-520ec3dbfd208c99f9b184ab0a4baeab9a93b556.zip
UI/TUI: improvements and cleanups for scrolling and clearing
- TUI: _never_ rely on BCE for implicit clearing, only explicit commands. - TUI: use unibi_erase_chars when possible. - TUI: use end-exclusive ranges for invalid and cleared areas - screen: scrolling leaves scrolled in aree undefined. This is a conservative change, a client assuming the old semantics will still behave correctly. - screen: factor out vsep handling from line drawing. This is needed anyway for the multigrid refactor. - screen: simplifications of win_do_lines
-rw-r--r--runtime/doc/ui.txt8
-rw-r--r--src/nvim/message.c4
-rw-r--r--src/nvim/move.c4
-rw-r--r--src/nvim/screen.c99
-rw-r--r--src/nvim/tui/tui.c153
-rw-r--r--src/nvim/ugrid.c25
-rw-r--r--src/nvim/ugrid.h14
7 files changed, 136 insertions, 171 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/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..4b00fcf57c 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;
@@ -119,6 +120,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;
@@ -239,6 +241,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");
@@ -401,6 +404,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);
}
@@ -662,7 +666,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 +738,48 @@ 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;
+ HlAttrs attrs = kv_A(data->attrs, (size_t)attr_id);
+ update_attrs(ui, attrs);
// 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;
- }
+ // 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 +840,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 +872,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 +1030,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 +1044,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 +1065,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);
}
}
@@ -1107,7 +1106,7 @@ static void tui_default_colors_set(UI *ui, Integer rgb_fg, Integer rgb_bg,
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);
+ invalidate(ui, 0, data->grid.height, 0, data->grid.width);
}
static void tui_flush(UI *ui)
@@ -1129,11 +1128,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);
@@ -1219,7 +1234,7 @@ static void tui_option_set(UI *ui, String name, Object value)
ui->rgb = value.data.boolean;
data->print_attrs = HLATTRS_INVALID;
- invalidate(ui, 0, data->grid.height-1, 0, data->grid.width-1);
+ invalidate(ui, 0, data->grid.height, 0, data->grid.width);
}
}
@@ -1235,18 +1250,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 +1282,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)