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 /src | |
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
Diffstat (limited to 'src')
-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 |
8 files changed, 388 insertions, 459 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, win_hl_attr(wp, HLF_AT)); } - // sign column, this is hit until sign_idx reaches count - if (wlv.draw_state == WL_SIGN - 1 && wlv.n_extra == 0) { - // Show the sign column when desired. - wlv.draw_state = WL_SIGN; - if (wp->w_scwidth > 0) { - get_sign_display_info(false, wp, &wlv, sign_idx, sign_cul_attr); - if (++sign_idx < wp->w_scwidth) { - wlv.draw_state = WL_SIGN - 1; - } else { - sign_idx = 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 (wlv.draw_state == WL_NR - 1 && wlv.n_extra == 0) { - // Show the line number, if desired. - wlv.draw_state = WL_NR; - handle_lnum_col(wp, &wlv, sign_num_attr, sign_cul_attr); - } - - if (wlv.draw_state == WL_STC - 1 && wlv.n_extra == 0) { - wlv.draw_state = WL_STC; - // Draw the 'statuscolumn' if option is set. - if (statuscol.draw) { - if (sign_num_attr == 0) { - statuscol.num_attr = get_line_number_attr(wp, &wlv); + if (virt_line_offset == 0) { + // skip columns + } else if (statuscol.draw) { + // Draw 'statuscolumn' if it is set. + if (sign_num_attr == 0) { + statuscol.num_attr = get_line_number_attr(wp, &wlv); + } + if (statuscol.textp == NULL) { + v = (ptr - line); + get_statuscol_str(wp, lnum, wlv.row - startrow - wlv.filler_lines, &statuscol); + if (!end_fill) { + // Get the line again as evaluating 'statuscolumn' may free it. + line = ml_get_buf(wp->w_buffer, lnum); + ptr = line + v; } - if (statuscol.textp == NULL) { - v = (ptr - line); - get_statuscol_str(wp, lnum, wlv.row - startrow - wlv.filler_lines, &statuscol); - if (!end_fill) { - // Get the line again as evaluating 'statuscolumn' may free it. - line = ml_get_buf(wp->w_buffer, lnum); - ptr = line + v; - } - if (wp->w_redr_statuscol) { - break; - } + if (wp->w_redr_statuscol) { + break; } - get_statuscol_display_info(&statuscol, &wlv); } - } + draw_statuscol(wp, &statuscol, &wlv); + } else { + // draw builtin info columns: fold, sign, number + draw_foldcolumn(wp, &wlv); + + // wp->w_scwidth is zero if signcol=number is used + for (int sign_idx = 0; sign_idx < wp->w_scwidth; sign_idx++) { + draw_sign(false, wp, &wlv, sign_idx, sign_cul_attr); + } - if (wlv.draw_state == WL_STC && wlv.n_extra == 0) { - win_col_offset = wlv.off; + draw_lnum_col(wp, &wlv, sign_num_attr, sign_cul_attr); } + win_col_offset = wlv.off; + // Check if 'breakindent' applies and show it. // May change wlv.draw_state to WL_BRI or WL_BRI - 1. - if (wlv.n_extra == 0) { + if (!wp->w_briopt_sbr) { handle_breakindent(wp, &wlv); } - - if (wlv.draw_state == WL_SBR - 1 && wlv.n_extra == 0) { - wlv.draw_state = WL_SBR; - handle_showbreak_and_filler(wp, &wlv); + handle_showbreak_and_filler(wp, &wlv); + if (wp->w_briopt_sbr) { + handle_breakindent(wp, &wlv); } - if (wlv.draw_state == WL_LINE - 1 && wlv.n_extra == 0) { - sign_idx = 0; - wlv.draw_state = WL_LINE; - if (has_decor && wlv.row == startrow + wlv.filler_lines) { - // hide virt_text on text hidden by 'nowrap' or 'smoothscroll' - decor_redraw_col(wp, (colnr_T)(ptr - line) - 1, wlv.off, true, &decor_state); - } - win_line_continue(&wlv); // use wlv.saved_ values + wlv.col = wlv.off; + draw_cols = false; + if (wlv.filler_todo <= 0) { + leftcols_width = wlv.off; + } + if (has_decor && wlv.row == startrow + wlv.filler_lines) { + // hide virt_text on text hidden by 'nowrap' or 'smoothscroll' + decor_redraw_col(wp, (colnr_T)(ptr - line) - 1, wlv.off, true, &decor_state); } } - if (cul_screenline && wlv.draw_state == WL_LINE - && wlv.vcol >= left_curline_col - && wlv.vcol < right_curline_col) { + if (cul_screenline && wlv.vcol >= left_curline_col && wlv.vcol < right_curline_col) { apply_cursorline_highlight(wp, &wlv); } @@ -1690,7 +1611,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl && wp == curwin && lnum == wp->w_cursor.lnum && wlv.vcol >= wp->w_virtcol) - || (number_only && wlv.draw_state > WL_STC)) + || number_only) && wlv.filler_todo <= 0) { draw_virt_text(wp, buf, win_col_offset, &wlv.col, wlv.row); // don't clear anything after wlv.col @@ -1705,15 +1626,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl break; } - const bool draw_folded = wlv.draw_state == WL_LINE && has_fold - && wlv.row == startrow + wlv.filler_lines; + const bool draw_folded = has_fold && wlv.row == startrow + wlv.filler_lines; if (draw_folded && wlv.n_extra == 0) { wlv.char_attr = folded_attr = win_hl_attr(wp, HLF_FL); } int extmark_attr = 0; - if (wlv.draw_state == WL_LINE - && (area_highlighting || spv->spv_has_spell || extra_check)) { + if (area_highlighting || spv->spv_has_spell || extra_check) { if (wlv.n_extra == 0 || !wlv.extra_for_extmark) { wlv.reset_extra_attr = false; } @@ -1740,7 +1659,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl 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 (wlv.filler_todo <= 0) { + 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) { handle_inline_virtual_text(wp, &wlv, v); @@ -1924,28 +1845,31 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl // 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; - saved_search_attr = 0; - } - if (area_attr == 0 && *ptr != NUL) { - area_attr = saved_area_attr; - saved_area_attr = 0; - } - if (decor_attr == 0) { - decor_attr = saved_decor_attr; - saved_decor_attr = 0; - } + if (search_attr == 0) { + search_attr = saved_search_attr; + saved_search_attr = 0; + } + if (area_attr == 0 && *ptr != NUL) { + area_attr = saved_area_attr; + saved_area_attr = 0; + } + if (decor_attr == 0) { + decor_attr = saved_decor_attr; + saved_decor_attr = 0; + } - if (wlv.extra_for_extmark) { - // wlv.extra_attr should be used at this position but not - // any further. - wlv.reset_extra_attr = true; - } + 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 (wlv.filler_todo > 0) { + // Wait with reading text until filler lines are done. Still need to + // initialize these. + mb_c = ' '; + mb_schar = schar_from_ascii(' '); } else if (has_fold) { // skip writing the buffer line itself mb_c = NUL; @@ -2519,7 +2443,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl // In the cursor line and we may be concealing characters: correct // the cursor column when we reach its position. - if (!did_wcol && wlv.draw_state == WL_LINE + if (!did_wcol && wp == curwin && lnum == wp->w_cursor.lnum && conceal_cursor_line(wp) && (int)wp->w_virtcol <= wlv.vcol + wlv.skip_cells) { @@ -2530,7 +2454,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl } // Don't override visual selection highlighting. - if (wlv.n_attr > 0 && wlv.draw_state == WL_LINE && !search_attr_from_match) { + if (wlv.n_attr > 0 && !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; @@ -2547,7 +2471,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl && wp->w_p_list && (wp->w_p_wrap ? (wp->w_skipcol > 0 && wlv.row == 0) : wp->w_leftcol > 0) && wlv.filler_todo <= 0 - && wlv.draw_state > WL_STC && mb_c != NUL) { mb_c = wp->w_p_lcs_chars.prec; lcs_prec_todo = NUL; @@ -2638,9 +2561,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl wlv.col -= wlv.boguscols; wlv.boguscols = 0; - if (draw_color_col) { - draw_color_col = advance_color_col(VCOL_HLC, &color_cols); - } + advance_color_col(&wlv, vcol_hlc(wlv)); bool has_virttext = false; // Make sure alignment is the same regardless @@ -2653,10 +2574,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl } if (((wp->w_p_cuc - && wp->w_virtcol >= VCOL_HLC - eol_hl_off + && wp->w_virtcol >= vcol_hlc(wlv) - eol_hl_off && wp->w_virtcol < grid->cols * (ptrdiff_t)(wlv.row - startrow + 1) + v && lnum != wp->w_cursor.lnum) - || draw_color_col || wlv.line_attr_lowprio || wlv.line_attr + || wlv.color_cols || wlv.line_attr_lowprio || wlv.line_attr || wlv.diff_hlf != 0 || has_virttext)) { int rightmost_vcol = 0; @@ -2664,11 +2585,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl rightmost_vcol = wp->w_virtcol; } - if (draw_color_col) { + if (wlv.color_cols) { // determine rightmost colorcolumn to possibly draw - for (int i = 0; color_cols[i] >= 0; i++) { - if (rightmost_vcol < color_cols[i]) { - rightmost_vcol = color_cols[i]; + for (int i = 0; wlv.color_cols[i] >= 0; i++) { + if (rightmost_vcol < wlv.color_cols[i]) { + rightmost_vcol = wlv.color_cols[i]; } } } @@ -2693,15 +2614,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl linebuf_char[wlv.off] = schar_from_ascii(' '); linebuf_vcol[wlv.off] = MAXCOL; wlv.col++; - if (draw_color_col) { - draw_color_col = advance_color_col(VCOL_HLC, &color_cols); - } + advance_color_col(&wlv, vcol_hlc(wlv)); int col_attr = base_attr; - if (wp->w_p_cuc && VCOL_HLC == wp->w_virtcol) { + if (wp->w_p_cuc && vcol_hlc(wlv) == wp->w_virtcol) { col_attr = cuc_attr; - } else if (draw_color_col && VCOL_HLC == *color_cols) { + } else if (wlv.color_cols && vcol_hlc(wlv) == *wlv.color_cols) { col_attr = hl_combine_attr(wlv.line_attr_lowprio, mc_attr); } @@ -2710,7 +2629,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl linebuf_attr[wlv.off] = col_attr; wlv.off++; - if (VCOL_HLC >= rightmost_vcol) { + if (vcol_hlc(wlv) >= rightmost_vcol) { break; } @@ -2747,13 +2666,20 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW); conceal_cursor_used = conceal_cursor_line(curwin); } + + // When the window is too narrow draw all "@" lines. + if (leftcols_width >= wp->w_grid.cols && wp->w_p_wrap) { + win_draw_end(wp, '@', ' ', true, wlv.row, wp->w_grid.rows, HLF_AT); + set_empty_rows(wp, wlv.row); + wlv.row = endrow; + } + break; } // Show "extends" character from 'listchars' if beyond the line end and // 'list' is set. if (wp->w_p_lcs_chars.ext != NUL - && wlv.draw_state == WL_LINE && wp->w_p_list && !wp->w_p_wrap && wlv.filler_todo <= 0 @@ -2773,47 +2699,38 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl } } - // advance to the next 'colorcolumn' - if (draw_color_col) { - draw_color_col = advance_color_col(VCOL_HLC, &color_cols); - } + advance_color_col(&wlv, vcol_hlc(wlv)); // Highlight the cursor column if 'cursorcolumn' is set. But don't // highlight the cursor position itself. // Also highlight the 'colorcolumn' if it is different than // 'cursorcolumn' - // Also highlight the 'colorcolumn' if 'breakindent' and/or 'showbreak' - // options are set vcol_save_attr = -1; - if ((wlv.draw_state == WL_LINE - || wlv.draw_state == WL_BRI - || wlv.draw_state == WL_SBR) - && !lnum_in_visual_area + if (!lnum_in_visual_area && search_attr == 0 && area_attr == 0 && wlv.filler_todo <= 0) { - if (wp->w_p_cuc && VCOL_HLC == wp->w_virtcol + if (wp->w_p_cuc && vcol_hlc(wlv) == wp->w_virtcol && lnum != wp->w_cursor.lnum) { vcol_save_attr = wlv.char_attr; wlv.char_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUC), wlv.char_attr); - } else if (draw_color_col && VCOL_HLC == *color_cols) { + } else if (wlv.color_cols && vcol_hlc(wlv) == *wlv.color_cols) { vcol_save_attr = wlv.char_attr; wlv.char_attr = hl_combine_attr(win_hl_attr(wp, HLF_MC), wlv.char_attr); } } // Apply lowest-priority line attr now, so everything can override it. - if (wlv.draw_state == WL_LINE) { - wlv.char_attr = hl_combine_attr(wlv.line_attr_lowprio, wlv.char_attr); - } + wlv.char_attr = hl_combine_attr(wlv.line_attr_lowprio, wlv.char_attr); - if (wlv.draw_state == WL_LINE) { - vcol_prev = wlv.vcol; - } + vcol_prev = wlv.vcol; // Store character to be displayed. // Skip characters that are left of the screen for 'nowrap'. - if (wlv.draw_state < WL_LINE || wlv.skip_cells <= 0) { + if (wlv.filler_todo > 0) { + // TODO(bfredl): the main render loop should get called also with the virtual + // lines chunks, so we get line wrapping and other Nice Things. + } else if (wlv.skip_cells <= 0) { // Store the character. linebuf_char[wlv.off] = mb_schar; if (multi_attr) { @@ -2823,18 +2740,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl linebuf_attr[wlv.off] = wlv.char_attr; } - if (wlv.draw_state > WL_STC && wlv.filler_todo <= 0) { - linebuf_vcol[wlv.off] = wlv.vcol; - } else if (wlv.draw_state == WL_FOLD) { - if (wlv.n_closing > 0) { - linebuf_vcol[wlv.off] = -3; - wlv.n_closing--; - } else { - linebuf_vcol[wlv.off] = -2; - } - } else { - linebuf_vcol[wlv.off] = -1; - } + linebuf_vcol[wlv.off] = wlv.vcol; if (utf_char2cells(mb_c) > 1) { // Need to fill two screen columns. @@ -2844,11 +2750,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl linebuf_char[wlv.off] = 0; linebuf_attr[wlv.off] = linebuf_attr[wlv.off - 1]; - if (wlv.draw_state > WL_STC && wlv.filler_todo <= 0) { - linebuf_vcol[wlv.off] = ++wlv.vcol; - } else { - linebuf_vcol[wlv.off] = -1; - } + linebuf_vcol[wlv.off] = ++wlv.vcol; // When "wlv.tocol" is halfway through a character, set it to the end // of the character, otherwise highlighting won't stop. @@ -2904,15 +2806,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl } // The skipped cells need to be accounted for in vcol. - if (wlv.draw_state > WL_STC && wlv.skipped_cells > 0) { + if (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 - && wlv.filler_todo <= 0) { + if (wlv.filler_todo <= 0) { wlv.vcol++; } @@ -2921,12 +2822,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl } // restore attributes after "predeces" in 'listchars' - if (wlv.draw_state > WL_STC && n_attr3 > 0 && --n_attr3 == 0) { + if (n_attr3 > 0 && --n_attr3 == 0) { wlv.char_attr = saved_attr3; } // restore attributes after last 'listchars' or 'number' char - if (wlv.n_attr > 0 && wlv.draw_state == WL_LINE && --wlv.n_attr == 0) { + if (wlv.n_attr > 0 && --wlv.n_attr == 0) { wlv.char_attr = saved_attr2; } @@ -2947,8 +2848,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl // At end of screen line and there is more to come: Display the line // so far. If there is no more to display it is caught above. if (wlv.col >= grid->cols && (!has_fold || virt_line_offset >= 0) - && (wlv.draw_state != WL_LINE - || *ptr != NUL + && (*ptr != NUL || wlv.filler_todo > 0 || (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL && wlv.p_extra != at_end_str) @@ -2992,7 +2892,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl } // When the window is too narrow draw all "@" lines. - if (wlv.draw_state != WL_LINE && wlv.filler_todo <= 0) { + if (wlv.col <= leftcols_width) { win_draw_end(wp, '@', ' ', true, wlv.row, wp->w_grid.rows, HLF_AT); set_empty_rows(wp, wlv.row); wlv.row = endrow; @@ -3005,6 +2905,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl } win_line_start(wp, &wlv, true); + draw_cols = true; lcs_prec_todo = wp->w_p_lcs_chars.prec; if (wlv.filler_todo <= 0) { diff --git a/src/nvim/sign.c b/src/nvim/sign.c index 0647d65e93..690da8999e 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -26,6 +26,7 @@ #include "nvim/fold.h" #include "nvim/gettext.h" #include "nvim/globals.h" +#include "nvim/grid.h" #include "nvim/highlight.h" #include "nvim/highlight_group.h" #include "nvim/macros_defs.h" @@ -104,7 +105,7 @@ static void buf_set_sign(buf_T *buf, uint32_t *id, char *group, int prio, linenr DecorSignHighlight sign = DECOR_SIGN_HIGHLIGHT_INIT; sign.flags |= kSHIsSign; - sign.text.ptr = sp->sn_text ? xstrdup(sp->sn_text) : NULL; + memcpy(sign.text, sp->sn_text, SIGN_WIDTH * sizeof(schar_T)); sign.sign_name = xstrdup(sp->sn_name); sign.hl_id = sp->sn_text_hl; sign.line_hl_id = sp->sn_line_hl; @@ -113,7 +114,7 @@ static void buf_set_sign(buf_T *buf, uint32_t *id, char *group, int prio, linenr sign.priority = (DecorPriority)prio; bool has_hl = (sp->sn_line_hl || sp->sn_num_hl || sp->sn_cul_hl); - uint16_t decor_flags = (sp->sn_text ? MT_FLAG_DECOR_SIGNTEXT : 0) + uint16_t decor_flags = (sp->sn_text[0] ? MT_FLAG_DECOR_SIGNTEXT : 0) | (has_hl ? MT_FLAG_DECOR_SIGNHL : 0); DecorInline decor = { .ext = true, .data.ext = { .vt = NULL, .sh_idx = decor_put_sh(sign) } }; @@ -333,9 +334,24 @@ static int sign_cmd_idx(char *begin_cmd, char *end_cmd) return idx; } +/// buf must be SIGN_WIDTH * MAX_SCHAR_SIZE (no extra +1 needed) +size_t describe_sign_text(char *buf, schar_T *sign_text) +{ + size_t p = 0; + for (int i = 0; i < SIGN_WIDTH; i++) { + schar_get(buf + p, sign_text[i]); + size_t len = strlen(buf + p); + if (len == 0) { + break; + } + p += len; + } + return p; +} + /// Initialize the "text" for a new sign and store in "sign_text". /// "sp" is NULL for signs added through nvim_buf_set_extmark(). -int init_sign_text(sign_T *sp, char **sign_text, char *text) +int init_sign_text(sign_T *sp, schar_T *sign_text, char *text) { char *s; char *endp = text + (int)strlen(text); @@ -350,34 +366,29 @@ int init_sign_text(sign_T *sp, char **sign_text, char *text) // Count cells and check for non-printable chars int cells = 0; for (s = text; s < endp; s += utfc_ptr2len(s)) { - if (!vim_isprintc(utf_ptr2char(s))) { + int c; + sign_text[cells] = utfc_ptr2schar(s, &c); + if (!vim_isprintc(c)) { break; } - cells += utf_ptr2cells(s); + int width = utf_char2cells(c); + if (width == 2) { + sign_text[cells + 1] = 0; + } + cells += width; } // Currently must be empty, one or two display cells - if (s != endp || cells > 2) { + if (s != endp || cells > SIGN_WIDTH) { if (sp != NULL) { semsg(_("E239: Invalid sign text: %s"), text); } return FAIL; } - if (cells < 1) { - if (sp != NULL) { - sp->sn_text = NULL; - } - return OK; - } - if (sp != NULL) { - xfree(sp->sn_text); - } - // Allocate one byte more if we need to pad up with a space. - size_t len = (size_t)(endp - text + (cells == 1)); - *sign_text = xstrnsave(text, len); - - if (cells == 1) { - STRCPY(*sign_text + len - 1, " "); + if (cells < 1) { + sign_text[0] = 0; + } else if (cells == 1) { + sign_text[1] = schar_from_ascii(' '); } return OK; @@ -411,7 +422,7 @@ static int sign_define_by_name(char *name, char *icon, char *text, char *linehl, backslash_halve((*sp)->sn_icon); } - if (text != NULL && (init_sign_text(*sp, &(*sp)->sn_text, text) == FAIL)) { + if (text != NULL && (init_sign_text(*sp, (*sp)->sn_text, text) == FAIL)) { return FAIL; } @@ -436,7 +447,6 @@ static int sign_undefine_by_name(const char *name) } xfree(sp->sn_name); - xfree(sp->sn_text); xfree(sp->sn_icon); xfree(sp); return OK; @@ -451,9 +461,11 @@ static void sign_list_defined(sign_T *sp) msg_outtrans(sp->sn_icon, 0); msg_puts(_(" (not supported)")); } - if (sp->sn_text != NULL) { + if (sp->sn_text[0]) { msg_puts(" text="); - msg_outtrans(sp->sn_text, 0); + char buf[SIGN_WIDTH * MAX_SCHAR_SIZE]; + describe_sign_text(buf, sp->sn_text); + msg_outtrans(buf, 0); } static char *arg[] = { " linehl=", " texthl=", " culhl=", " numhl=" }; int hl[] = { sp->sn_line_hl, sp->sn_text_hl, sp->sn_cul_hl, sp->sn_num_hl }; @@ -880,8 +892,10 @@ static dict_T *sign_get_info_dict(sign_T *sp) if (sp->sn_icon != NULL) { tv_dict_add_str(d, S_LEN("icon"), sp->sn_icon); } - if (sp->sn_text != NULL) { - tv_dict_add_str(d, S_LEN("text"), sp->sn_text); + if (sp->sn_text[0]) { + char buf[SIGN_WIDTH * MAX_SCHAR_SIZE]; + describe_sign_text(buf, sp->sn_text); + tv_dict_add_str(d, S_LEN("text"), buf); } static char *arg[] = { "linehl", "texthl", "culhl", "numhl" }; int hl[] = { sp->sn_line_hl, sp->sn_text_hl, sp->sn_cul_hl, sp->sn_num_hl }; diff --git a/src/nvim/sign_defs.h b/src/nvim/sign_defs.h index 79d21585fc..7676fa5319 100644 --- a/src/nvim/sign_defs.h +++ b/src/nvim/sign_defs.h @@ -1,8 +1,10 @@ #pragma once +#include "nvim/types_defs.h" + /// Sign attributes. Used by the screen refresh routines. typedef struct { - char *text; + schar_T text[SIGN_WIDTH]; int hl_id; } SignTextAttrs; @@ -10,13 +12,12 @@ typedef struct { typedef struct sign { char *sn_name; // name of sign char *sn_icon; // name of pixmap - char *sn_text; // text used instead of pixmap + schar_T sn_text[SIGN_WIDTH]; // text used instead of pixmap int sn_line_hl; // highlight ID for line int sn_text_hl; // highlight ID for text int sn_cul_hl; // highlight ID for text on current line when 'cursorline' is set int sn_num_hl; // highlight ID for line number } sign_T; -enum { SIGN_WIDTH = 2, }; ///< Number of display cells for a sign in the signcolumn enum { SIGN_SHOW_MAX = 9, }; ///< Maximum number of signs shown on a single line enum { SIGN_DEF_PRIO = 10, }; ///< Default sign highlight priority diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index 112a433d9d..e249317bd3 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -1640,20 +1640,32 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op char *p = NULL; if (fold) { - size_t n = fill_foldcolumn(out_p, wp, stcp->foldinfo, - (linenr_T)get_vim_var_nr(VV_LNUM), NULL); + schar_T fold_buf[10]; + size_t n = fill_foldcolumn(NULL, wp, stcp->foldinfo, + (linenr_T)get_vim_var_nr(VV_LNUM), 0, fold_buf); stl_items[curitem].minwid = -((stcp->use_cul ? HLF_CLF : HLF_FC) + 1); + size_t buflen = 0; + // TODO(bfredl): this is very backwards. we must support schar_T + // being used directly in 'statuscol' + for (size_t i = 0; i < n; i++) { + schar_get(out_p + buflen, fold_buf[i]); + buflen += strlen(out_p + buflen); + } p = out_p; - p[n] = NUL; } + char buf[SIGN_WIDTH * MAX_SCHAR_SIZE]; size_t buflen = 0; varnumber_T virtnum = get_vim_var_nr(VV_VIRTNUM); for (int i = 0; i < width; i++) { if (!fold) { SignTextAttrs *sattr = virtnum ? NULL : &stcp->sattrs[i]; - p = sattr && sattr->text ? sattr->text : " "; - stl_items[curitem].minwid = -(sattr && sattr->text + p = " "; + if (sattr && sattr->text[0]) { + describe_sign_text(buf, sattr->text); + p = buf; + } + stl_items[curitem].minwid = -(sattr && sattr->text[0] ? (stcp->sign_cul_id ? stcp->sign_cul_id : sattr->hl_id) : (stcp->use_cul ? HLF_CLS : HLF_SC) + 1); } diff --git a/src/nvim/types_defs.h b/src/nvim/types_defs.h index b2c7101f60..0573439b73 100644 --- a/src/nvim/types_defs.h +++ b/src/nvim/types_defs.h @@ -56,6 +56,8 @@ typedef struct { } SignRange; #define SIGNRANGE_INIT { 0, 0 } +enum { SIGN_WIDTH = 2, }; ///< Number of display cells for a sign in the signcolumn + typedef struct file_buffer buf_T; typedef struct loop Loop; typedef struct regprog regprog_T; |