aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/cmdexpand.c2
-rw-r--r--src/nvim/drawline.c40
-rw-r--r--src/nvim/drawscreen.c49
-rw-r--r--src/nvim/grid.c345
-rw-r--r--src/nvim/normal.c2
-rw-r--r--src/nvim/popupmenu.c2
-rw-r--r--src/nvim/statusline.c6
7 files changed, 200 insertions, 246 deletions
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c
index 290cc336b8..e5a97e28bb 100644
--- a/src/nvim/cmdexpand.c
+++ b/src/nvim/cmdexpand.c
@@ -608,7 +608,7 @@ static void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int m
grid_line_fill(clen, Columns, fillchar, attr);
- grid_line_flush(false);
+ grid_line_flush();
}
win_redraw_last_status(topframe);
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 9da421e79b..5baaa913b3 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -1825,7 +1825,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
|| (number_only && wlv.draw_state > WL_STC))
&& wlv.filler_todo <= 0) {
draw_virt_text(wp, buf, win_col_offset, &wlv.col, wp->w_p_rl ? -1 : grid->cols, wlv.row);
- grid_put_linebuf(grid, wlv.row, 0, wlv.col, -grid->cols, wp->w_p_rl, wp, bg_attr, false);
+ win_put_linebuf(wp, wlv.row, 0, wlv.col, -grid->cols, bg_attr, false);
// Pretend we have finished updating the window. Except when
// 'cursorcolumn' is set.
if (wp->w_p_cuc) {
@@ -2956,7 +2956,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
wp->w_p_rl ? -1 : grid->cols, 0, wp->w_p_rl);
}
draw_virt_text(wp, buf, win_col_offset, &wlv.col, wp->w_p_rl ? -1 : grid->cols, wlv.row);
- grid_put_linebuf(grid, wlv.row, 0, wlv.col, grid->cols, wp->w_p_rl, wp, bg_attr, false);
+ win_put_linebuf(wp, wlv.row, 0, wlv.col, grid->cols, bg_attr, false);
wlv.row++;
// Update w_cline_height and w_cline_folded if the cursor line was
@@ -3229,7 +3229,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
draw_virt_text(wp, buf, win_col_offset, &draw_col, wp->w_p_rl ? -1 : grid->cols, wlv.row);
}
- grid_put_linebuf(grid, wlv.row, 0, draw_col, grid->cols, wp->w_p_rl, wp, bg_attr, wrap);
+ win_put_linebuf(wp, wlv.row, 0, draw_col, grid->cols, bg_attr, wrap);
if (wrap) {
ScreenGrid *current_grid = grid;
int current_row = wlv.row, dummy_col = 0; // dummy_col unused
@@ -3297,3 +3297,37 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
xfree(wlv.saved_p_extra_free);
return wlv.row;
}
+
+static void win_put_linebuf(win_T *wp, int row, int coloff, int endcol, int clear_width,
+ int bg_attr, bool wrap)
+{
+ ScreenGrid *grid = &wp->w_grid;
+
+ // Take care of putting "<<<" on the first line for 'smoothscroll'.
+ if (row == 0 && wp->w_skipcol > 0
+ // do not overwrite the 'showbreak' text with "<<<"
+ && *get_showbreak_value(wp) == NUL
+ // do not overwrite the 'listchars' "precedes" text with "<<<"
+ && !(wp->w_p_list && wp->w_p_lcs_chars.prec != 0)) {
+ int off = 0;
+ if (wp->w_p_nu && wp->w_p_rnu) {
+ // do not overwrite the line number, change "123 text" to "123<<<xt".
+ while (off < grid->cols && ascii_isdigit(schar_get_ascii(linebuf_char[off]))) {
+ off++;
+ }
+ }
+
+ for (int i = 0; i < 3 && off < grid->cols; i++) {
+ if (off + 1 < grid->cols && linebuf_char[off + 1] == NUL) {
+ // When the first half of a double-width character is
+ // overwritten, change the second half to a space.
+ linebuf_char[off + 1] = schar_from_ascii(' ');
+ }
+ linebuf_char[off] = schar_from_ascii('<');
+ linebuf_attr[off] = HL_ATTR(HLF_AT);
+ off++;
+ }
+ }
+
+ grid_put_linebuf(grid, row, coloff, 0, endcol, clear_width, wp->w_p_rl, bg_attr, wrap, false);
+}
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index f65146fd16..06e4cd48e7 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -771,20 +771,20 @@ static void win_redr_border(win_T *wp)
if (adj[1]) {
grid_line_put_schar(icol + adj[3], chars[2], attrs[2]);
}
- grid_line_flush(false);
+ grid_line_flush();
}
for (int i = 0; i < irow; i++) {
if (adj[3]) {
grid_line_start(grid, i + adj[0]);
grid_line_put_schar(0, chars[7], attrs[7]);
- grid_line_flush(false);
+ grid_line_flush();
}
if (adj[1]) {
int ic = (i == 0 && !adj[0] && chars[2]) ? 2 : 3;
grid_line_start(grid, i + adj[0]);
grid_line_put_schar(icol + adj[3], chars[ic], attrs[ic]);
- grid_line_flush(false);
+ grid_line_flush();
}
}
@@ -807,7 +807,7 @@ static void win_redr_border(win_T *wp)
if (adj[1]) {
grid_line_put_schar(icol + adj[3], chars[4], attrs[4]);
}
- grid_line_flush(false);
+ grid_line_flush();
}
}
@@ -1098,7 +1098,7 @@ int showmode(void)
&& !(p_ch == 0 && !ui_has(kUIMessages))) {
grid_line_start(&msg_grid_adj, Rows - 1);
win_redr_ruler(ruler_win);
- grid_line_flush(false);
+ grid_line_flush();
}
redraw_cmdline = false;
@@ -1370,25 +1370,25 @@ static void draw_sep_connectors_win(win_T *wp)
bool bot_left = !(win_at_bottom || win_at_left);
bool bot_right = !(win_at_bottom || win_at_right);
- if (top_left || top_right) {
+ if (top_left) {
grid_line_start(&default_grid, wp->w_winrow - 1);
- if (top_left) {
- grid_line_put_schar(wp->w_wincol - 1, get_corner_sep_connector(wp, WC_TOP_LEFT), hl);
- }
- if (top_right) {
- grid_line_put_schar(W_ENDCOL(wp), get_corner_sep_connector(wp, WC_TOP_RIGHT), hl);
- }
- grid_line_flush(false);
+ grid_line_put_schar(wp->w_wincol - 1, get_corner_sep_connector(wp, WC_TOP_LEFT), hl);
+ grid_line_flush();
+ }
+ if (top_right) {
+ grid_line_start(&default_grid, wp->w_winrow - 1);
+ grid_line_put_schar(W_ENDCOL(wp), get_corner_sep_connector(wp, WC_TOP_RIGHT), hl);
+ grid_line_flush();
}
- if (bot_left || bot_right) {
+ if (bot_left) {
grid_line_start(&default_grid, W_ENDROW(wp));
- if (bot_left) {
- grid_line_put_schar(wp->w_wincol - 1, get_corner_sep_connector(wp, WC_BOTTOM_LEFT), hl);
- }
- if (bot_right) {
- grid_line_put_schar(W_ENDCOL(wp), get_corner_sep_connector(wp, WC_BOTTOM_RIGHT), hl);
- }
- grid_line_flush(false);
+ grid_line_put_schar(wp->w_wincol - 1, get_corner_sep_connector(wp, WC_BOTTOM_LEFT), hl);
+ grid_line_flush();
+ }
+ if (bot_right) {
+ grid_line_start(&default_grid, W_ENDROW(wp));
+ grid_line_put_schar(W_ENDCOL(wp), get_corner_sep_connector(wp, WC_BOTTOM_RIGHT), hl);
+ grid_line_flush();
}
}
@@ -2394,8 +2394,11 @@ static void win_update(win_T *wp, DecorProviders *providers)
int symbol = wp->w_p_fcs_chars.lastline;
// Last line isn't finished: Display "@@@" at the end.
- grid_fill(&wp->w_grid, wp->w_grid.rows - 1, wp->w_grid.rows,
- MAX(start_col, 0), wp->w_grid.cols, symbol, symbol, at_attr);
+ // TODO(bfredl): this display ">@@@" when ">" was a left-halve
+ // maybe "@@@@" is preferred when this happens.
+ grid_line_start(&wp->w_grid, wp->w_grid.rows - 1);
+ grid_line_fill(MAX(start_col, 0), wp->w_grid.cols, symbol, at_attr);
+ grid_line_flush();
set_empty_rows(wp, srow);
wp->w_botline = lnum;
} else {
diff --git a/src/nvim/grid.c b/src/nvim/grid.c
index da72054540..1d9cd80ec3 100644
--- a/src/nvim/grid.c
+++ b/src/nvim/grid.c
@@ -190,21 +190,16 @@ void grid_invalidate(ScreenGrid *grid)
(void)memset(grid->attrs, -1, sizeof(sattr_T) * (size_t)grid->rows * (size_t)grid->cols);
}
-bool grid_invalid_row(ScreenGrid *grid, int row)
+static bool grid_invalid_row(ScreenGrid *grid, int row)
{
return grid->attrs[grid->line_offset[row]] < 0;
}
-static int line_off2cells(schar_T *line, size_t off, size_t max_off)
-{
- return (off + 1 < max_off && line[off + 1] == 0) ? 2 : 1;
-}
-
/// Return number of display cells for char at grid->chars[off].
/// We make sure that the offset used is less than "max_off".
static int grid_off2cells(ScreenGrid *grid, size_t off, size_t max_off)
{
- return line_off2cells(grid->chars, off, max_off);
+ return (off + 1 < max_off && grid->chars[off + 1] == 0) ? 2 : 1;
}
/// Return true if the character at "row"/"col" on the screen is the left side
@@ -261,18 +256,12 @@ void grid_getbytes(ScreenGrid *grid, int row, int col, char *bytes, int *attrp)
schar_get(bytes, grid->chars[off]);
}
-static bool check_grid(ScreenGrid *grid, int row, int col)
-{
- grid_adjust(&grid, &row, &col);
- // Safety check. The check for negative row and column is to fix issue
- // vim/vim#4102. TODO(neovim): find out why row/col could be negative.
- if (grid->chars == NULL
- || row >= grid->rows || row < 0
- || col >= grid->cols || col < 0) {
- return false;
- }
- return true;
-}
+static ScreenGrid *grid_line_grid = NULL;
+static int grid_line_row = -1;
+static int grid_line_coloff = 0;
+static int grid_line_maxcol = 0;
+static int grid_line_first = INT_MAX;
+static int grid_line_last = 0;
/// put string 'text' on the window grid at position 'row' and 'col', with
/// attributes 'attr', and update contents of 'grid'
@@ -280,26 +269,32 @@ static bool check_grid(ScreenGrid *grid, int row, int col)
/// Note: only outputs within one row!
int grid_puts(ScreenGrid *grid, const char *text, int textlen, int row, int col, int attr)
{
- if (!check_grid(grid, row, col)) {
+ grid_line_start(grid, row);
+
+ // Safety check. The check for negative row and column is to fix issue
+ // vim/vim#4102. TODO(neovim): find out why row/col could be negative.
+ int off_col = grid_line_coloff + col;
+ if (grid_line_grid->chars == NULL
+ || grid_line_row >= grid_line_grid->rows || grid_line_row < 0
+ || off_col >= grid_line_grid->cols || off_col < 0) {
if (rdb_flags & RDB_INVALID) {
abort();
+ } else {
+ grid_line_grid = NULL;
+ return 0;
}
- return 0;
}
- grid_line_start(grid, row);
int len = grid_line_puts(col, text, textlen, attr);
- grid_line_flush(true);
+ if (grid_line_last > grid_line_first) {
+ // TODO(bfredl): this is bullshit. message.c should manage its own cursor movements
+ int col_pos = MIN(grid_line_coloff + grid_line_last, grid_line_grid->cols - 1);
+ ui_grid_cursor_goto(grid_line_grid->handle, grid_line_row, col_pos);
+ }
+ grid_line_flush();
return len;
}
-static ScreenGrid *grid_line_grid = NULL;
-static int grid_line_row = -1;
-static int grid_line_coloff = 0;
-static int grid_line_first = INT_MAX;
-static int grid_line_last = 0;
-static bool grid_line_was_invalid = false;
-
/// Start a group of grid_line_puts calls that builds a single grid line.
///
/// Must be matched with a grid_line_flush call before moving to
@@ -308,56 +303,46 @@ void grid_line_start(ScreenGrid *grid, int row)
{
int col = 0;
grid_adjust(&grid, &row, &col);
- assert(grid_line_row == -1);
+ assert(grid_line_grid == NULL);
grid_line_row = row;
grid_line_grid = grid;
grid_line_coloff = col;
- // TODO(bfredl): ugly hackaround, will be fixed in STAGE 2
- grid_line_was_invalid = grid != &default_grid && grid_invalid_row(grid, row);
+ grid_line_first = (int)linebuf_size;
+ grid_line_maxcol = grid->cols - grid_line_coloff;
+ grid_line_last = 0;
}
void grid_line_put_schar(int col, schar_T schar, int attr)
{
- assert(grid_line_row >= 0);
- ScreenGrid *grid = grid_line_grid;
+ assert(grid_line_grid);
- size_t off = grid->line_offset[grid_line_row] + (size_t)col;
- if (grid->attrs[off] != attr || grid->chars[off] != schar || rdb_flags & RDB_NODELTA) {
- grid->chars[off] = schar;
- grid->attrs[off] = attr;
+ linebuf_char[col] = schar;
+ linebuf_attr[col] = attr;
- grid_line_first = MIN(grid_line_first, col);
- // TODO(bfredl): Y U NO DOUBLEWIDTH?
- grid_line_last = MAX(grid_line_last, col + 1);
- }
- grid->vcols[off] = -1;
+ grid_line_first = MIN(grid_line_first, col);
+ // TODO(bfredl): Y U NO DOUBLEWIDTH?
+ grid_line_last = MAX(grid_line_last, col + 1);
+ linebuf_vcol[col] = -1;
}
/// like grid_puts(), but output "text[len]". When "len" is -1 output up to
/// a NUL.
int grid_line_puts(int col, const char *text, int textlen, int attr)
{
- size_t off;
const char *ptr = text;
int len = textlen;
int c;
- size_t max_off;
int u8cc[MAX_MCO];
- bool clear_next_cell = false;
int prev_c = 0; // previous Arabic character
int pc, nc, nc1;
int pcc[MAX_MCO];
- assert(grid_line_row >= 0);
- ScreenGrid *grid = grid_line_grid;
- int row = grid_line_row;
- col += grid_line_coloff;
+ assert(grid_line_grid);
- off = grid->line_offset[row] + (size_t)col;
int start_col = col;
- max_off = grid->line_offset[row] + (size_t)grid->cols;
- while (col < grid->cols
+ int max_col = grid_line_maxcol;
+ while (col < max_col
&& (len < 0 || (int)(ptr - text) < len)
&& *ptr != NUL) {
c = (unsigned char)(*ptr);
@@ -394,7 +379,7 @@ int grid_line_puts(int col, const char *text, int textlen, int attr)
} else {
prev_c = u8c;
}
- if (col + mbyte_cells > grid->cols) {
+ if (col + mbyte_cells > max_col) {
// Only 1 cell left, but character requires 2 cells:
// display a '>' in the last column to avoid wrapping. */
c = '>';
@@ -408,55 +393,29 @@ int grid_line_puts(int col, const char *text, int textlen, int attr)
// an edge case, treat it as such..
buf = schar_from_cc(u8c, u8cc);
- int need_redraw = grid->chars[off] != buf
- || (mbyte_cells == 2 && grid->chars[off + 1] != 0)
- || grid->attrs[off] != attr
- || exmode_active
- || rdb_flags & RDB_NODELTA;
-
- if (need_redraw) {
- // When at the end of the text and overwriting a two-cell
- // character with a one-cell character, need to clear the next
- // cell. Also when overwriting the left half of a two-cell char
- // with the right half of a two-cell char. Do this only once
- // (utf8_off2cells() may return 2 on the right half).
- if (clear_next_cell) {
- clear_next_cell = false;
- } else if ((len < 0 ? ptr[mbyte_blen] == NUL : ptr + mbyte_blen >= text + len)
- && ((mbyte_cells == 1
- && grid_off2cells(grid, off, max_off) > 1)
- || (mbyte_cells == 2
- && grid_off2cells(grid, off, max_off) == 1
- && grid_off2cells(grid, off + 1, max_off) > 1))) {
- clear_next_cell = true;
- }
-
- // When at the start of the text and overwriting the right half of a
- // two-cell character in the same grid, truncate that into a '>'.
- if (ptr == text && col > 0 && grid->chars[off] == 0) {
- grid->chars[off - 1] = schar_from_ascii('>');
- }
+ // When at the start of the text and overwriting the right half of a
+ // two-cell character in the same grid, truncate that into a '>'.
+ if (ptr == text && col > grid_line_first && col < grid_line_last
+ && linebuf_char[col] == 0) {
+ linebuf_char[col - 1] = schar_from_ascii('>');
+ }
- grid->chars[off] = buf;
- grid->attrs[off] = attr;
- grid->vcols[off] = -1;
- if (mbyte_cells == 2) {
- grid->chars[off + 1] = 0;
- grid->attrs[off + 1] = attr;
- grid->vcols[off + 1] = -1;
- }
- grid_line_first = MIN(grid_line_first, col);
- grid_line_last = MAX(grid_line_last, col + mbyte_cells);
+ linebuf_char[col] = buf;
+ linebuf_attr[col] = attr;
+ linebuf_vcol[col] = -1;
+ if (mbyte_cells == 2) {
+ linebuf_char[col + 1] = 0;
+ linebuf_attr[col + 1] = attr;
+ linebuf_vcol[col + 1] = -1;
}
- off += (size_t)mbyte_cells;
col += mbyte_cells;
ptr += mbyte_blen;
- if (clear_next_cell) {
- // This only happens at the end, display one space next.
- ptr = " ";
- len = -1;
- }
+ }
+
+ if (col > start_col) {
+ grid_line_first = MIN(grid_line_first, start_col);
+ grid_line_last = MAX(grid_line_last, col);
}
return col - start_col;
@@ -464,56 +423,30 @@ int grid_line_puts(int col, const char *text, int textlen, int attr)
void grid_line_fill(int start_col, int end_col, int c, int attr)
{
- ScreenGrid *grid = grid_line_grid;
- size_t lineoff = grid->line_offset[grid_line_row];
- start_col += grid_line_coloff;
- end_col += grid_line_coloff;
-
schar_T sc = schar_from_char(c);
for (int col = start_col; col < end_col; col++) {
- size_t off = lineoff + (size_t)col;
- if (grid->chars[off] != sc || grid->attrs[off] != attr || rdb_flags & RDB_NODELTA) {
- grid->chars[off] = sc;
- grid->attrs[off] = attr;
- grid_line_first = MIN(grid_line_first, col);
- grid_line_last = MAX(grid_line_last, col + 1);
- }
- grid->vcols[off] = -1;
+ linebuf_char[col] = sc;
+ linebuf_attr[col] = attr;
+ linebuf_vcol[col] = -1;
}
+ grid_line_first = MIN(grid_line_first, start_col);
+ grid_line_last = MAX(grid_line_last, end_col);
}
/// End a group of grid_line_puts calls and send the screen buffer to the UI layer.
-///
-/// @param set_cursor Move the visible cursor to the end of the changed region.
-/// This is a workaround for not yet refactored code paths
-/// and shouldn't be used in new code.
-void grid_line_flush(bool set_cursor)
+void grid_line_flush(void)
{
- assert(grid_line_row != -1);
- if (grid_line_first < grid_line_last) {
- // When drawing over the right half of a double-wide char clear out the
- // left half. Only needed in a terminal.
- if (grid_line_was_invalid && grid_line_first == 0) {
- // redraw the previous cell, make it empty
- grid_line_first = -1;
- }
- if (set_cursor) {
- ui_grid_cursor_goto(grid_line_grid->handle, grid_line_row,
- MIN(grid_line_last, grid_line_grid->cols - 1));
- }
- if (!grid_line_grid->throttled) {
- ui_line(grid_line_grid, grid_line_row, grid_line_first, grid_line_last,
- grid_line_last, 0, false);
- } else if (grid_line_grid->dirty_col) {
- if (grid_line_last > grid_line_grid->dirty_col[grid_line_row]) {
- grid_line_grid->dirty_col[grid_line_row] = grid_line_last;
- }
- }
- grid_line_first = INT_MAX;
- grid_line_last = 0;
- }
- grid_line_row = -1;
+ ScreenGrid *grid = grid_line_grid;
grid_line_grid = NULL;
+ if (!(grid_line_first < grid_line_last)) {
+ return;
+ }
+
+ int row = grid_line_row;
+
+ bool invalid_row = grid != &default_grid && grid_invalid_row(grid, row) && grid_line_first == 0;
+ grid_put_linebuf(grid, row, grid_line_coloff, grid_line_first, grid_line_last, grid_line_last,
+ false, 0, false, invalid_row);
}
/// Fill the grid from "start_row" to "end_row" (exclusive), from "start_col"
@@ -607,13 +540,14 @@ void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col, int
/// - the attributes are different
/// - the character is multi-byte and the next byte is different
/// - the character is two cells wide and the second cell differs.
-static int grid_char_needs_redraw(ScreenGrid *grid, size_t off_from, size_t off_to, int cols)
+static int grid_char_needs_redraw(ScreenGrid *grid, int col, size_t off_to, int cols)
{
return (cols > 0
- && ((linebuf_char[off_from] != grid->chars[off_to]
- || linebuf_attr[off_from] != grid->attrs[off_to]
- || (line_off2cells(linebuf_char, off_from, off_from + (size_t)cols) > 1
- && linebuf_char[off_from + 1] != grid->chars[off_to + 1]))
+ && ((linebuf_char[col] != grid->chars[off_to]
+ || linebuf_attr[col] != grid->attrs[off_to]
+ || (cols > 1 && linebuf_char[col + 1] == 0
+ && linebuf_char[col + 1] != grid->chars[off_to + 1]))
+ || exmode_active // TODO(bfredl): what in the actual fuck
|| rdb_flags & RDB_NODELTA));
}
@@ -623,30 +557,27 @@ static int grid_char_needs_redraw(ScreenGrid *grid, size_t off_from, size_t off_
/// "endcol" gives the columns where valid characters are.
/// "clear_width" is the width of the window. It's > 0 if the rest of the line
/// needs to be cleared, negative otherwise.
-/// "rlflag" is true in a rightleft window:
+/// "rl" is true for rightleft text, like a window with 'rightleft' option set
/// When true and "clear_width" > 0, clear columns 0 to "endcol"
/// When false and "clear_width" > 0, clear columns "endcol" to "clear_width"
/// If "wrap" is true, then hint to the UI that "row" contains a line
/// which has wrapped into the next row.
-void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int clear_width,
- int rlflag, win_T *wp, int bg_attr, bool wrap)
+void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int col, int endcol, int clear_width,
+ int rl, int bg_attr, bool wrap, bool invalid_row)
{
- int col = 0;
bool redraw_next; // redraw_this for next character
bool clear_next = false;
- bool topline = row == 0;
int char_cells; // 1: normal char
// 2: occupies two display cells
int start_dirty = -1, end_dirty = 0;
- assert(row < grid->rows);
+ assert(0 <= row && row < grid->rows);
// TODO(bfredl): check all callsites and eliminate
// Check for illegal col, just in case
if (endcol > grid->cols) {
endcol = grid->cols;
}
- const size_t max_off_from = (size_t)grid->cols;
grid_adjust(&grid, &row, &coloff);
// Safety check. Avoids clang warnings down the call stack.
@@ -655,45 +586,21 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle
return;
}
- size_t off_from = 0;
size_t off_to = grid->line_offset[row] + (size_t)coloff;
const size_t max_off_to = grid->line_offset[row] + (size_t)grid->cols;
- // Take care of putting "<<<" on the first line for 'smoothscroll'.
- if (topline && wp->w_skipcol > 0
- // do not overwrite the 'showbreak' text with "<<<"
- && *get_showbreak_value(wp) == NUL
- // do not overwrite the 'listchars' "precedes" text with "<<<"
- && !(wp->w_p_list && wp->w_p_lcs_chars.prec != 0)) {
- size_t off = 0;
- size_t skip = 0;
- if (wp->w_p_nu && wp->w_p_rnu) {
- // do not overwrite the line number, change "123 text" to
- // "123<<<xt".
- while (skip < max_off_from && ascii_isdigit(schar_get_ascii(linebuf_char[off]))) {
- off++;
- skip++;
- }
- }
-
- for (size_t i = 0; i < 3 && i + skip < max_off_from; i++) {
- if (line_off2cells(linebuf_char, off, max_off_from) > 1) {
- // When the first half of a double-width character is
- // overwritten, change the second half to a space.
- linebuf_char[off + 1] = schar_from_ascii(' ');
- }
- linebuf_char[off] = schar_from_ascii('<');
- linebuf_attr[off] = HL_ATTR(HLF_AT);
- off++;
- }
+ // When at the start of the text and overwriting the right half of a
+ // two-cell character in the same grid, truncate that into a '>'.
+ if (col > 0 && grid->chars[off_to + (size_t)col] == 0) {
+ linebuf_char[col - 1] = schar_from_ascii('>');
+ col--;
}
- if (rlflag) {
+ if (rl) {
// Clear rest first, because it's left of the text.
if (clear_width > 0) {
- while (col <= endcol && grid->chars[off_to] == schar_from_ascii(' ')
- && grid->attrs[off_to] == bg_attr) {
- off_to++;
+ while (col <= endcol && grid->chars[off_to + (size_t)col] == schar_from_ascii(' ')
+ && grid->attrs[off_to + (size_t)col] == bg_attr) {
col++;
}
if (col <= endcol) {
@@ -701,28 +608,26 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle
}
}
col = endcol + 1;
- off_to = grid->line_offset[row] + (size_t)col + (size_t)coloff;
- off_from += (size_t)col;
endcol = (clear_width > 0 ? clear_width : -clear_width);
}
if (bg_attr) {
- assert(off_from == (size_t)col);
for (int c = col; c < endcol; c++) {
linebuf_attr[c] = hl_combine_attr(bg_attr, linebuf_attr[c]);
}
}
- redraw_next = grid_char_needs_redraw(grid, off_from, off_to, endcol - col);
+ redraw_next = grid_char_needs_redraw(grid, col, (size_t)col + off_to, endcol - col);
while (col < endcol) {
char_cells = 1;
- if (col + 1 < endcol) {
- char_cells = line_off2cells(linebuf_char, off_from, max_off_from);
+ if (col + 1 < endcol && linebuf_char[col + 1] == 0) {
+ char_cells = 2;
}
bool redraw_this = redraw_next; // Does character need redraw?
- redraw_next = grid_char_needs_redraw(grid, off_from + (size_t)char_cells,
- off_to + (size_t)char_cells,
+ size_t off = (size_t)col + off_to;
+ redraw_next = grid_char_needs_redraw(grid, col + char_cells,
+ off + (size_t)char_cells,
endcol - col - char_cells);
if (redraw_this) {
@@ -737,53 +642,52 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle
// char over the left half of an existing one
if (col + char_cells == endcol
&& ((char_cells == 1
- && grid_off2cells(grid, off_to, max_off_to) > 1)
+ && grid_off2cells(grid, off, max_off_to) > 1)
|| (char_cells == 2
- && grid_off2cells(grid, off_to, max_off_to) == 1
- && grid_off2cells(grid, off_to + 1, max_off_to) > 1))) {
+ && grid_off2cells(grid, off, max_off_to) == 1
+ && grid_off2cells(grid, off + 1, max_off_to) > 1))) {
clear_next = true;
}
- grid->chars[off_to] = linebuf_char[off_from];
+ grid->chars[off] = linebuf_char[col];
if (char_cells == 2) {
- grid->chars[off_to + 1] = linebuf_char[off_from + 1];
+ grid->chars[off + 1] = linebuf_char[col + 1];
}
- grid->attrs[off_to] = linebuf_attr[off_from];
+ grid->attrs[off] = linebuf_attr[col];
// For simplicity set the attributes of second half of a
// double-wide character equal to the first half.
if (char_cells == 2) {
- grid->attrs[off_to + 1] = linebuf_attr[off_from];
+ grid->attrs[off + 1] = linebuf_attr[col];
}
}
- grid->vcols[off_to] = linebuf_vcol[off_from];
+ grid->vcols[off] = linebuf_vcol[col];
if (char_cells == 2) {
- grid->vcols[off_to + 1] = linebuf_vcol[off_from + 1];
+ grid->vcols[off + 1] = linebuf_vcol[col + 1];
}
- off_to += (size_t)char_cells;
- off_from += (size_t)char_cells;
col += char_cells;
}
if (clear_next) {
// Clear the second half of a double-wide character of which the left
// half was overwritten with a single-wide character.
- grid->chars[off_to] = schar_from_ascii(' ');
+ grid->chars[(size_t)col + off_to] = schar_from_ascii(' ');
end_dirty++;
}
int clear_end = -1;
- if (clear_width > 0 && !rlflag) {
+ if (clear_width > 0 && !rl) {
// blank out the rest of the line
// TODO(bfredl): we could cache winline widths
while (col < clear_width) {
- if (grid->chars[off_to] != schar_from_ascii(' ')
- || grid->attrs[off_to] != bg_attr
+ size_t off = (size_t)col + off_to;
+ if (grid->chars[off] != schar_from_ascii(' ')
+ || grid->attrs[off] != bg_attr
|| rdb_flags & RDB_NODELTA) {
- grid->chars[off_to] = schar_from_ascii(' ');
- grid->attrs[off_to] = bg_attr;
+ grid->chars[off] = schar_from_ascii(' ');
+ grid->attrs[off] = bg_attr;
if (start_dirty == -1) {
start_dirty = col;
end_dirty = col;
@@ -792,9 +696,8 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle
}
clear_end = col + 1;
}
- grid->vcols[off_to] = MAXCOL;
+ grid->vcols[off] = MAXCOL;
col++;
- off_to++;
}
}
@@ -805,8 +708,22 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle
start_dirty = end_dirty;
}
if (clear_end > start_dirty) {
- ui_line(grid, row, coloff + start_dirty, coloff + end_dirty, coloff + clear_end,
- bg_attr, wrap);
+ if (!grid->throttled) {
+ int start_pos = coloff + start_dirty;
+ // When drawing over the right half of a double-wide char clear out the
+ // left half. Only needed in a terminal.
+ if (invalid_row && start_pos == 0) {
+ start_pos = -1;
+ }
+ ui_line(grid, row, start_pos, coloff + end_dirty, coloff + clear_end,
+ bg_attr, wrap);
+ } else if (grid->dirty_col) {
+ // TODO(bfredl): really get rid of the extra psuedo terminal in message.c
+ // by using a linebuf_char copy for "throttled message line"
+ if (clear_end > grid->dirty_col[row]) {
+ grid->dirty_col[row] = clear_end;
+ }
+ }
}
}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index b6fe24a961..834204e5e1 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -2087,7 +2087,7 @@ static void display_showcmd(void)
// clear the rest of an old message by outputting up to SHOWCMD_COLS spaces
grid_line_puts(sc_col + len, (char *)" " + len, -1, HL_ATTR(HLF_MSG));
- grid_line_flush(false);
+ grid_line_flush();
}
/// When "check" is false, prepare for commands that scroll the window.
diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c
index 488c893bd8..3be2f4cd9f 100644
--- a/src/nvim/popupmenu.c
+++ b/src/nvim/popupmenu.c
@@ -655,7 +655,7 @@ void pum_redraw(void)
i >= thumb_pos && i < thumb_pos + thumb_height ? attr_thumb : attr_scroll);
}
}
- grid_line_flush(false);
+ grid_line_flush();
row++;
}
}
diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c
index bdc2e4a57e..407bf71417 100644
--- a/src/nvim/statusline.c
+++ b/src/nvim/statusline.c
@@ -171,7 +171,7 @@ void win_redr_status(win_T *wp)
}
}
- grid_line_flush(false);
+ grid_line_flush();
}
// May need to draw the character below the vertical separator.
@@ -449,7 +449,7 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
grid_line_fill(col, maxcol, fillchar, curattr);
if (!draw_ruler) {
- grid_line_flush(false);
+ grid_line_flush();
}
// Fill the tab_page_click_defs, w_status_click_defs or w_winbar_click_defs array for clicking
@@ -861,7 +861,7 @@ void draw_tabline(void)
};
}
- grid_line_flush(false);
+ grid_line_flush();
}
// Reset the flag here again, in case evaluating 'tabline' causes it to be