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.c208
1 files changed, 176 insertions, 32 deletions
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 67086b3248..510731a438 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -98,6 +98,7 @@ typedef struct {
int char_attr; ///< attributes for next character
int n_extra; ///< number of extra bytes
+ int n_attr; ///< chars with special attr
char *p_extra; ///< string of extra chars, plus NUL, only used
///< when c_extra and c_final are NUL
char *p_extra_free; ///< p_extra buffer that needs to be freed
@@ -105,9 +106,12 @@ typedef struct {
int c_extra; ///< extra chars, all the same
int c_final; ///< final char, mandatory if set
+ bool extra_for_extmark;
+
// saved "extra" items for when draw_state becomes WL_LINE (again)
int saved_n_extra;
char *saved_p_extra;
+ bool saved_extra_for_extmark;
int saved_c_extra;
int saved_c_final;
int saved_char_attr;
@@ -120,6 +124,14 @@ typedef struct {
int filler_lines; ///< nr of filler lines to be drawn
int filler_todo; ///< nr of filler lines still to do + 1
SignTextAttrs sattrs[SIGN_SHOW_MAX]; ///< sign attributes for the sign column
+
+ VirtText virt_inline;
+ size_t virt_inline_i;
+
+ bool reset_extra_attr;
+
+ int skip_cells; // nr of cells to skip for virtual text
+ int skipped_cells; // nr of skipped virtual text cells
} winlinevars_T;
/// for line_putchar. Contains the state that needs to be remembered from
@@ -851,6 +863,73 @@ static void apply_cursorline_highlight(win_T *wp, winlinevars_T *wlv)
}
}
+static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t v, bool *do_save)
+{
+ while (true) {
+ // we could already be inside an existing inline text with multiple chunks
+ if (!(wlv->virt_inline_i < kv_size(wlv->virt_inline))) {
+ DecorState *state = &decor_state;
+ 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)
+ || item->decor.virt_text_pos != kVTInline) {
+ continue;
+ }
+ if (item->win_col >= -1 && item->start_col == v) {
+ wlv->virt_inline = item->decor.virt_text;
+ wlv->virt_inline_i = 0;
+ item->win_col = -2;
+ break;
+ }
+ }
+ }
+
+ if (wlv->n_extra == 0 || !wlv->extra_for_extmark) {
+ wlv->reset_extra_attr = false;
+ }
+
+ if (wlv->n_extra <= 0 && wlv->virt_inline_i < kv_size(wlv->virt_inline)) {
+ VirtTextChunk vtc = kv_A(wlv->virt_inline, wlv->virt_inline_i);
+ wlv->p_extra = vtc.text;
+ wlv->n_extra = (int)strlen(wlv->p_extra);
+ wlv->extra_for_extmark = true;
+ wlv->c_extra = NUL;
+ wlv->c_final = NUL;
+ wlv->extra_attr = vtc.hl_id ? syn_id2attr(vtc.hl_id) : 0;
+ wlv->n_attr = mb_charlen(vtc.text);
+ wlv->virt_inline_i++;
+ *do_save = true;
+ // If the text didn't reach until the first window
+ // column we need to skip cells.
+ if (wlv->skip_cells > 0) {
+ int virt_text_len = wlv->n_attr;
+ if (virt_text_len > wlv->skip_cells) {
+ int len = mb_charlen2bytelen(wlv->p_extra, wlv->skip_cells);
+ wlv->n_extra -= len;
+ wlv->p_extra += len;
+ wlv->n_attr -= wlv->skip_cells;
+ // Skipped cells needed to be accounted for in vcol.
+ wlv->skipped_cells += wlv->skip_cells;
+ wlv->skip_cells = 0;
+ } else {
+ // the whole text is left of the window, drop
+ // it and advance to the next one
+ wlv->skip_cells -= virt_text_len;
+ // Skipped cells needed to be accounted for in vcol.
+ wlv->skipped_cells += virt_text_len;
+ wlv->n_attr = 0;
+ wlv->n_extra = 0;
+
+ // go to the start so the next virtual text chunk can be selected.
+ continue;
+ }
+ }
+ }
+ break;
+ }
+}
+
static bool check_mb_utf8(int *c, int *u8cc)
{
if (utf_char2len(*c) > 1) {
@@ -917,6 +996,7 @@ static void win_line_start(win_T *wp, winlinevars_T *wlv, bool save_extra)
wlv->draw_state = WL_START;
wlv->saved_n_extra = wlv->n_extra;
wlv->saved_p_extra = wlv->p_extra;
+ wlv->saved_extra_for_extmark = wlv->extra_for_extmark;
wlv->saved_c_extra = wlv->c_extra;
wlv->saved_c_final = wlv->c_final;
wlv->saved_char_attr = wlv->char_attr;
@@ -931,6 +1011,8 @@ static void win_line_continue(winlinevars_T *wlv)
if (wlv->saved_n_extra > 0) {
// Continue item from end of wrapped line.
wlv->n_extra = wlv->saved_n_extra;
+ wlv->saved_n_extra = 0;
+ wlv->extra_for_extmark = wlv->saved_extra_for_extmark;
wlv->c_extra = wlv->saved_c_extra;
wlv->c_final = wlv->saved_c_final;
wlv->p_extra = wlv->saved_p_extra;
@@ -969,12 +1051,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
// at end-of-line
bool has_fold = foldinfo.fi_level != 0 && foldinfo.fi_lines > 0;
- int n_attr = 0; // chars with special attr
int saved_attr2 = 0; // char_attr saved for n_attr
int n_attr3 = 0; // chars with overruling special attr
int saved_attr3 = 0; // char_attr saved for n_attr3
- int n_skip = 0; // nr of chars to skip for 'nowrap'
+ int n_skip = 0; // nr of chars to skip for 'nowrap' or
+ // concealing
int fromcol_prev = -2; // start of inverting after cursor
bool noinvcur = false; // don't invert the cursor
@@ -986,7 +1068,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
bool area_highlighting = false; // Visual or incsearch highlighting in this line
int vi_attr = 0; // attributes for Visual and incsearch highlighting
int area_attr = 0; // attributes desired by highlighting
+ int saved_area_attr = 0; // idem for area_attr
int search_attr = 0; // attributes desired by 'hlsearch'
+ int saved_search_attr = 0; // search_attr to be used when n_extra
+ // goes to zero
int vcol_save_attr = 0; // saved attr for 'cursorcolumn'
int syntax_attr = 0; // attributes desired by syntax
bool has_syntax = false; // this buffer has syntax highl.
@@ -1024,6 +1109,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
int prev_c1 = 0; // first composing char for prev_c
bool search_attr_from_match = false; // if search_attr is from :match
+ bool saved_search_attr_from_match = false; // if search_attr is from :match
bool has_decor = false; // this buffer has decoration
int win_col_offset = 0; // offset for window columns
@@ -1436,6 +1522,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
}
+ // If there the text doesn't reach to the desired column, need to skip
+ // "skip_cells" cells when virtual text follows.
+ if (!wp->w_p_wrap && v > wlv.vcol) {
+ wlv.skip_cells = (int)(v - wlv.vcol);
+ }
+
// Adjust for when the inverted text is before the screen,
// and when the start of the inverted text is before the screen.
if (wlv.tocol <= wlv.vcol) {
@@ -1714,7 +1806,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.n_extra = 0;
}
- if (wlv.draw_state == WL_LINE && (area_highlighting || has_spell)) {
+ int extmark_attr = 0;
+ if (wlv.draw_state == WL_LINE
+ && (area_highlighting || has_spell || (extra_check && !has_fold))) {
// handle Visual or match highlighting in this line
if (wlv.vcol == wlv.fromcol
|| (wlv.vcol + 1 == wlv.fromcol && wlv.n_extra == 0
@@ -1732,7 +1826,29 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
area_active = false;
}
- if (!wlv.n_extra) {
+ if (has_decor && v >= 0) {
+ bool selected = (area_active || (area_highlighting && noinvcur
+ && wlv.vcol == wp->w_virtcol));
+ extmark_attr = decor_redraw_col(wp, (colnr_T)v, wlv.off,
+ selected, &decor_state);
+
+ bool do_save = false;
+ handle_inline_virtual_text(wp, &wlv, v, &do_save);
+ if (do_save) {
+ // restore search_attr and area_attr when n_extra is down to zero
+ // TODO(bfredl): this is ugly as fuck. look if we can do this some other way.
+ saved_search_attr = search_attr;
+ saved_area_attr = area_attr;
+ saved_search_attr_from_match = search_attr_from_match;
+ search_attr_from_match = false;
+ search_attr = 0;
+ area_attr = 0;
+ extmark_attr = 0;
+ n_skip = 0;
+ }
+ }
+
+ if (wlv.n_extra == 0) {
// Check for start/end of 'hlsearch' and other matches.
// After end, check for start/end of next match.
// When another match, have to check for start again.
@@ -1750,12 +1866,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
if (wlv.diff_hlf != (hlf_T)0) {
+ // When there is extra text (eg: virtual text) it gets the
+ // diff highlighting for the line, but not for changed text.
if (wlv.diff_hlf == HLF_CHD && ptr - line >= change_start
&& wlv.n_extra == 0) {
wlv.diff_hlf = HLF_TXD; // changed text
}
- if (wlv.diff_hlf == HLF_TXD && ptr - line > change_end
- && wlv.n_extra == 0) {
+ if (wlv.diff_hlf == HLF_TXD && ((ptr - line > change_end && wlv.n_extra == 0)
+ || (wlv.n_extra > 0 && wlv.extra_for_extmark))) {
wlv.diff_hlf = HLF_CHD; // changed line
}
wlv.line_attr = win_hl_attr(wp, (int)wlv.diff_hlf);
@@ -1856,6 +1974,26 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.p_extra++;
}
wlv.n_extra--;
+
+ // Only restore search_attr and area_attr after "n_extra" in
+ // the next screen line is also done.
+ if (wlv.n_extra <= 0) {
+ if (wlv.saved_n_extra <= 0) {
+ if (search_attr == 0) {
+ search_attr = saved_search_attr;
+ }
+ if (area_attr == 0 && *ptr != NUL) {
+ area_attr = saved_area_attr;
+ }
+
+ if (wlv.extra_for_extmark) {
+ // wlv.extra_attr should be used at this position but not
+ // any further.
+ wlv.reset_extra_attr = true;
+ }
+ }
+ wlv.extra_for_extmark = false;
+ }
} else if (foldinfo.fi_lines > 0) {
// skip writing the buffer line itself
c = NUL;
@@ -1907,7 +2045,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.c_extra = NUL;
wlv.c_final = NUL;
if (area_attr == 0 && search_attr == 0) {
- n_attr = wlv.n_extra + 1;
+ wlv.n_attr = wlv.n_extra + 1;
wlv.extra_attr = win_hl_attr(wp, HLF_8);
saved_attr2 = wlv.char_attr; // save current attr
}
@@ -1962,7 +2100,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.c_final = NUL;
c = ' ';
if (area_attr == 0 && search_attr == 0) {
- n_attr = wlv.n_extra + 1;
+ wlv.n_attr = wlv.n_extra + 1;
wlv.extra_attr = win_hl_attr(wp, HLF_AT);
saved_attr2 = wlv.char_attr; // save current attr
}
@@ -2027,10 +2165,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
if (has_decor && v > 0) {
- bool selected = (area_active || (area_highlighting && noinvcur
- && wlv.vcol == wp->w_virtcol));
- int extmark_attr = decor_redraw_col(wp, (colnr_T)v - 1, wlv.off,
- selected, &decor_state);
if (extmark_attr != 0) {
if (!attr_pri) {
wlv.char_attr = hl_combine_attr(wlv.char_attr, extmark_attr);
@@ -2135,7 +2269,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
chartabsize_T cts;
init_chartabsize_arg(&cts, wp, lnum, wlv.vcol, line, p);
+ // do not want virtual text to be counted here
+ cts.cts_has_virt_text = false;
wlv.n_extra = win_lbr_chartabsize(&cts, NULL) - 1;
+ clear_chartabsize_arg(&cts);
// We have just drawn the showbreak value, no need to add
// space for it again.
@@ -2167,7 +2304,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
c = ' ';
}
}
- clear_chartabsize_arg(&cts);
}
in_multispace = c == ' ' && ((ptr > line + 1 && ptr[-2] == ' ') || *ptr == ' ');
@@ -2198,7 +2334,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
} else {
c = (c == ' ') ? wp->w_p_lcs_chars.space : wp->w_p_lcs_chars.nbsp;
}
- n_attr = 1;
+ wlv.n_attr = 1;
wlv.extra_attr = win_hl_attr(wp, HLF_0);
saved_attr2 = wlv.char_attr; // save current attr
mb_c = c;
@@ -2221,7 +2357,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
c = wp->w_p_lcs_chars.space;
}
- n_attr = 1;
+ wlv.n_attr = 1;
wlv.extra_attr = win_hl_attr(wp, HLF_0);
saved_attr2 = wlv.char_attr; // save current attr
mb_c = c;
@@ -2337,7 +2473,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.c_extra = wp->w_p_lcs_chars.tab2;
}
wlv.c_final = wp->w_p_lcs_chars.tab3;
- n_attr = tab_len + 1;
+ wlv.n_attr = tab_len + 1;
wlv.extra_attr = win_hl_attr(wp, HLF_0);
saved_attr2 = wlv.char_attr; // save current attr
mb_c = c;
@@ -2364,15 +2500,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
&& wlv.line_attr == 0
&& wlv.line_attr_lowprio == 0) {
// In virtualedit, visual selections may extend beyond end of line
- if (area_highlighting && virtual_active()
- && wlv.tocol != MAXCOL && wlv.vcol < wlv.tocol) {
- wlv.n_extra = 0;
- } else {
+ if (!(area_highlighting && virtual_active()
+ && wlv.tocol != MAXCOL && wlv.vcol < wlv.tocol)) {
wlv.p_extra = at_end_str;
- wlv.n_extra = 1;
- wlv.c_extra = NUL;
- wlv.c_final = NUL;
}
+ wlv.n_extra = 0;
}
if (wp->w_p_list && wp->w_p_lcs_chars.eol > 0) {
c = wp->w_p_lcs_chars.eol;
@@ -2382,7 +2514,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
lcs_eol_one = -1;
ptr--; // put it back at the NUL
wlv.extra_attr = win_hl_attr(wp, HLF_AT);
- n_attr = 1;
+ wlv.n_attr = 1;
mb_c = c;
mb_utf8 = check_mb_utf8(&c, u8cc);
} else if (c != NUL) {
@@ -2411,7 +2543,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.n_extra = byte2cells(c) - 1;
c = (uint8_t)(*wlv.p_extra++);
}
- n_attr = wlv.n_extra + 1;
+ wlv.n_attr = wlv.n_extra + 1;
wlv.extra_attr = win_hl_attr(wp, HLF_8);
saved_attr2 = wlv.char_attr; // save current attr
mb_utf8 = false; // don't draw as UTF-8
@@ -2471,7 +2603,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
}
wlv.n_extra = 0;
- n_attr = 0;
+ wlv.n_attr = 0;
} else if (n_skip == 0) {
is_concealing = true;
n_skip = 1;
@@ -2506,8 +2638,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
// Don't override visual selection highlighting.
- if (n_attr > 0 && wlv.draw_state == WL_LINE && !search_attr_from_match) {
+ if (wlv.n_attr > 0 && wlv.draw_state == WL_LINE && !search_attr_from_match) {
wlv.char_attr = hl_combine_attr(wlv.char_attr, wlv.extra_attr);
+ if (wlv.reset_extra_attr) {
+ wlv.reset_extra_attr = false;
+ wlv.extra_attr = 0;
+ // search_attr_from_match can be restored now that the extra_attr has been applied
+ search_attr_from_match = saved_search_attr_from_match;
+ }
}
// Handle the case where we are in column 0 but not on the first
@@ -2527,7 +2665,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.c_extra = MB_FILLER_CHAR;
wlv.c_final = NUL;
wlv.n_extra = 1;
- n_attr = 2;
+ wlv.n_attr = 2;
wlv.extra_attr = win_hl_attr(wp, HLF_AT);
}
mb_c = c;
@@ -2743,7 +2881,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
&& !has_fold
&& (*ptr != NUL
|| lcs_eol_one > 0
- || (wlv.n_extra && (wlv.c_extra != NUL || *wlv.p_extra != NUL)))) {
+ || (wlv.n_extra > 0 && (wlv.c_extra != NUL || *wlv.p_extra != NUL)))) {
c = wp->w_p_lcs_chars.ext;
wlv.char_attr = win_hl_attr(wp, HLF_AT);
mb_c = c;
@@ -2864,7 +3002,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.boguscols += wlv.n_extra;
}
wlv.n_extra = 0;
- n_attr = 0;
+ wlv.n_attr = 0;
}
if (utf_char2cells(mb_c) > 1) {
@@ -2889,13 +3027,19 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
if (wlv.n_extra > 0) {
wlv.vcol += wlv.n_extra;
wlv.n_extra = 0;
- n_attr = 0;
+ wlv.n_attr = 0;
}
}
} else {
n_skip--;
}
+ // The skipped cells need to be accounted for in vcol.
+ if (wlv.draw_state > WL_STC && wlv.skipped_cells > 0) {
+ wlv.vcol += wlv.skipped_cells;
+ wlv.skipped_cells = 0;
+ }
+
// Only advance the "wlv.vcol" when after the 'number' or
// 'relativenumber' column.
if (wlv.draw_state > WL_STC
@@ -2913,7 +3057,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
// restore attributes after last 'listchars' or 'number' char
- if (n_attr > 0 && wlv.draw_state == WL_LINE && --n_attr == 0) {
+ if (wlv.n_attr > 0 && wlv.draw_state == WL_LINE && --wlv.n_attr == 0) {
wlv.char_attr = saved_attr2;
}