aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/drawline.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/drawline.c')
-rw-r--r--src/nvim/drawline.c124
1 files changed, 84 insertions, 40 deletions
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 969021ef2c..8b4786a98e 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -106,6 +106,8 @@ typedef struct {
int c_extra; ///< extra chars, all the same
int c_final; ///< final char, mandatory if set
+ int n_closing; ///< number of chars in fdc which will be closing
+
bool extra_for_extmark; ///< n_extra set for inline virtual text
// saved "extra" items for when draw_state becomes WL_LINE (again)
@@ -136,8 +138,6 @@ typedef struct {
///< or w_skipcol or concealing
int skipped_cells; ///< nr of skipped cells for virtual text
///< to be added to wlv.vcol later
- bool more_virt_inline_chunks; ///< indicates if there is more inline virtual text
- ///< after n_extra
} winlinevars_T;
/// for line_putchar. Contains the state that needs to be remembered from
@@ -223,11 +223,11 @@ static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, b
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], ' ');
+ dest[c] = schar_from_ascii(' ');
}
goto done;
} else if ((uint8_t)(*p) < 0x80 && u8cc[0] == 0) {
- schar_from_ascii(dest[0], *p);
+ dest[0] = schar_from_ascii(*p);
s->prev_c = u8c;
} else {
if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c)) {
@@ -254,10 +254,10 @@ static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, b
} else {
s->prev_c = u8c;
}
- schar_from_cc(dest[0], u8c, u8cc);
+ dest[0] = schar_from_cc(u8c, u8cc);
}
if (cells > 1) {
- dest[1][0] = 0;
+ dest[1] = 0;
}
done:
s->p += c_len;
@@ -350,17 +350,17 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode,
max_col - col, false, vcol);
// If we failed to emit a char, we still need to put a space and advance.
if (cells < 1) {
- schar_from_ascii(linebuf_char[col], ' ');
+ linebuf_char[col] = schar_from_ascii(' ');
cells = 1;
}
for (int c = 0; c < cells; c++) {
linebuf_attr[col++] = attr;
}
- if (col < max_col && linebuf_char[col][0] == 0) {
+ if (col < max_col && linebuf_char[col] == 0) {
// If the left half of a double-width char is overwritten,
// change the right half to a space so that grid redraws properly,
// but don't advance the current column.
- schar_from_ascii(linebuf_char[col], ' ');
+ linebuf_char[col] = schar_from_ascii(' ');
}
vcol += cells;
}
@@ -386,7 +386,8 @@ static void handle_foldcolumn(win_T *wp, winlinevars_T *wlv)
// Allocate a buffer, "wlv->extra[]" may already be in use.
xfree(wlv->p_extra_free);
wlv->p_extra_free = xmalloc(MAX_MCO * (size_t)fdc + 1);
- wlv->n_extra = (int)fill_foldcolumn(wlv->p_extra_free, wp, wlv->foldinfo, wlv->lnum);
+ wlv->n_extra = (int)fill_foldcolumn(wlv->p_extra_free, wp, wlv->foldinfo, wlv->lnum,
+ &wlv->n_closing);
wlv->p_extra_free[wlv->n_extra] = NUL;
wlv->p_extra = wlv->p_extra_free;
wlv->c_extra = NUL;
@@ -407,7 +408,7 @@ static void handle_foldcolumn(win_T *wp, winlinevars_T *wlv)
///
/// Assume monocell characters
/// @return number of chars added to \param p
-size_t fill_foldcolumn(char *p, win_T *wp, foldinfo_T foldinfo, linenr_T lnum)
+size_t fill_foldcolumn(char *p, win_T *wp, foldinfo_T foldinfo, linenr_T lnum, int *n_closing)
{
int i = 0;
int level;
@@ -449,16 +450,23 @@ size_t fill_foldcolumn(char *p, win_T *wp, foldinfo_T foldinfo, linenr_T lnum)
}
}
+ int n_closing_val = i;
+
if (closed) {
if (symbol != 0) {
// rollback previous write
char_counter -= (size_t)len;
memset(&p[char_counter], ' ', (size_t)len);
+ n_closing_val--;
}
len = utf_char2bytes(wp->w_p_fcs_chars.foldclosed, &p[char_counter]);
char_counter += (size_t)len;
}
+ if (n_closing) {
+ *n_closing = n_closing_val;
+ }
+
return MAX(char_counter + (size_t)(fdc - i), (size_t)fdc);
}
@@ -868,10 +876,12 @@ static void apply_cursorline_highlight(win_T *wp, winlinevars_T *wlv)
}
}
-/// Checks if there is more inline virtual text that need to be drawn
-/// and sets has_more_virt_inline_chunks to reflect that.
+/// Checks if there is more inline virtual text that need to be drawn.
static bool has_more_inline_virt(winlinevars_T *wlv, ptrdiff_t v)
{
+ if (wlv->virt_inline_i < kv_size(wlv->virt_inline)) {
+ return true;
+ }
DecorState *state = &decor_state;
for (size_t i = 0; i < kv_size(state->active); i++) {
DecorRange *item = &kv_A(state->active, i);
@@ -911,7 +921,6 @@ static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t
break;
}
}
- wlv->more_virt_inline_chunks = has_more_inline_virt(wlv, v);
if (!kv_size(wlv->virt_inline)) {
// no more inline virtual text here
break;
@@ -929,11 +938,6 @@ static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t
wlv->c_final = NUL;
wlv->extra_attr = vtc.hl_id ? syn_id2attr(vtc.hl_id) : 0;
wlv->n_attr = mb_charlen(vtc.text);
-
- // Checks if there is more inline virtual text chunks that need to be drawn.
- wlv->more_virt_inline_chunks = has_more_inline_virt(wlv, v)
- || wlv->virt_inline_i < kv_size(wlv->virt_inline);
-
// If the text didn't reach until the first window
// column we need to skip cells.
if (wlv->skip_cells > 0) {
@@ -1147,8 +1151,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
bool saved_search_attr_from_match = false;
int win_col_offset = 0; // offset for window columns
+ bool area_active = false; // whether in Visual selection, for virtual text
+ bool decor_need_recheck = false; // call decor_recheck_draw_col() at next char
char buf_fold[FOLD_TEXT_LEN]; // Hold value returned by get_foldtext
+ VirtText fold_vt = VIRTTEXT_EMPTY;
// 'cursorlineopt' has "screenline" and cursor is in this line
bool cul_screenline = false;
@@ -1788,9 +1795,27 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
if (has_decor && wlv.n_extra == 0) {
- bool selected = (area_highlighting
- && ((wlv.vcol >= wlv.fromcol && wlv.vcol < wlv.tocol)
- || (noinvcur && wlv.vcol == wp->w_virtcol)));
+ // Duplicate the Visual area check after this block,
+ // but don't check inside p_extra here.
+ if (wlv.vcol == wlv.fromcol
+ || (wlv.vcol + 1 == wlv.fromcol
+ && (wlv.n_extra == 0 && utf_ptr2cells(ptr) > 1))
+ || (vcol_prev == fromcol_prev
+ && vcol_prev < wlv.vcol
+ && wlv.vcol < wlv.tocol)) {
+ area_active = true;
+ } else if (area_active
+ && (wlv.vcol == wlv.tocol
+ || (noinvcur && wlv.vcol == wp->w_virtcol))) {
+ area_active = false;
+ }
+
+ bool selected = (area_active || (area_highlighting && noinvcur
+ && wlv.vcol == wp->w_virtcol));
+ if (decor_need_recheck) {
+ decor_recheck_draw_col(wlv.off, selected, &decor_state);
+ decor_need_recheck = false;
+ }
extmark_attr = decor_redraw_col(wp, (colnr_T)v, wlv.off, selected, &decor_state);
if (!has_fold && wp->w_buffer->b_virt_text_inline > 0) {
@@ -1824,10 +1849,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
&& vcol_prev < wlv.vcol // not at margin
&& wlv.vcol < wlv.tocol)) {
*area_attr_p = vi_attr; // start highlighting
+ area_active = true;
} else if (*area_attr_p != 0
&& (wlv.vcol == wlv.tocol
|| (noinvcur && wlv.vcol == wp->w_virtcol))) {
*area_attr_p = 0; // stop highlighting
+ area_active = false;
}
if (!has_fold && wlv.n_extra == 0) {
@@ -1900,7 +1927,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
if (draw_folded && wlv.n_extra == 0 && wlv.col == win_col_offset) {
linenr_T lnume = lnum + foldinfo.fi_lines - 1;
memset(buf_fold, ' ', FOLD_TEXT_LEN);
- wlv.p_extra = get_foldtext(wp, lnum, lnume, foldinfo, buf_fold);
+ wlv.p_extra = get_foldtext(wp, lnum, lnume, foldinfo, buf_fold, &fold_vt);
wlv.n_extra = (int)strlen(wlv.p_extra);
if (wlv.p_extra != buf_fold) {
@@ -2720,7 +2747,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
wlv.col += n;
} else {
// Add a blank character to highlight.
- schar_from_ascii(linebuf_char[wlv.off], ' ');
+ linebuf_char[wlv.off] = schar_from_ascii(' ');
}
if (area_attr == 0 && !has_fold) {
// Use attributes from match with highest priority among
@@ -2822,7 +2849,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
int col_stride = wp->w_p_rl ? -1 : 1;
while (wp->w_p_rl ? wlv.col >= 0 : wlv.col < grid->cols) {
- schar_from_ascii(linebuf_char[wlv.off], ' ');
+ linebuf_char[wlv.off] = schar_from_ascii(' ');
linebuf_vcol[wlv.off] = MAXCOL;
wlv.col += col_stride;
if (draw_color_col) {
@@ -2856,7 +2883,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// logical line
int n = wp->w_p_rl ? -1 : 1;
while (wlv.col >= 0 && wlv.col < grid->cols) {
- schar_from_ascii(linebuf_char[wlv.off], ' ');
+ linebuf_char[wlv.off] = schar_from_ascii(' ');
linebuf_attr[wlv.off] = wlv.vcol >= TERM_ATTRS_MAX ? 0 : term_attrs[wlv.vcol];
linebuf_vcol[wlv.off] = wlv.vcol;
wlv.off += n;
@@ -2865,6 +2892,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
}
+ if (kv_size(fold_vt) > 0) {
+ draw_virt_text_item(buf, win_col_offset, fold_vt, kHlModeCombine, grid->cols, 0);
+ }
draw_virt_text(wp, buf, win_col_offset, &wlv.col, grid->cols, wlv.row);
grid_put_linebuf(grid, wlv.row, 0, wlv.col, grid->cols, wp->w_p_rl, wp, bg_attr, false);
wlv.row++;
@@ -2890,15 +2920,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
&& wlv.filler_todo <= 0
&& (wp->w_p_rl ? wlv.col == 0 : wlv.col == grid->cols - 1)
&& !has_fold) {
- if (*ptr == NUL && lcs_eol_one == 0 && has_decor) {
+ if (has_decor && *ptr == NUL && lcs_eol_one == 0) {
// Tricky: there might be a virtual text just _after_ the last char
decor_redraw_col(wp, (colnr_T)v, wlv.off, false, &decor_state);
- handle_inline_virtual_text(wp, &wlv, v);
}
if (*ptr != NUL
|| lcs_eol_one > 0
|| (wlv.n_extra > 0 && (wlv.c_extra != NUL || *wlv.p_extra != NUL))
- || wlv.more_virt_inline_chunks) {
+ || has_more_inline_virt(&wlv, v)) {
c = wp->w_p_lcs_chars.ext;
wlv.char_attr = win_hl_attr(wp, HLF_AT);
mb_c = c;
@@ -2954,9 +2983,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
wlv.col--;
}
if (mb_utf8) {
- schar_from_cc(linebuf_char[wlv.off], mb_c, u8cc);
+ linebuf_char[wlv.off] = schar_from_cc(mb_c, u8cc);
} else {
- schar_from_ascii(linebuf_char[wlv.off], (char)c);
+ linebuf_char[wlv.off] = schar_from_ascii((char)c);
}
if (multi_attr) {
linebuf_attr[wlv.off] = multi_attr;
@@ -2967,12 +2996,20 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
linebuf_vcol[wlv.off] = wlv.vcol;
+ if (wlv.draw_state == WL_FOLD) {
+ linebuf_vcol[wlv.off] = -2;
+ if (wlv.n_closing > 0) {
+ linebuf_vcol[wlv.off] = -3;
+ wlv.n_closing--;
+ }
+ }
+
if (utf_char2cells(mb_c) > 1) {
// Need to fill two screen columns.
wlv.off++;
wlv.col++;
// UTF-8: Put a 0 in the second screen char.
- linebuf_char[wlv.off][0] = 0;
+ linebuf_char[wlv.off] = 0;
linebuf_attr[wlv.off] = linebuf_attr[wlv.off - 1];
if (wlv.draw_state > WL_STC && wlv.filler_todo <= 0) {
wlv.vcol++;
@@ -3085,13 +3122,19 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
wlv.char_attr = saved_attr2;
}
- if ((wp->w_p_rl ? (wlv.col < 0) : (wlv.col >= grid->cols)) && has_decor) {
+ if (has_decor && wlv.filler_todo <= 0
+ && (wp->w_p_rl ? (wlv.col < 0) : (wlv.col >= grid->cols))) {
// At the end of screen line: might need to peek for decorations just after
- // this position. Without wrapping, we might need to display win_pos overlays
- // from the entire text line.
- colnr_T nextpos = wp->w_p_wrap ? (colnr_T)(ptr - line) : (colnr_T)strlen(line);
- decor_redraw_col(wp, nextpos, wlv.off, true, &decor_state);
- handle_inline_virtual_text(wp, &wlv, v);
+ // this position.
+ if (!has_fold && wp->w_p_wrap && wlv.n_extra == 0) {
+ decor_redraw_col(wp, (int)(ptr - line), -3, false, &decor_state);
+ // Check position/hiding of virtual text again on next screen line.
+ decor_need_recheck = true;
+ } else if (has_fold || !wp->w_p_wrap) {
+ // Without wrapping, we might need to display right_align and win_col
+ // virt_text for the entire text line.
+ decor_redraw_col(wp, MAXCOL, -1, true, &decor_state);
+ }
}
// At end of screen line and there is more to come: Display the line
@@ -3104,7 +3147,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
|| (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL
&& wlv.p_extra != at_end_str)
|| (wlv.n_extra != 0 && (wlv.c_extra != NUL || *wlv.p_extra != NUL))
- || wlv.more_virt_inline_chunks)) {
+ || has_more_inline_virt(&wlv, v))) {
bool wrap = wp->w_p_wrap // Wrapping enabled.
&& wlv.filler_todo <= 0 // Not drawing diff filler lines.
&& lcs_eol_one != -1 // Haven't printed the lcs_eol character.
@@ -3117,7 +3160,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
if (virt_line_offset >= 0) {
draw_virt_text_item(buf, virt_line_offset, kv_A(virt_lines, virt_line_index).line,
kHlModeReplace, grid->cols, 0);
- } else {
+ } else if (wlv.filler_todo <= 0) {
draw_virt_text(wp, buf, win_col_offset, &draw_col, grid->cols, wlv.row);
}
@@ -3186,6 +3229,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
} // for every character in the line
+ clear_virttext(&fold_vt);
kv_destroy(virt_lines);
xfree(wlv.p_extra_free);
xfree(wlv.saved_p_extra_free);