diff options
Diffstat (limited to 'src/nvim/drawline.c')
-rw-r--r-- | src/nvim/drawline.c | 124 |
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); |