mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #25395 from bfredl/line_buf2
refactor(grid): unify the two put-text-on-the-screen code paths
This commit is contained in:
commit
dd872cbb44
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 (bot_left || bot_right) {
|
||||
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) {
|
||||
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 {
|
||||
|
347
src/nvim/grid.c
347
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('>');
|
||||
}
|
||||
|
||||
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);
|
||||
// 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('>');
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user