aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/api/ui.c2
-rw-r--r--src/nvim/api/ui_events.in.h2
-rw-r--r--src/nvim/popupmnu.c2
-rw-r--r--src/nvim/screen.c47
-rw-r--r--src/nvim/tui/tui.c5
-rw-r--r--src/nvim/ui.c12
-rw-r--r--src/nvim/ui.h7
-rw-r--r--src/nvim/ui_bridge.c6
-rw-r--r--src/nvim/ui_compositor.c84
9 files changed, 99 insertions, 68 deletions
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 9d577db022..b77516d588 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -461,7 +461,7 @@ static void remote_ui_put(UI *ui, const char *cell)
static void remote_ui_raw_line(UI *ui, Integer grid, Integer row,
Integer startcol, Integer endcol,
Integer clearcol, Integer clearattr,
- Boolean wrap, const schar_T *chunk,
+ LineFlags flags, const schar_T *chunk,
const sattr_T *attrs)
{
UIData *data = ui->data;
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index 70f8b9d85c..ef3ff0f4c2 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -92,7 +92,7 @@ void grid_destroy(Integer grid)
// translate this in to the public grid_line format.
void raw_line(Integer grid, Integer row, Integer startcol,
Integer endcol, Integer clearcol, Integer clearattr,
- Boolean wrap, const schar_T *chunk, const sattr_T *attrs)
+ LineFlags flags, const schar_T *chunk, const sattr_T *attrs)
FUNC_API_NOEXPORT FUNC_API_COMPOSITOR_IMPL;
void event(char *name, Array args, bool *args_consumed)
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index 78b64621e9..d64406846a 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -363,7 +363,7 @@ void pum_redraw(void)
if (!pum_grid.chars
|| pum_grid.Rows != pum_height || pum_grid.Columns != grid_width) {
- grid_alloc(&pum_grid, pum_height, grid_width, !moved);
+ grid_alloc(&pum_grid, pum_height, grid_width, !moved, false);
ui_call_grid_resize(pum_grid.handle, pum_grid.Columns, pum_grid.Rows);
} else if (moved) {
grid_invalidate(&pum_grid);
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index b50333e7fa..7252289e0e 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -5316,7 +5316,7 @@ void grid_puts(ScreenGrid *grid, char_u *text, int row, int col, int attr)
}
static int put_dirty_row = -1;
-static int put_dirty_first = -1;
+static int put_dirty_first = INT_MAX;
static int put_dirty_last = 0;
/// Start a group of screen_puts_len calls that builds a single screen line.
@@ -5347,8 +5347,6 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row,
int prev_c = 0; /* previous Arabic character */
int pc, nc, nc1;
int pcc[MAX_MCO];
- int force_redraw_this;
- int force_redraw_next = FALSE;
int need_redraw;
bool do_flush = false;
@@ -5371,16 +5369,10 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row,
/* When drawing over the right halve of a double-wide char clear out the
* left halve. Only needed in a terminal. */
- if (col > 0 && col < grid->Columns && grid_fix_col(grid, col, row) != col) {
- schar_from_ascii(grid->chars[off - 1], ' ');
- grid->attrs[off - 1] = 0;
+ if (grid != &default_grid && col == 0 && grid_invalid_row(grid, row)) {
// redraw the previous cell, make it empty
- if (put_dirty_first == -1) {
- put_dirty_first = col-1;
- }
- put_dirty_last = col+1;
- // force the cell at "col" to be redrawn
- force_redraw_next = true;
+ put_dirty_first = -1;
+ put_dirty_last = MAX(put_dirty_last, 1);
}
max_off = grid->line_offset[row] + grid->Columns;
@@ -5428,15 +5420,12 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row,
schar_from_cc(buf, u8c, u8cc);
- force_redraw_this = force_redraw_next;
- force_redraw_next = FALSE;
-
need_redraw = schar_cmp(grid->chars[off], buf)
|| (mbyte_cells == 2 && grid->chars[off + 1][0] != 0)
|| grid->attrs[off] != attr
|| exmode_active;
- if (need_redraw || force_redraw_this) {
+ 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 halve of a two-cell char
@@ -5460,9 +5449,7 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row,
grid->chars[off + 1][0] = 0;
grid->attrs[off + 1] = attr;
}
- if (put_dirty_first == -1 || col < put_dirty_first) {
- put_dirty_first = col;
- }
+ put_dirty_first = MIN(put_dirty_first, col);
put_dirty_last = MAX(put_dirty_last, col+mbyte_cells);
}
@@ -5491,14 +5478,14 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row,
void grid_puts_line_flush(ScreenGrid *grid, bool set_cursor)
{
assert(put_dirty_row != -1);
- if (put_dirty_first != -1) {
+ if (put_dirty_first < put_dirty_last) {
if (set_cursor) {
ui_grid_cursor_goto(grid->handle, put_dirty_row,
MIN(put_dirty_last, grid->Columns-1));
}
ui_line(grid, put_dirty_row, put_dirty_first, put_dirty_last,
put_dirty_last, 0, false);
- put_dirty_first = -1;
+ put_dirty_first = INT_MAX;
put_dirty_last = 0;
}
put_dirty_row = -1;
@@ -5870,9 +5857,7 @@ void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col,
if (dirty_last > dirty_first) {
// TODO(bfredl): support a cleared suffix even with a batched line?
if (put_dirty_row == row) {
- if (put_dirty_first == -1 || dirty_first < put_dirty_first) {
- put_dirty_first = dirty_first;
- }
+ put_dirty_first = MIN(put_dirty_first, dirty_first);
put_dirty_last = MAX(put_dirty_last, dirty_last);
} else {
int last = c2 != ' ' ? dirty_last : dirty_first + (c1 != ' ');
@@ -5958,7 +5943,7 @@ void win_grid_alloc(win_T *wp)
|| grid->Rows != rows
|| grid->Columns != cols) {
if (want_allocation) {
- grid_alloc(grid, rows, cols, true);
+ grid_alloc(grid, rows, cols, true, true);
} else {
// Single grid mode, all rendering will be redirected to default_grid.
// Only keep track of the size and offset of the window.
@@ -6054,7 +6039,7 @@ retry:
// Continuing with the old arrays may result in a crash, because the
// size is wrong.
- grid_alloc(&default_grid, Rows, Columns, !doclear);
+ grid_alloc(&default_grid, Rows, Columns, !doclear, true);
StlClickDefinition *new_tab_page_click_defs = xcalloc(
(size_t)Columns, sizeof(*new_tab_page_click_defs));
@@ -6088,7 +6073,7 @@ retry:
}
}
-void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy)
+void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy, bool valid)
{
int new_row;
ScreenGrid new = *grid;
@@ -6106,7 +6091,7 @@ void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy)
new.line_offset[new_row] = new_row * new.Columns;
new.line_wraps[new_row] = false;
- grid_clear_line(&new, new.line_offset[new_row], columns, true);
+ grid_clear_line(&new, new.line_offset[new_row], columns, valid);
if (copy) {
// If the screen is not going to be cleared, copy as much as
@@ -6234,6 +6219,12 @@ void grid_invalidate(ScreenGrid *grid)
(void)memset(grid->attrs, -1, grid->Rows * grid->Columns * sizeof(sattr_T));
}
+bool grid_invalid_row(ScreenGrid *grid, int row)
+{
+ return grid->attrs[grid->line_offset[row]] < 0;
+}
+
+
/// Copy part of a grid line for vertically split window.
static void linecopy(ScreenGrid *grid, int to, int from, int col, int width)
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 2e26a75be1..a1a43c3e3a 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -1273,7 +1273,7 @@ static void tui_option_set(UI *ui, String name, Object value)
static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol,
Integer endcol, Integer clearcol, Integer clearattr,
- Boolean wrap, const schar_T *chunk,
+ LineFlags flags, const schar_T *chunk,
const sattr_T *attrs)
{
TUIData *data = ui->data;
@@ -1295,7 +1295,8 @@ static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol,
(int)clearattr);
}
- if (wrap && ui->width == grid->width && linerow + 1 < grid->height) {
+ if (flags & kLineFlagWrap && ui->width == grid->width
+ && linerow + 1 < grid->height) {
// Only do line wrapping if the grid width is equal to the terminal
// width and the line continuation is within the grid.
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 3dc6ccaf52..dd4eb0f196 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -315,11 +315,17 @@ void ui_set_ext_option(UI *ui, UIExtension ext, bool active)
void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol,
int clearattr, bool wrap)
{
+ LineFlags flags = wrap ? kLineFlagWrap : 0;
+ if (startcol == -1) {
+ startcol = 0;
+ flags |= kLineFlagInvalid;
+ }
+
size_t off = grid->line_offset[row] + (size_t)startcol;
- ui_call_raw_line(grid->handle, row, startcol, endcol,
- clearcol, clearattr, wrap, (const schar_T *)grid->chars + off,
- (const sattr_T *)grid->attrs + off);
+ ui_call_raw_line(grid->handle, row, startcol, endcol, clearcol, clearattr,
+ flags, (const schar_T *)grid->chars + off,
+ (const sattr_T *)grid->attrs + off);
if (p_wd) { // 'writedelay': flush & delay each time.
int old_row = cursor_row, old_col = cursor_col;
diff --git a/src/nvim/ui.h b/src/nvim/ui.h
index 8aeb632f6d..a5a0fa8b75 100644
--- a/src/nvim/ui.h
+++ b/src/nvim/ui.h
@@ -34,6 +34,13 @@ EXTERN const char *ui_ext_names[] INIT(= {
typedef struct ui_t UI;
+enum {
+ kLineFlagWrap = 1,
+ kLineFlagInvalid = 2,
+};
+
+typedef int LineFlags;
+
struct ui_t {
bool rgb;
bool composed;
diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c
index bd5d37be73..91cd458702 100644
--- a/src/nvim/ui_bridge.c
+++ b/src/nvim/ui_bridge.c
@@ -153,14 +153,14 @@ static void ui_bridge_raw_line_event(void **argv)
UI *ui = UI(argv[0]);
ui->raw_line(ui, PTR2INT(argv[1]), PTR2INT(argv[2]), PTR2INT(argv[3]),
PTR2INT(argv[4]), PTR2INT(argv[5]), PTR2INT(argv[6]),
- PTR2INT(argv[7]), argv[8], argv[9]);
+ (LineFlags)PTR2INT(argv[7]), argv[8], argv[9]);
xfree(argv[8]);
xfree(argv[9]);
}
static void ui_bridge_raw_line(UI *ui, Integer grid, Integer row,
Integer startcol, Integer endcol,
Integer clearcol, Integer clearattr,
- Boolean wrap, const schar_T *chunk,
+ LineFlags flags, const schar_T *chunk,
const sattr_T *attrs)
{
size_t ncol = (size_t)(endcol-startcol);
@@ -168,7 +168,7 @@ static void ui_bridge_raw_line(UI *ui, Integer grid, Integer row,
sattr_T *hl = xmemdup(attrs, ncol * sizeof(sattr_T));
UI_BRIDGE_CALL(ui, raw_line, 10, ui, INT2PTR(grid), INT2PTR(row),
INT2PTR(startcol), INT2PTR(endcol), INT2PTR(clearcol),
- INT2PTR(clearattr), INT2PTR(wrap), c, hl);
+ INT2PTR(clearattr), INT2PTR(flags), c, hl);
}
static void ui_bridge_suspend(UI *b)
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index 2ca0d1a6eb..9e0c44f3c2 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -217,8 +217,16 @@ static void ui_comp_grid_cursor_goto(UI *ui, Integer grid_handle,
/// do something more efficient (where efficiency means smaller deltas to
/// the downstream UI.)
static void compose_line(Integer row, Integer startcol, Integer endcol,
- bool wrap)
+ LineFlags flags)
{
+ // in case we start on the right half of a double-width char, we need to
+ // check the left half. But skip it in output if it wasn't doublewidth.
+ int skip = 0;
+ if (startcol > 0 && (flags & kLineFlagInvalid)) {
+ startcol--;
+ skip = 1;
+ }
+
int col = (int)startcol;
ScreenGrid *grid = NULL;
@@ -247,15 +255,37 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
+ (size_t)(col-grid->comp_col);
memcpy(linebuf+(col-startcol), grid->chars+off, n * sizeof(*linebuf));
memcpy(attrbuf+(col-startcol), grid->attrs+off, n * sizeof(*attrbuf));
+
+ // Tricky: if overlap caused a doublewidth char to get cut-off, must
+ // replace the visible half with a space.
+ if (linebuf[col-startcol][0] == NUL) {
+ linebuf[col-startcol][0] = ' ';
+ linebuf[col-startcol][1] = NUL;
+ } else if (n > 1 && linebuf[col-startcol+1][0] == NUL) {
+ skip = 0;
+ }
+ if (grid->comp_col+grid->Columns > until
+ && grid->chars[off+n][0] == NUL) {
+ linebuf[until-1-startcol][0] = ' ';
+ linebuf[until-1-startcol][1] = '\0';
+ if (col == startcol && n == 1) {
+ skip = 0;
+ }
+ }
col = until;
}
assert(endcol <= chk_width);
assert(row < chk_height);
- // TODO(bfredl): too conservative, need check
- // grid->line_wraps if grid->Width == Width
- wrap = wrap && grid && grid->handle == 1;
- ui_composed_call_raw_line(1, row, startcol, endcol, endcol, 0, wrap,
- (const schar_T *)linebuf, (const sattr_T *)attrbuf);
+
+ if (!(grid && grid == &default_grid)) {
+ // TODO(bfredl): too conservative, need check
+ // grid->line_wraps if grid->Width == Width
+ flags = flags & ~kLineFlagWrap;
+ }
+
+ ui_composed_call_raw_line(1, row, startcol+skip, endcol, endcol, 0, flags,
+ (const schar_T *)linebuf+skip,
+ (const sattr_T *)attrbuf+skip);
}
static void compose_area(Integer startrow, Integer endrow,
@@ -264,39 +294,35 @@ static void compose_area(Integer startrow, Integer endrow,
endrow = MIN(endrow, default_grid.Rows);
endcol = MIN(endcol, default_grid.Columns);
for (int r = (int)startrow; r < endrow; r++) {
- compose_line(r, startcol, endcol, false);
+ compose_line(r, startcol, endcol, kLineFlagInvalid);
}
}
-static void draw_line(ScreenGrid *grid, Integer row, Integer startcol,
- Integer endcol, Integer clearcol, Integer clearattr,
- bool wrap, const schar_T *chunk, const sattr_T *attrs)
-{
- row += grid->comp_row;
- startcol += grid->comp_col;
- endcol += grid->comp_col;
- clearcol += grid->comp_col;
- wrap = wrap && grid->handle == 1;
- assert(clearcol <= default_grid.Columns);
- if (kv_size(layers) > grid->comp_index+1) {
- compose_line(row, startcol, clearcol, wrap);
- } else {
- ui_composed_call_raw_line(1, row, startcol, endcol, clearcol, clearattr,
- wrap, chunk, attrs);
- }
-}
-
static void ui_comp_raw_line(UI *ui, Integer grid, Integer row,
Integer startcol, Integer endcol,
- Integer clearcol, Integer clearattr, bool wrap,
- const schar_T *chunk, const sattr_T *attrs)
+ Integer clearcol, Integer clearattr,
+ LineFlags flags, const schar_T *chunk,
+ const sattr_T *attrs)
{
if (!ui_comp_should_draw() || !ui_comp_set_grid((int)grid)) {
return;
}
- draw_line(curgrid, row, startcol, endcol, clearcol, clearattr, wrap, chunk,
- attrs);
+
+ row += curgrid->comp_row;
+ startcol += curgrid->comp_col;
+ endcol += curgrid->comp_col;
+ clearcol += curgrid->comp_col;
+ if (curgrid != &default_grid) {
+ flags = flags & ~kLineFlagWrap;
+ }
+ assert(clearcol <= default_grid.Columns);
+ if (flags & kLineFlagInvalid || kv_size(layers) > curgrid->comp_index+1) {
+ compose_line(row, startcol, clearcol, flags);
+ } else {
+ ui_composed_call_raw_line(1, row, startcol, endcol, clearcol, clearattr,
+ flags, chunk, attrs);
+ }
}
/// The screen is invalid and will soon be cleared