mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
refactor(grid): unify the two put-text-on-the-screen code paths
The screen grid refactors will continue until morale improves. Jokes aside, this is quite a central installment in the series. Before this refactor, there were two fundamentally distinct codepaths for getting some text on the screen: - the win_line() -> grid_put_linebuf() -> ui_line() call chain used for buffer text, with linebuf_char as a temporary scratch buffer - the grid_line_start/grid_line_puts/grid_line_flush() -> ui_line() path used for every thing else: statuslines, messages and the command line. Here the grid->chars[] array itself doubles as a scratch buffer. With this refactor, the later family of functions still exist, however they now as well render to linebuf_char just like win_line() did, and grid_put_linebuf() is called in the end to calculate delta changes. This means we don't need any duplicate logic for delta calculations anymore. Later down the line, it will be possible to share more logic operating on this scratch buffer, like doing 'rightleft' reversal and arabic shaping as a post-processing step.
This commit is contained in:
parent
af7d317f3f
commit
e33269578b
@ -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