diff options
| author | bfredl <bjorn.linse@gmail.com> | 2023-12-22 11:49:06 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-12-22 11:49:06 +0100 |
| commit | d9d9d94343cc3ee2c9bcda37e987d63e84928d79 (patch) | |
| tree | d07465d7fbd6c758fa3f393edf55a6b0a1a45f3a | |
| parent | 92204b06e7365cf4c68e6ea8258dce801f0a5df9 (diff) | |
| parent | 66ac327db27c8097cfa6c1f136dca96151b074f4 (diff) | |
| download | rneovim-d9d9d94343cc3ee2c9bcda37e987d63e84928d79.tar.gz rneovim-d9d9d94343cc3ee2c9bcda37e987d63e84928d79.tar.bz2 rneovim-d9d9d94343cc3ee2c9bcda37e987d63e84928d79.zip | |
Merge pull request #26528 from bfredl/nodrawstate
refactor(drawline): remove LineDrawState and wlv->saved_n_extra
| -rw-r--r-- | src/nvim/api/extmark.c | 7 | ||||
| -rw-r--r-- | src/nvim/decoration.c | 36 | ||||
| -rw-r--r-- | src/nvim/decoration_defs.h | 8 | ||||
| -rw-r--r-- | src/nvim/drawline.c | 697 | ||||
| -rw-r--r-- | src/nvim/sign.c | 68 | ||||
| -rw-r--r-- | src/nvim/sign_defs.h | 7 | ||||
| -rw-r--r-- | src/nvim/statusline.c | 22 | ||||
| -rw-r--r-- | src/nvim/types_defs.h | 2 | ||||
| -rw-r--r-- | test/functional/ui/sign_spec.lua | 10 |
9 files changed, 393 insertions, 464 deletions
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index ec47d7227e..fa3c5afcc6 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -665,9 +665,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } if (HAS_KEY(opts, set_extmark, sign_text)) { - sign.text.ptr = NULL; - VALIDATE_S(init_sign_text(NULL, &sign.text.ptr, opts->sign_text.data), - "sign_text", "", { + sign.text[0] = 0; + VALIDATE_S(init_sign_text(NULL, sign.text, opts->sign_text.data), "sign_text", "", { goto error; }); sign.flags |= kSHIsSign; @@ -785,7 +784,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer uint32_t decor_indexed = DECOR_ID_INVALID; if (sign.flags & kSHIsSign) { decor_indexed = decor_put_sh(sign); - if (sign.text.ptr != NULL) { + if (sign.text[0]) { decor_flags |= MT_FLAG_DECOR_SIGNTEXT; } if (sign.number_hl_id || sign.line_hl_id || sign.cursorline_hl_id) { diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index ad2482c2e4..6f1416711a 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -5,6 +5,7 @@ #include "nvim/api/extmark.h" #include "nvim/api/private/helpers.h" +#include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" #include "nvim/decoration.h" #include "nvim/drawscreen.h" @@ -19,6 +20,7 @@ #include "nvim/move.h" #include "nvim/option_vars.h" #include "nvim/pos_defs.h" +#include "nvim/sign.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "decoration.c.generated.h" @@ -158,7 +160,7 @@ DecorSignHighlight decor_sh_from_inline(DecorHighlightInline item) DecorSignHighlight conv = { .flags = item.flags, .priority = item.priority, - .text.sc[0] = item.conceal_char, + .text[0] = item.conceal_char, .hl_id = item.hl_id, .number_hl_id = 0, .line_hl_id = 0, @@ -207,7 +209,7 @@ void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row1, int row2) if (sh->flags & kSHIsSign) { sh->sign_add_id = sign_add_id++; buf->b_signs++; - if (sh->text.ptr) { + if (sh->text[0]) { buf->b_signs_with_text++; buf_signcols_invalidate_range(buf, row1, row2, 1); } @@ -253,7 +255,7 @@ void buf_remove_decor_sh(buf_T *buf, int row1, int row2, DecorSignHighlight *sh) if (sh->flags & kSHIsSign) { assert(buf->b_signs > 0); buf->b_signs--; - if (sh->text.ptr) { + if (sh->text[0]) { assert(buf->b_signs_with_text > 0); buf->b_signs_with_text--; if (row2 >= row1) { @@ -312,9 +314,6 @@ void decor_free_inner(DecorVirtText *vt, uint32_t first_idx) while (idx != DECOR_ID_INVALID) { DecorSignHighlight *sh = &kv_A(decor_items, idx); if (sh->flags & kSHIsSign) { - xfree(sh->text.ptr); - } - if (sh->flags & kSHIsSign) { xfree(sh->sign_name); } sh->flags = 0; @@ -362,8 +361,11 @@ void decor_check_invalid_glyphs(void) { for (size_t i = 0; i < kv_size(decor_items); i++) { DecorSignHighlight *it = &kv_A(decor_items, i); - if ((it->flags & kSHConceal) && schar_high(it->text.sc[0])) { - it->text.sc[0] = schar_from_char(schar_get_first_codepoint(it->text.sc[0])); + int width = (it->flags & kSHIsSign) ? SIGN_WIDTH : ((it->flags & kSHConceal) ? 1 : 0); + for (int j = 0; j < width; j++) { + if (schar_high(it->text[j])) { + it->text[j] = schar_from_char(schar_get_first_codepoint(it->text[j])); + } } } } @@ -661,7 +663,7 @@ next_mark: if (item.start_row == state->row && item.start_col == col) { DecorSignHighlight *sh = &item.data.sh; conceal = 2; - conceal_char = sh->text.sc[0]; + conceal_char = sh->text[0]; state->col_until = MIN(state->col_until, item.start_col); conceal_attr = item.attr_id; } @@ -729,7 +731,7 @@ void decor_redraw_signs(win_T *wp, buf_T *buf, int row, SignTextAttrs sattrs[], while (marktree_itr_step_overlap(buf->b_marktree, itr, &pair)) { if (!mt_invalid(pair.start) && mt_decor_sign(pair.start)) { DecorSignHighlight *sh = decor_find_sign(mt_decor(pair.start)); - num_text += (sh->text.ptr != NULL); + num_text += (sh->text[0] != NUL); kv_push(signs, ((SignItem){ sh, pair.start.id })); } } @@ -741,7 +743,7 @@ void decor_redraw_signs(win_T *wp, buf_T *buf, int row, SignTextAttrs sattrs[], } if (!mt_end(mark) && !mt_invalid(mark) && mt_decor_sign(mark)) { DecorSignHighlight *sh = decor_find_sign(mt_decor(mark)); - num_text += (sh->text.ptr != NULL); + num_text += (sh->text[0] != NUL); kv_push(signs, ((SignItem){ sh, mark.id })); } @@ -755,8 +757,8 @@ void decor_redraw_signs(win_T *wp, buf_T *buf, int row, SignTextAttrs sattrs[], for (size_t i = 0; i < kv_size(signs); i++) { DecorSignHighlight *sh = kv_A(signs, i).sh; - if (idx >= 0 && sh->text.ptr) { - sattrs[idx].text = sh->text.ptr; + if (idx >= 0 && sh->text[0]) { + memcpy(sattrs[idx].text, sh->text, SIGN_WIDTH * sizeof(sattr_T)); sattrs[idx--].hl_id = sh->hl_id; } if (*num_id == 0) { @@ -1033,7 +1035,7 @@ void decor_to_dict_legacy(Dictionary *dict, DecorInline decor, bool hl_name) PUT(*dict, "hl_eol", BOOLEAN_OBJ(sh_hl.flags & kSHHlEol)); if (sh_hl.flags & kSHConceal) { char buf[MAX_SCHAR_SIZE]; - schar_get(buf, sh_hl.text.sc[0]); + schar_get(buf, sh_hl.text[0]); PUT(*dict, "conceal", CSTR_TO_OBJ(buf)); } @@ -1081,8 +1083,10 @@ void decor_to_dict_legacy(Dictionary *dict, DecorInline decor, bool hl_name) } if (sh_sign.flags & kSHIsSign) { - if (sh_sign.text.ptr) { - PUT(*dict, "sign_text", CSTR_TO_OBJ(sh_sign.text.ptr)); + if (sh_sign.text[0]) { + char buf[SIGN_WIDTH * MAX_SCHAR_SIZE]; + describe_sign_text(buf, sh_sign.text); + PUT(*dict, "sign_text", CSTR_TO_OBJ(buf)); } if (sh_sign.sign_name) { diff --git a/src/nvim/decoration_defs.h b/src/nvim/decoration_defs.h index f272753f46..4550ae0a42 100644 --- a/src/nvim/decoration_defs.h +++ b/src/nvim/decoration_defs.h @@ -59,11 +59,7 @@ typedef struct { uint16_t flags; DecorPriority priority; int hl_id; // if sign: highlight of sign text - // TODO(bfredl): Later signs should use sc[2] as well. - union { - char *ptr; // sign - schar_T sc[2]; // conceal text (only sc[0] used) - } text; + schar_T text[SIGN_WIDTH]; // conceal text only uses text[0] // NOTE: if more functionality is added to a Highlight these should be overloaded // or restructured char *sign_name; @@ -74,7 +70,7 @@ typedef struct { uint32_t next; } DecorSignHighlight; -#define DECOR_SIGN_HIGHLIGHT_INIT { 0, DECOR_PRIORITY_BASE, 0, { .ptr = NULL }, NULL, 0, 0, 0, 0, \ +#define DECOR_SIGN_HIGHLIGHT_INIT { 0, DECOR_PRIORITY_BASE, 0, { 0, 0 }, NULL, 0, 0, 0, 0, \ DECOR_ID_INVALID } enum { diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 4f62fda2c5..29221e64f9 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -52,23 +52,8 @@ #define MB_FILLER_CHAR '<' // character used when a double-width character doesn't fit. -/// possible draw states in win_line(), drawn in sequence. -typedef enum { - WL_START = 0, // nothing done yet - WL_CMDLINE, // cmdline window column - WL_FOLD, // 'foldcolumn' - WL_SIGN, // column for signs - WL_NR, // line number - WL_STC, // 'statuscolumn' - WL_BRI, // 'breakindent' - WL_SBR, // 'showbreak' or 'diff' - WL_LINE, // text in the line -} LineDrawState; - /// structure with variables passed between win_line() and other functions typedef struct { - LineDrawState draw_state; ///< what to draw next - linenr_T lnum; ///< line number to be drawn foldinfo_T foldinfo; ///< fold info for this line @@ -102,18 +87,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) - 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; - char extra[57]; ///< sign, line number and 'fdc' must fit in here hlf_T diff_hlf; ///< type of diff highlighting @@ -136,6 +111,8 @@ typedef struct { ///< or w_skipcol or concealing int skipped_cells; ///< nr of skipped cells for virtual text ///< to be added to wlv.vcol later + + int *color_cols; ///< if not NULL, highlight colorcolumn using according columns array } winlinevars_T; #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -163,15 +140,17 @@ void drawline_free_all_mem(void) } #endif -/// Advance **color_cols -/// -/// @return true when there are columns to draw. -static bool advance_color_col(int vcol, int **color_cols) +/// Advance wlv->color_cols if not NULL +static void advance_color_col(winlinevars_T *wlv, int vcol) { - while (**color_cols >= 0 && vcol > **color_cols) { - (*color_cols)++; + if (wlv->color_cols) { + while (*wlv->color_cols >= 0 && vcol > *wlv->color_cols) { + wlv->color_cols++; + } + if (*wlv->color_cols < 0) { + wlv->color_cols = NULL; + } } - return **color_cols >= 0; } /// Used when 'cursorlineopt' contains "screenline": compute the margins between @@ -360,6 +339,38 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode, return col; } +// TODO(bfredl): integrate with grid.c linebuf code? madness? +static void draw_col_buf(win_T *wp, winlinevars_T *wlv, const char *text, size_t len, int attr, + bool vcol) +{ + const char *ptr = text; + while (ptr < text + len && wlv->off < wp->w_grid.cols) { + int cells = line_putchar(wp->w_buffer, &ptr, &linebuf_char[wlv->off], + wp->w_grid.cols - wlv->off, wlv->off); + int myattr = attr; + if (vcol) { + advance_color_col(wlv, wlv->vcol); + if (wlv->color_cols && wlv->vcol == *wlv->color_cols) { + myattr = hl_combine_attr(win_hl_attr(wp, HLF_MC), myattr); + } + } + for (int c = 0; c < cells; c++) { + linebuf_attr[wlv->off] = myattr; + linebuf_vcol[wlv->off] = vcol ? wlv->vcol++ : -1; + wlv->off++; + } + } +} + +static void draw_col_fill(winlinevars_T *wlv, schar_T fillchar, int width, int attr) +{ + for (int i = 0; i < width; i++) { + linebuf_char[wlv->off] = fillchar; + linebuf_attr[wlv->off] = attr; + wlv->off++; + } +} + /// Return true if CursorLineSign highlight is to be used. static bool use_cursor_line_highlight(win_T *wp, linenr_T lnum) { @@ -368,28 +379,18 @@ static bool use_cursor_line_highlight(win_T *wp, linenr_T lnum) && (wp->w_p_culopt_flags & CULOPT_NBR); } -static char fdc_buf[MB_MAXCHAR * 10 + 1]; - /// Setup for drawing the 'foldcolumn', if there is one. -static void handle_foldcolumn(win_T *wp, winlinevars_T *wlv) +static void draw_foldcolumn(win_T *wp, winlinevars_T *wlv) { int fdc = compute_foldcolumn(wp, 0); if (fdc <= 0) { return; } - // Use a separate buffer as `extra_buf` might be in use. - wlv->n_extra = (int)fill_foldcolumn(fdc_buf, wp, wlv->foldinfo, wlv->lnum, - &wlv->n_closing); - fdc_buf[wlv->n_extra] = NUL; - wlv->p_extra = fdc_buf; - wlv->c_extra = NUL; - wlv->c_final = NUL; - if (use_cursor_line_highlight(wp, wlv->lnum)) { - wlv->char_attr = win_hl_attr(wp, HLF_CLF); - } else { - wlv->char_attr = win_hl_attr(wp, HLF_FC); - } + int attr = use_cursor_line_highlight(wp, wlv->lnum) + ? win_hl_attr(wp, HLF_CLF) : win_hl_attr(wp, HLF_FC); + + fill_foldcolumn(wlv, wp, wlv->foldinfo, wlv->lnum, attr, NULL); } /// Fills the foldcolumn at "p" for window "wp". @@ -401,29 +402,25 @@ 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, int *n_closing) +size_t fill_foldcolumn(void *maybe_wlv, win_T *wp, foldinfo_T foldinfo, linenr_T lnum, int attr, + schar_T *out_buffer) { int i = 0; int fdc = compute_foldcolumn(wp, 0); // available cell width - size_t char_counter = 0; - int symbol = 0; - int len = 0; + int char_counter = 0; bool closed = foldinfo.fi_level != 0 && foldinfo.fi_lines > 0; - // Init to all spaces. - memset(p, ' ', MB_MAXCHAR * (size_t)fdc + 1); int level = foldinfo.fi_level; + winlinevars_T *wlv = maybe_wlv; // TODO(bfredl): this is bullshit + // If the column is too narrow, we start at the lowest level that // fits and use numbers to indicate the depth. - int first_level = level - fdc - closed + 1; - if (first_level < 1) { - first_level = 1; - } + int first_level = MAX(level - fdc - closed + 1, 1); for (i = 0; i < MIN(fdc, level); i++) { - if (foldinfo.fi_lnum == lnum - && first_level + i >= foldinfo.fi_low_level) { + int symbol = 0; + if (foldinfo.fi_lnum == lnum && first_level + i >= foldinfo.fi_low_level) { symbol = wp->w_p_fcs_chars.foldopen; } else if (first_level == 1) { symbol = wp->w_p_fcs_chars.foldsep; @@ -433,64 +430,74 @@ size_t fill_foldcolumn(char *p, win_T *wp, foldinfo_T foldinfo, linenr_T lnum, i symbol = '>'; } - len = utf_char2bytes(symbol, &p[char_counter]); - char_counter += (size_t)len; + if (out_buffer) { + out_buffer[char_counter++] = schar_from_char(symbol); + } else { + linebuf_vcol[wlv->off] = -3; + linebuf_attr[wlv->off] = attr; + linebuf_char[wlv->off++] = schar_from_char(symbol); + char_counter++; + } + if (first_level + i >= level) { i++; break; } } - int n_closing_val = i; - if (closed) { - if (symbol != 0) { + if (char_counter > 0) { // rollback previous write - char_counter -= (size_t)len; - memset(&p[char_counter], ' ', (size_t)len); - n_closing_val--; + char_counter--; + if (!out_buffer) { + wlv->off--; + } + } + if (out_buffer) { + out_buffer[char_counter++] = schar_from_char(wp->w_p_fcs_chars.foldclosed); + } else { + linebuf_vcol[wlv->off] = -2; + linebuf_attr[wlv->off] = attr; + linebuf_char[wlv->off++] = schar_from_char(wp->w_p_fcs_chars.foldclosed); + char_counter++; } - 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; + int width = MAX(char_counter + (fdc - i), fdc); + if (char_counter < width) { + if (out_buffer) { + while (char_counter < width) { + out_buffer[char_counter++] = schar_from_ascii(' '); + } + } else { + draw_col_fill(wlv, schar_from_ascii(' '), width - char_counter, attr); + } } - - return MAX(char_counter + (size_t)(fdc - i), (size_t)fdc); + return (size_t)width; } /// Get information needed to display the sign in line "wlv->lnum" in window "wp". /// If "nrcol" is true, the sign is going to be displayed in the number column. /// Otherwise the sign is going to be displayed in the sign column. If there is no /// sign, draw blank cells instead. -static void get_sign_display_info(bool nrcol, win_T *wp, winlinevars_T *wlv, int sign_idx, - int sign_cul_attr) +static void draw_sign(bool nrcol, win_T *wp, winlinevars_T *wlv, int sign_idx, int sign_cul_attr) { SignTextAttrs sattr = wlv->sattrs[sign_idx]; wlv->c_final = NUL; - if (sattr.text && wlv->row == wlv->startrow + wlv->filler_lines && wlv->filler_todo <= 0) { - size_t fill = nrcol ? (size_t)number_width(wp) - SIGN_WIDTH : 0; - size_t sign_len = strlen(sattr.text); - - // Spaces + sign: " " + ">>" + ' ' - wlv->n_extra = (int)(fill + sign_len + nrcol); - if (nrcol) { - memset(wlv->extra, ' ', (size_t)wlv->n_extra); - } - memcpy(wlv->extra + fill, sattr.text, sign_len); - wlv->p_extra = wlv->extra; - wlv->c_extra = NUL; - wlv->char_attr = (use_cursor_line_highlight(wp, wlv->lnum) && sign_cul_attr) - ? sign_cul_attr : sattr.hl_id ? syn_id2attr(sattr.hl_id) : 0; + if (sattr.text[0] && wlv->row == wlv->startrow + wlv->filler_lines && wlv->filler_todo <= 0) { + int attr = (use_cursor_line_highlight(wp, wlv->lnum) && sign_cul_attr) + ? sign_cul_attr : sattr.hl_id ? syn_id2attr(sattr.hl_id) : 0; + int fill = nrcol ? number_width(wp) + 1 : SIGN_WIDTH; + draw_col_fill(wlv, schar_from_ascii(' '), fill, attr); + int sign_pos = wlv->off - SIGN_WIDTH - (int)nrcol; + linebuf_char[sign_pos] = sattr.text[0]; + linebuf_char[sign_pos + 1] = sattr.text[1]; } else { + assert(!nrcol); // handled in draw_lnum_col() wlv->c_extra = ' '; - wlv->n_extra = nrcol ? number_width(wp) + 1 : SIGN_WIDTH; - if (!nrcol) { - wlv->char_attr = win_hl_attr(wp, use_cursor_line_highlight(wp, wlv->lnum) ? HLF_CLS : HLF_SC); - } + int attr = win_hl_attr(wp, use_cursor_line_highlight(wp, wlv->lnum) ? HLF_CLS : HLF_SC); + draw_col_fill(wlv, schar_from_ascii(' '), SIGN_WIDTH, attr); } } @@ -557,7 +564,7 @@ static int get_line_number_attr(win_T *wp, winlinevars_T *wlv) /// Display the absolute or relative line number. After the first row fill with /// blanks when the 'n' flag isn't in 'cpo'. -static void handle_lnum_col(win_T *wp, winlinevars_T *wlv, int sign_num_attr, int sign_cul_attr) +static void draw_lnum_col(win_T *wp, winlinevars_T *wlv, int sign_num_attr, int sign_cul_attr) { bool has_cpo_n = vim_strchr(p_cpo, CPO_NUMCOL) != NULL; @@ -568,33 +575,30 @@ static void handle_lnum_col(win_T *wp, winlinevars_T *wlv, int sign_num_attr, in && !((has_cpo_n && !wp->w_p_bri) && wp->w_skipcol > 0 && wlv->lnum == wp->w_topline)) { // If 'signcolumn' is set to 'number' and a sign is present in "lnum", // then display the sign instead of the line number. - if (wp->w_minscwidth == SCL_NUM && wlv->sattrs[0].text) { - get_sign_display_info(true, wp, wlv, 0, sign_cul_attr); + if (wp->w_minscwidth == SCL_NUM && wlv->sattrs[0].text[0] + && wlv->row == wlv->startrow + wlv->filler_lines && wlv->filler_todo <= 0) { + draw_sign(true, wp, wlv, 0, sign_cul_attr); } else { // Draw the line number (empty space after wrapping). + int width = number_width(wp) + 1; + int attr = (sign_num_attr > 0 && wlv->filler_todo <= 0) + ? sign_num_attr : get_line_number_attr(wp, wlv); if (wlv->row == wlv->startrow + wlv->filler_lines && (wp->w_skipcol == 0 || wlv->row > 0 || (wp->w_p_nu && wp->w_p_rnu))) { - get_line_number_str(wp, wlv->lnum, wlv->extra, sizeof(wlv->extra)); + char buf[32]; + get_line_number_str(wp, wlv->lnum, buf, sizeof(buf)); if (wp->w_skipcol > 0 && wlv->startrow == 0) { - for (wlv->p_extra = wlv->extra; *wlv->p_extra == ' '; wlv->p_extra++) { - *wlv->p_extra = '-'; + for (char *c = buf; *c == ' '; c++) { + *c = '-'; } } if (wp->w_p_rl) { // reverse line numbers - char *num = skipwhite(wlv->extra); + char *num = skipwhite(buf); rl_mirror_ascii(num, skiptowhite(num)); } - wlv->p_extra = wlv->extra; - wlv->c_extra = NUL; + draw_col_buf(wp, wlv, buf, (size_t)width, attr, false); } else { - wlv->c_extra = ' '; - } - wlv->c_final = NUL; - wlv->n_extra = number_width(wp) + 1; - if (sign_num_attr > 0) { - wlv->char_attr = sign_num_attr; - } else { - wlv->char_attr = get_line_number_attr(wp, wlv); + draw_col_fill(wlv, schar_from_ascii(' '), width, attr); } } } @@ -663,124 +667,108 @@ static void get_statuscol_str(win_T *wp, linenr_T lnum, int virtnum, statuscol_T /// /// @param stcp Status column attributes /// @param[in,out] wlv -static void get_statuscol_display_info(statuscol_T *stcp, winlinevars_T *wlv) +static void draw_statuscol(win_T *wp, statuscol_T *stcp, winlinevars_T *wlv) { - wlv->c_extra = NUL; - wlv->c_final = NUL; do { - wlv->draw_state = WL_STC; - wlv->char_attr = stcp->cur_attr; - wlv->p_extra = stcp->textp; - char *const section_end = stcp->hlrecp->start ? stcp->hlrecp->start : stcp->text_end; - wlv->n_extra = (int)(section_end - stcp->textp); + int attr = stcp->cur_attr; + char *text = stcp->textp; + char *section_end = stcp->hlrecp->start ? stcp->hlrecp->start : stcp->text_end; + ptrdiff_t len = section_end - text; // Prepare for next highlight section if not yet at the end if (section_end < stcp->text_end) { int hl = stcp->hlrecp->userhl; stcp->textp = stcp->hlrecp->start; stcp->cur_attr = hl < 0 ? syn_id2attr(-hl) : stcp->num_attr; stcp->hlrecp++; - wlv->draw_state = WL_STC - 1; + } else { + stcp->textp = section_end; } // Skip over empty highlight sections - } while (wlv->n_extra == 0 && stcp->textp < stcp->text_end); - if (wlv->n_extra > 0) { - static char transbuf[(MAX_NUMBERWIDTH + 9 + 9 * 2) * MB_MAXBYTES + 1]; - wlv->n_extra = (int)transstr_buf(wlv->p_extra, wlv->n_extra, transbuf, sizeof transbuf, true); - wlv->p_extra = transbuf; - } + if (len) { + static char transbuf[(MAX_NUMBERWIDTH + 9 + 9 * SIGN_WIDTH) * MB_MAXBYTES + 1]; + size_t translen = transstr_buf(text, len, transbuf, sizeof transbuf, true); + draw_col_buf(wp, wlv, transbuf, translen, attr, false); + } + } while (stcp->textp < stcp->text_end); } static void handle_breakindent(win_T *wp, winlinevars_T *wlv) { - if (wp->w_briopt_sbr && wlv->draw_state == WL_BRI - 1 - && *get_showbreak_value(wp) != NUL) { - // draw indent after showbreak value - wlv->draw_state = WL_BRI; - } else if (wp->w_briopt_sbr && wlv->draw_state == WL_SBR) { - // after the showbreak, draw the breakindent - wlv->draw_state = WL_BRI - 1; - } - // draw 'breakindent': indent wrapped text accordingly - if (wlv->draw_state == WL_BRI - 1 && wlv->n_extra == 0) { - wlv->draw_state = WL_BRI; - // if wlv->need_showbreak is set, breakindent also applies - if (wp->w_p_bri && (wlv->row > wlv->startrow + wlv->filler_lines - || wlv->need_showbreak)) { - wlv->char_attr = 0; - if (wlv->diff_hlf != (hlf_T)0) { - wlv->char_attr = win_hl_attr(wp, (int)wlv->diff_hlf); - } - wlv->p_extra = NULL; - wlv->c_extra = ' '; - wlv->c_final = NUL; - wlv->n_extra = get_breakindent_win(wp, ml_get_buf(wp->w_buffer, wlv->lnum)); - if (wlv->row == wlv->startrow) { - wlv->n_extra -= win_col_off2(wp); - if (wlv->n_extra < 0) { - wlv->n_extra = 0; - } - } - if (wp->w_skipcol > 0 && wlv->startrow == 0 && wp->w_p_wrap && wp->w_briopt_sbr) { - wlv->need_showbreak = false; + // if wlv->need_showbreak is set, breakindent also applies + if (wp->w_p_bri && (wlv->row > wlv->startrow + wlv->filler_lines + || wlv->need_showbreak)) { + int attr = 0; + if (wlv->diff_hlf != (hlf_T)0) { + attr = win_hl_attr(wp, (int)wlv->diff_hlf); + } + int num = get_breakindent_win(wp, ml_get_buf(wp->w_buffer, wlv->lnum)); + if (wlv->row == wlv->startrow) { + num -= win_col_off2(wp); + if (wlv->n_extra < 0) { + num = 0; } - // Correct end of highlighted area for 'breakindent', - // required wen 'linebreak' is also set. - if (wlv->tocol == wlv->vcol) { - wlv->tocol += wlv->n_extra; + } + + // Correct end of highlighted area for 'breakindent', + // required wen 'linebreak' is also set. + if (wlv->tocol == wlv->vcol) { + wlv->tocol += num; + } + + for (int i = 0; i < num; i++) { + linebuf_char[wlv->off] = schar_from_ascii(' '); + + advance_color_col(wlv, wlv->vcol); + int myattr = attr; + if (wlv->color_cols && wlv->vcol == *wlv->color_cols) { + myattr = hl_combine_attr(win_hl_attr(wp, HLF_MC), myattr); } + linebuf_attr[wlv->off] = myattr; + linebuf_vcol[wlv->off] = wlv->vcol++; // These are vcols, sorry I don't make the rules + wlv->off++; + } + + if (wp->w_skipcol > 0 && wlv->startrow == 0 && wp->w_p_wrap && wp->w_briopt_sbr) { + wlv->need_showbreak = false; } } } static void handle_showbreak_and_filler(win_T *wp, winlinevars_T *wlv) { + int remaining = wp->w_grid.cols - wlv->off; if (wlv->filler_todo > wlv->filler_lines - wlv->n_virt_lines) { // TODO(bfredl): check this doesn't inhibit TUI-style // clear-to-end-of-line. - wlv->c_extra = ' '; - wlv->c_final = NUL; - wlv->n_extra = wp->w_grid.cols - wlv->col; - wlv->char_attr = 0; + draw_col_fill(wlv, schar_from_ascii(' '), remaining, 0); } else if (wlv->filler_todo > 0) { // Draw "deleted" diff line(s) - if (char2cells(wp->w_p_fcs_chars.diff) > 1) { - wlv->c_extra = '-'; - wlv->c_final = NUL; - } else { - wlv->c_extra = wp->w_p_fcs_chars.diff; - wlv->c_final = NUL; - } - wlv->n_extra = wp->w_grid.cols - wlv->col; - wlv->char_attr = win_hl_attr(wp, HLF_DED); + int c = (char2cells(wp->w_p_fcs_chars.diff) > 1) ? '-' : wp->w_p_fcs_chars.diff; + draw_col_fill(wlv, schar_from_char(c), remaining, win_hl_attr(wp, HLF_DED)); } char *const sbr = get_showbreak_value(wp); if (*sbr != NUL && wlv->need_showbreak) { // Draw 'showbreak' at the start of each broken line. - wlv->p_extra = sbr; - wlv->c_extra = NUL; - wlv->c_final = NUL; - wlv->n_extra = (int)strlen(sbr); - wlv->char_attr = win_hl_attr(wp, HLF_AT); if (wp->w_skipcol == 0 || wlv->startrow != 0 || !wp->w_p_wrap) { wlv->need_showbreak = false; } - wlv->vcol_sbr = wlv->vcol + mb_charlen(sbr); + // Combine 'showbreak' with 'cursorline', prioritizing 'showbreak'. + int attr = hl_combine_attr(wlv->cul_attr, win_hl_attr(wp, HLF_AT)); + int vcol_before = wlv->vcol; + draw_col_buf(wp, wlv, sbr, strlen(sbr), attr, true); + wlv->vcol_sbr = wlv->vcol; // Correct start of highlighted area for 'showbreak'. - if (wlv->fromcol >= wlv->vcol && wlv->fromcol < wlv->vcol_sbr) { + if (wlv->fromcol >= vcol_before && wlv->fromcol < wlv->vcol_sbr) { wlv->fromcol = wlv->vcol_sbr; } // Correct end of highlighted area for 'showbreak', // required when 'linebreak' is also set. - if (wlv->tocol == wlv->vcol) { - wlv->tocol += wlv->n_extra; - } - // Combine 'showbreak' with 'cursorline', prioritizing 'showbreak'. - if (wlv->cul_attr) { - wlv->char_attr = hl_combine_attr(wlv->cul_attr, wlv->char_attr); + if (wlv->tocol == vcol_before) { + wlv->tocol = wlv->vcol; } } } @@ -943,37 +931,7 @@ static void win_line_start(win_T *wp, winlinevars_T *wlv, bool save_extra) wlv->col = 0; wlv->off = 0; wlv->need_lbr = false; - - if (save_extra) { - // reset the drawing state for the start of a wrapped line - 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->need_lbr = true; - wlv->saved_char_attr = wlv->char_attr; - - wlv->n_extra = 0; - } -} - -/// Called when wlv->draw_state is set to WL_LINE. -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->c_extra = wlv->saved_c_extra; - wlv->c_final = wlv->saved_c_final; - wlv->p_extra = wlv->saved_p_extra; - wlv->extra_for_extmark = wlv->saved_extra_for_extmark; - wlv->char_attr = wlv->saved_char_attr; - } else { - wlv->char_attr = 0; - } + memset(linebuf_vcol, -1, (size_t)wp->w_grid.cols * sizeof(*linebuf_vcol)); } /// Display line "lnum" of window "wp" on the screen. @@ -1025,8 +983,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl int folded_attr = 0; // attributes for folded line int save_did_emsg; int eol_hl_off = 0; // 1 if highlighted char after EOL - bool draw_color_col = false; // highlight colorcolumn - int *color_cols = NULL; // pointer to according columns array #define SPWORDLEN 150 char nextline[SPWORDLEN * 2]; // text with start of the next line int nextlinecol = 0; // column where nextline[] starts @@ -1079,7 +1035,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl bool is_concealing = false; bool did_wcol = false; int old_boguscols = 0; -#define VCOL_HLC (wlv.vcol - wlv.vcol_off) +#define vcol_hlc(wlv) ((wlv).vcol - (wlv).vcol_off) #define FIX_FOR_BOGUSCOLS \ { \ wlv.n_extra += wlv.vcol_off; \ @@ -1136,10 +1092,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl } // Check for columns to display for 'colorcolumn'. - color_cols = wp->w_buffer->terminal ? NULL : wp->w_p_cc_cols; - if (color_cols != NULL) { - draw_color_col = advance_color_col(VCOL_HLC, &color_cols); - } + wlv.color_cols = wp->w_buffer->terminal ? NULL : wp->w_p_cc_cols; + advance_color_col(&wlv, vcol_hlc(wlv)); // handle Visual active in this window if (VIsual_active && wp->w_buffer == curwin->w_buffer) { @@ -1453,7 +1407,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl // - the visual mode is active, // the end of the line may be before the start of the displayed part. if (wlv.vcol < v && (wp->w_p_cuc - || draw_color_col + || wlv.color_cols || virtual_active() || (VIsual_active && wp->w_buffer == curwin->w_buffer))) { wlv.vcol = (colnr_T)v; @@ -1550,6 +1504,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl } win_line_start(wp, &wlv, false); + bool draw_cols = true; + int leftcols_width = 0; // won't highlight after TERM_ATTRS_MAX columns int term_attrs[TERM_ATTRS_MAX] = { 0 }; @@ -1558,7 +1514,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl extra_check = true; } - int sign_idx = 0; int virt_line_index; int virt_line_offset = -1; // Repeat for the whole displayed line. @@ -1569,119 +1524,85 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl bool did_decrement_ptr = false; // Skip this quickly when working on the text. - if (wlv.draw_state != WL_LINE) { + if (draw_cols) { if (cul_screenline) { wlv.cul_attr = 0; wlv.line_attr = line_attr_save; wlv.line_attr_lowprio = line_attr_lowprio_save; } - if (wlv.draw_state == WL_CMDLINE - 1 && wlv.n_extra == 0) { - wlv.draw_state = WL_CMDLINE; - if (cmdwin_type != 0 && wp == curwin) { - // Draw the cmdline character. - wlv.n_extra = 1; - wlv.c_extra = cmdwin_type; - wlv.c_final = NUL; - wlv.char_attr = win_hl_attr(wp, HLF_AT); - } - } - - if (wlv.draw_state == WL_FOLD - 1 && wlv.n_extra == 0) { - if (wlv.filler_todo > 0) { - int index = wlv.filler_todo - (wlv.filler_lines - wlv.n_virt_lines); - if (index > 0) { - virt_line_index = (int)kv_size(virt_lines) - index; - assert(virt_line_index >= 0); - virt_line_offset = kv_A(virt_lines, virt_line_index).left_col ? 0 : win_col_off(wp); - } - } - if (virt_line_offset == 0) { - // Skip the column states if there is a "virt_left_col" line. - wlv.draw_state = WL_BRI - 1; - } else if (statuscol.draw) { - // Skip fold, sign and number states if 'statuscolumn' is set. - wlv.draw_state = WL_STC - 1; - } - } + assert(wlv.off == 0); - if (wlv.draw_state == WL_FOLD - 1 && wlv.n_extra == 0) { - wlv.draw_state = WL_FOLD; - handle_foldcolumn(wp, &wlv); + if (cmdwin_type != 0 && wp == curwin) { + // Draw the cmdline character. + draw_col_fill(&wlv, schar_from_ascii(cmdwin_type), 1, |