mirror of
https://github.com/neovim/neovim.git
synced 2025-09-22 11:18:19 +00:00
feat(decorations): support virtual lines (for now: only one block at a time)
This commit is contained in:
@@ -1003,8 +1003,7 @@ static void win_update(win_T *wp, Providers *providers)
|
||||
i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1);
|
||||
// insert extra lines for previously invisible filler lines
|
||||
if (wp->w_lines[0].wl_lnum != wp->w_topline) {
|
||||
i += diff_check_fill(wp, wp->w_lines[0].wl_lnum)
|
||||
- wp->w_old_topfill;
|
||||
i += win_get_fill(wp, wp->w_lines[0].wl_lnum) - wp->w_old_topfill;
|
||||
}
|
||||
if (i != 0 && i < wp->w_grid.Rows - 2) { // less than a screen off
|
||||
// Try to insert the correct number of lines.
|
||||
@@ -1067,7 +1066,7 @@ static void win_update(win_T *wp, Providers *providers)
|
||||
if (wp->w_lines[0].wl_lnum == wp->w_topline) {
|
||||
row += wp->w_old_topfill;
|
||||
} else {
|
||||
row += diff_check_fill(wp, wp->w_topline);
|
||||
row += win_get_fill(wp, wp->w_topline);
|
||||
}
|
||||
// ... but don't delete new filler lines.
|
||||
row -= wp->w_topfill;
|
||||
@@ -1101,12 +1100,12 @@ static void win_update(win_T *wp, Providers *providers)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Correct the first entry for filler lines at the top
|
||||
* when it won't get updated below. */
|
||||
if (wp->w_p_diff && bot_start > 0) {
|
||||
wp->w_lines[0].wl_size =
|
||||
plines_win_nofill(wp, wp->w_topline, true)
|
||||
+ wp->w_topfill;
|
||||
|
||||
// Correct the first entry for filler lines at the top
|
||||
// when it won't get updated below.
|
||||
if (win_may_fill(wp) && bot_start > 0) {
|
||||
wp->w_lines[0].wl_size = (plines_win_nofill(wp, wp->w_topline, true)
|
||||
+ wp->w_topfill);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1564,7 +1563,7 @@ static void win_update(win_T *wp, Providers *providers)
|
||||
&& lnum > wp->w_topline
|
||||
&& !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
|
||||
&& srow + wp->w_lines[idx].wl_size > wp->w_grid.Rows
|
||||
&& diff_check_fill(wp, lnum) == 0) {
|
||||
&& win_get_fill(wp, lnum) == 0) {
|
||||
// This line is not going to fit. Don't draw anything here,
|
||||
// will draw "@ " lines below.
|
||||
row = wp->w_grid.Rows + 1;
|
||||
@@ -1664,7 +1663,7 @@ static void win_update(win_T *wp, Providers *providers)
|
||||
* Don't overwrite it, it can be edited.
|
||||
*/
|
||||
wp->w_botline = lnum + 1;
|
||||
} else if (diff_check_fill(wp, lnum) >= wp->w_grid.Rows - srow) {
|
||||
} else if (win_get_fill(wp, lnum) >= wp->w_grid.Rows - srow) {
|
||||
// Window ends in filler lines.
|
||||
wp->w_botline = lnum;
|
||||
wp->w_filler_rows = wp->w_grid.Rows - srow;
|
||||
@@ -1691,7 +1690,7 @@ static void win_update(win_T *wp, Providers *providers)
|
||||
} else {
|
||||
if (eof) { // we hit the end of the file
|
||||
wp->w_botline = buf->b_ml.ml_line_count + 1;
|
||||
j = diff_check_fill(wp, wp->w_botline);
|
||||
j = win_get_fill(wp, wp->w_botline);
|
||||
if (j > 0 && !wp->w_botfill) {
|
||||
// Display filler text below last line. win_line() will check
|
||||
// for ml_line_count+1 and only draw filler lines
|
||||
@@ -1866,7 +1865,7 @@ static int compute_foldcolumn(win_T *wp, int col)
|
||||
/// Put a single char from an UTF-8 buffer into a line buffer.
|
||||
///
|
||||
/// Handles composing chars and arabic shaping state.
|
||||
static int line_putchar(LineState *s, schar_T *dest, int maxcells, bool rl)
|
||||
static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, bool rl, int vcol)
|
||||
{
|
||||
const char_u *p = (char_u *)s->p;
|
||||
int cells = utf_ptr2cells(p);
|
||||
@@ -1876,7 +1875,13 @@ static int line_putchar(LineState *s, schar_T *dest, int maxcells, bool rl)
|
||||
return -1;
|
||||
}
|
||||
u8c = utfc_ptr2char(p, u8cc);
|
||||
if (*p < 0x80 && u8cc[0] == 0) {
|
||||
if (*p == TAB) {
|
||||
cells = MIN(tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array), maxcells);
|
||||
for (int c = 0; c < cells; c++) {
|
||||
schar_from_ascii(dest[c], ' ');
|
||||
}
|
||||
goto done;
|
||||
} else if (*p < 0x80 && u8cc[0] == 0) {
|
||||
schar_from_ascii(dest[0], *p);
|
||||
s->prev_c = u8c;
|
||||
} else {
|
||||
@@ -1909,6 +1914,7 @@ static int line_putchar(LineState *s, schar_T *dest, int maxcells, bool rl)
|
||||
if (cells > 1) {
|
||||
dest[1][0] = 0;
|
||||
}
|
||||
done:
|
||||
s->p += c_len;
|
||||
return cells;
|
||||
}
|
||||
@@ -2366,8 +2372,11 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
|
||||
filler_lines = 0;
|
||||
area_highlighting = true;
|
||||
}
|
||||
int virtual_lines = decor_virtual_lines(wp, lnum);
|
||||
filler_lines += virtual_lines;
|
||||
if (lnum == wp->w_topline) {
|
||||
filler_lines = wp->w_topfill;
|
||||
virtual_lines = MIN(virtual_lines, filler_lines);
|
||||
}
|
||||
filler_todo = filler_lines;
|
||||
|
||||
@@ -2895,7 +2904,18 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
|
||||
|
||||
if (draw_state == WL_SBR - 1 && n_extra == 0) {
|
||||
draw_state = WL_SBR;
|
||||
if (filler_todo > 0) {
|
||||
if (filler_todo > filler_lines - virtual_lines) {
|
||||
// TODO(bfredl): check this doesn't inhibit TUI-style
|
||||
// clear-to-end-of-line.
|
||||
c_extra = ' ';
|
||||
c_final = NUL;
|
||||
if (wp->w_p_rl) {
|
||||
n_extra = col + 1;
|
||||
} else {
|
||||
n_extra = grid->Columns - col;
|
||||
}
|
||||
char_attr = 0;
|
||||
} else if (filler_todo > 0) {
|
||||
// draw "deleted" diff line(s)
|
||||
if (char2cells(wp->w_p_fcs_chars.diff) > 1) {
|
||||
c_extra = '-';
|
||||
@@ -4402,7 +4422,19 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
|
||||
&& !wp->w_p_rl; // Not right-to-left.
|
||||
|
||||
int draw_col = col - boguscols;
|
||||
draw_virt_text(buf, win_col_offset, &draw_col, grid->Columns);
|
||||
if (filler_todo > 0) {
|
||||
int index = filler_todo - (filler_lines - virtual_lines);
|
||||
if (index > 0) {
|
||||
int fpos = kv_size(buf->b_virt_lines) - index;
|
||||
assert(fpos >= 0);
|
||||
int offset = buf->b_virt_line_leftcol ? 0 : win_col_offset;
|
||||
draw_virt_text_item(buf, offset, kv_A(buf->b_virt_lines, fpos),
|
||||
kHlModeReplace, grid->Columns, offset);
|
||||
}
|
||||
} else {
|
||||
draw_virt_text(buf, win_col_offset, &draw_col, grid->Columns);
|
||||
}
|
||||
|
||||
grid_put_linebuf(grid, row, 0, draw_col, grid->Columns, wp->w_p_rl,
|
||||
wp, wp->w_hl_attr_normal, wrap);
|
||||
if (wrap) {
|
||||
@@ -4485,69 +4517,82 @@ void draw_virt_text(buf_T *buf, int col_off, int *end_col, int max_col)
|
||||
bool do_eol = state->eol_col > -1;
|
||||
for (size_t i = 0; i < kv_size(state->active); i++) {
|
||||
DecorRange *item = &kv_A(state->active, i);
|
||||
if (item->start_row == state->row && kv_size(item->decor.virt_text)) {
|
||||
if (item->win_col == -1) {
|
||||
if (item->decor.virt_text_pos == kVTRightAlign) {
|
||||
right_pos -= item->decor.virt_text_width;
|
||||
item->win_col = right_pos;
|
||||
} else if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
|
||||
item->win_col = state->eol_col;
|
||||
state->eol_col += item->decor.virt_text_width;
|
||||
} else if (item->decor.virt_text_pos == kVTWinCol) {
|
||||
item->win_col = MAX(item->decor.col+col_off, 0);
|
||||
}
|
||||
}
|
||||
if (item->win_col < 0) {
|
||||
continue;
|
||||
}
|
||||
VirtText vt = item->decor.virt_text;
|
||||
HlMode hl_mode = item->decor.hl_mode;
|
||||
LineState s = LINE_STATE("");
|
||||
int virt_attr = 0;
|
||||
int col = item->win_col;
|
||||
size_t virt_pos = 0;
|
||||
item->win_col = -2; // deactivate
|
||||
|
||||
while (col < max_col) {
|
||||
if (!*s.p) {
|
||||
if (virt_pos >= kv_size(vt)) {
|
||||
break;
|
||||
}
|
||||
virt_attr = 0;
|
||||
do {
|
||||
s.p = kv_A(vt, virt_pos).text;
|
||||
int hl_id = kv_A(vt, virt_pos).hl_id;
|
||||
virt_attr = hl_combine_attr(virt_attr,
|
||||
hl_id > 0 ? syn_id2attr(hl_id) : 0);
|
||||
virt_pos++;
|
||||
} while (!s.p && virt_pos < kv_size(vt));
|
||||
if (!s.p) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
int attr;
|
||||
bool through = false;
|
||||
if (hl_mode == kHlModeCombine) {
|
||||
attr = hl_combine_attr(linebuf_attr[col], virt_attr);
|
||||
} else if (hl_mode == kHlModeBlend) {
|
||||
through = (*s.p == ' ');
|
||||
attr = hl_blend_attrs(linebuf_attr[col], virt_attr, &through);
|
||||
} else {
|
||||
attr = virt_attr;
|
||||
}
|
||||
schar_T dummy[2];
|
||||
int cells = line_putchar(&s, through ? dummy : &linebuf_char[col],
|
||||
max_col-col, false);
|
||||
linebuf_attr[col++] = attr;
|
||||
if (cells > 1) {
|
||||
linebuf_attr[col++] = attr;
|
||||
}
|
||||
}
|
||||
*end_col = MAX(*end_col, col);
|
||||
if (!(item->start_row == state->row && kv_size(item->decor.virt_text))) {
|
||||
continue;
|
||||
}
|
||||
if (item->win_col == -1) {
|
||||
if (item->decor.virt_text_pos == kVTRightAlign) {
|
||||
right_pos -= item->decor.virt_text_width;
|
||||
item->win_col = right_pos;
|
||||
} else if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
|
||||
item->win_col = state->eol_col;
|
||||
} else if (item->decor.virt_text_pos == kVTWinCol) {
|
||||
item->win_col = MAX(item->decor.col+col_off, 0);
|
||||
}
|
||||
}
|
||||
if (item->win_col < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int col = draw_virt_text_item(buf, item->win_col, item->decor.virt_text,
|
||||
item->decor.hl_mode, max_col, item->win_col-col_off);
|
||||
item->win_col = -2; // deactivate
|
||||
if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
|
||||
state->eol_col = col+1;
|
||||
}
|
||||
|
||||
*end_col = MAX(*end_col, col);
|
||||
}
|
||||
}
|
||||
|
||||
static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode,
|
||||
int max_col, int vcol)
|
||||
{
|
||||
LineState s = LINE_STATE("");
|
||||
int virt_attr = 0;
|
||||
size_t virt_pos = 0;
|
||||
|
||||
while (col < max_col) {
|
||||
if (!*s.p) {
|
||||
if (virt_pos >= kv_size(vt)) {
|
||||
break;
|
||||
}
|
||||
virt_attr = 0;
|
||||
do {
|
||||
s.p = kv_A(vt, virt_pos).text;
|
||||
int hl_id = kv_A(vt, virt_pos).hl_id;
|
||||
virt_attr = hl_combine_attr(virt_attr,
|
||||
hl_id > 0 ? syn_id2attr(hl_id) : 0);
|
||||
virt_pos++;
|
||||
} while (!s.p && virt_pos < kv_size(vt));
|
||||
if (!s.p) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
int attr;
|
||||
bool through = false;
|
||||
if (hl_mode == kHlModeCombine) {
|
||||
attr = hl_combine_attr(linebuf_attr[col], virt_attr);
|
||||
} else if (hl_mode == kHlModeBlend) {
|
||||
through = (*s.p == ' ');
|
||||
attr = hl_blend_attrs(linebuf_attr[col], virt_attr, &through);
|
||||
} else {
|
||||
attr = virt_attr;
|
||||
}
|
||||
schar_T dummy[2];
|
||||
int cells = line_putchar(buf, &s, through ? dummy : &linebuf_char[col],
|
||||
max_col-col, false, vcol);
|
||||
// if we failed to emit a char, we still need to advance
|
||||
cells = MAX(cells, 1);
|
||||
|
||||
for (int c = 0; c < cells; c++) {
|
||||
linebuf_attr[col++] = attr;
|
||||
}
|
||||
vcol += cells;
|
||||
}
|
||||
return col;
|
||||
}
|
||||
|
||||
/// Determine if dedicated window grid should be used or the default_grid
|
||||
///
|
||||
/// If UI did not request multigrid support, draw all windows on the
|
||||
@@ -5489,7 +5534,7 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
|
||||
ewp->w_p_crb = p_crb_save;
|
||||
|
||||
// Make all characters printable.
|
||||
p = (char_u *)transstr((const char *)buf);
|
||||
p = (char_u *)transstr((const char *)buf, true);
|
||||
len = STRLCPY(buf, p, sizeof(buf));
|
||||
len = (size_t)len < sizeof(buf) ? len : (int)sizeof(buf) - 1;
|
||||
xfree(p);
|
||||
|
Reference in New Issue
Block a user