diff options
Diffstat (limited to 'src/nvim/drawline.c')
-rw-r--r-- | src/nvim/drawline.c | 148 |
1 files changed, 87 insertions, 61 deletions
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 8fc1a4b029..01ff207c2b 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -400,40 +400,56 @@ static int get_sign_attrs(buf_T *buf, linenr_T lnum, SignTextAttrs *sattrs, int /// Prepare and build the 'statuscolumn' string for line "lnum" in window "wp". /// Fill "stcp" with the built status column string and attributes. +/// This can be called three times per win_line(), once for virt_lines, once for +/// the start of the buffer line "lnum" and once for the wrapped lines. /// /// @param[out] stcp Status column attributes static void get_statuscol_str(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines, - int cul_attr, int sign_num_attr, int sign_cul_attr, char_u *extra, - foldinfo_T foldinfo, SignTextAttrs *sattrs, statuscol_T *stcp) + int cul_attr, int sign_num_attr, int sign_cul_attr, statuscol_T *stcp, + foldinfo_T foldinfo, SignTextAttrs *sattrs) { - long relnum = 0; - bool wrapped = row != startrow + filler_lines; + long relnum = -1; bool use_cul = use_cursor_line_sign(wp, lnum); + int virtnum = row - startrow - filler_lines; - // Set num, fold and sign text and attrs, empty when wrapped - if (row == startrow) { - relnum = labs(get_cursor_rel_lnum(wp, lnum)); + // When called the first time for line "lnum" set num_attr + if (stcp->num_attr == 0) { stcp->num_attr = sign_num_attr ? sign_num_attr : get_line_number_attr(wp, lnum, row, startrow, filler_lines); - + } + // When called for the first non-filler row of line "lnum" set num v:vars and fold column + if (virtnum == 0) { + relnum = labs(get_cursor_rel_lnum(wp, lnum)); if (compute_foldcolumn(wp, 0)) { size_t n = fill_foldcolumn(stcp->fold_text, wp, foldinfo, lnum); stcp->fold_text[n] = NUL; stcp->fold_attr = win_hl_attr(wp, use_cul ? HLF_CLF : HLF_FC); } } - + // Make sure to clear->set->clear sign column for filler->first->wrapped lines int i = 0; for (; i < wp->w_scwidth; i++) { - SignTextAttrs *sattr = wrapped ? NULL : sign_get_attr(i, sattrs, wp->w_scwidth); + SignTextAttrs *sattr = virtnum ? NULL : sign_get_attr(i, sattrs, wp->w_scwidth); stcp->sign_text[i] = sattr && sattr->text ? sattr->text : " "; stcp->sign_attr[i] = sattr ? (use_cul && sign_cul_attr ? sign_cul_attr : sattr->hl_attr_id) : win_hl_attr(wp, use_cul ? HLF_CLS : HLF_SC); } stcp->sign_text[i] = NULL; - int width = build_statuscol_str(wp, row == startrow, wrapped, lnum, relnum, - stcp->width, ' ', stcp->text, &stcp->hlrec, stcp); + // When a buffer's line count has changed, make a best estimate for the full + // width of the status column by building with "w_nrwidth_line_count". Add + // potentially truncated width and rebuild before drawing anything. + if (wp->w_statuscol_line_count != wp->w_nrwidth_line_count) { + wp->w_statuscol_line_count = wp->w_nrwidth_line_count; + set_vim_var_nr(VV_VIRTNUM, 0); + build_statuscol_str(wp, wp->w_nrwidth_line_count, 0, stcp->width, + ' ', stcp->text, &stcp->hlrec, stcp); + stcp->width += stcp->truncate; + } + set_vim_var_nr(VV_VIRTNUM, virtnum); + + int width = build_statuscol_str(wp, lnum, relnum, stcp->width, + ' ', stcp->text, &stcp->hlrec, stcp); // Force a redraw in case of error or when truncated if (*wp->w_p_stc == NUL || (stcp->truncate > 0 && wp->w_nrwidth < MAX_NUMBERWIDTH)) { if (stcp->truncate) { // Avoid truncating 'statuscolumn' @@ -466,9 +482,8 @@ static void get_statuscol_str(win_T *wp, linenr_T lnum, int row, int startrow, i /// /// @param stcp Status column attributes /// @param[out] draw_state Current draw state in win_line() -static void get_statuscol_display_info(LineDrawState *draw_state, int *char_attr, int *n_extrap, - int *c_extrap, int *c_finalp, char_u *extra, char **pp_extra, - statuscol_T *stcp) +static void get_statuscol_display_info(statuscol_T *stcp, LineDrawState *draw_state, int *char_attr, + int *n_extrap, int *c_extrap, int *c_finalp, char **pp_extra) { *c_extrap = NUL; *c_finalp = NUL; @@ -509,7 +524,7 @@ static bool use_cursor_line_nr(win_T *wp, linenr_T lnum, int row, int startrow, && (wp->w_p_culopt_flags & CULOPT_LINE))); } -static inline void get_line_number_str(win_T *wp, linenr_T lnum, char_u *buf, size_t buf_len) +static inline void get_line_number_str(win_T *wp, linenr_T lnum, char *buf, size_t buf_len) { long num; char *fmt = "%*ld "; @@ -527,7 +542,7 @@ static inline void get_line_number_str(win_T *wp, linenr_T lnum, char_u *buf, si } } - snprintf((char *)buf, buf_len, fmt, number_width(wp), num); + snprintf(buf, buf_len, fmt, number_width(wp), num); } static int get_line_number_attr(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines) @@ -608,7 +623,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, int row; // row in the window, excl w_winrow ScreenGrid *grid = &wp->w_grid; // grid specific to the window - char_u extra[57]; // sign, line number and 'fdc' must + char extra[57]; // sign, line number and 'fdc' must // fit in here int n_extra = 0; // number of extra chars char *p_extra = NULL; // string of extra chars, plus NUL @@ -802,7 +817,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, nextline[SPWORDLEN] = NUL; if (lnum < wp->w_buffer->b_ml.ml_line_count) { line = ml_get_buf(wp->w_buffer, lnum + 1, false); - spell_cat_line(nextline + SPWORDLEN, (char_u *)line, SPWORDLEN); + spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN); } // When a word wrapped from the previous line the start of the current @@ -936,7 +951,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, area_highlighting = true; } VirtLines virt_lines = KV_INITIAL_VALUE; - int n_virt_lines = decor_virt_lines(wp, lnum, &virt_lines); + int n_virt_lines = decor_virt_lines(wp, lnum, &virt_lines, has_fold); filler_lines += n_virt_lines; if (lnum == wp->w_topline) { filler_lines = wp->w_topfill; @@ -1128,7 +1143,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // no bad word found at line start, don't check until end of a // word spell_hlf = HLF_COUNT; - word_end = (int)(spell_to_word_end((char_u *)ptr, wp) - (char_u *)line + 1); + word_end = (int)(spell_to_word_end(ptr, wp) - line + 1); } else { // bad word found, use attributes until end of word assert(len <= INT_MAX); @@ -1200,6 +1215,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } int sign_idx = 0; + int virt_line_index; + int virt_line_offset = -1; // Repeat for the whole displayed line. for (;;) { int has_match_conc = 0; ///< match wants to conceal @@ -1226,9 +1243,22 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } } - // Skip fold, sign and number states if 'statuscolumn' is set. - if (draw_state == WL_FOLD - 1 && n_extra == 0 && statuscol.draw) { - draw_state = WL_STC - 1; + if (draw_state == WL_FOLD - 1 && n_extra == 0) { + if (filler_todo > 0) { + int index = filler_todo - (filler_lines - 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) { + // Skip the column states if there is a "virt_left_col" line. + draw_state = WL_BRI - 1; + } else if (statuscol.draw) { + // Skip fold, sign and number states if 'statuscolumn' is set. + draw_state = WL_STC - 1; + } } if (draw_state == WL_FOLD - 1 && n_extra == 0) { @@ -1259,7 +1289,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (wp->w_scwidth > 0) { get_sign_display_info(false, wp, lnum, sattrs, row, startrow, filler_lines, filler_todo, - &c_extra, &c_final, (char *)extra, sizeof(extra), + &c_extra, &c_final, extra, sizeof(extra), &p_extra, &n_extra, &char_attr, sign_idx, sign_cul_attr); sign_idx++; @@ -1284,29 +1314,29 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u' && num_signs > 0) { get_sign_display_info(true, wp, lnum, sattrs, row, startrow, filler_lines, filler_todo, - &c_extra, &c_final, (char *)extra, sizeof(extra), + &c_extra, &c_final, extra, sizeof(extra), &p_extra, &n_extra, &char_attr, sign_idx, sign_cul_attr); } else { // Draw the line number (empty space after wrapping). if (row == startrow + filler_lines) { - get_line_number_str(wp, lnum, (char_u *)extra, sizeof(extra)); + get_line_number_str(wp, lnum, extra, sizeof(extra)); if (wp->w_skipcol > 0) { - for (p_extra = (char *)extra; *p_extra == ' '; p_extra++) { + for (p_extra = extra; *p_extra == ' '; p_extra++) { *p_extra = '-'; } } if (wp->w_p_rl) { // reverse line numbers // like rl_mirror(), but keep the space at the end - char *p2 = skipwhite((char *)extra); + char *p2 = skipwhite(extra); p2 = skiptowhite(p2) - 1; - for (char *p1 = skipwhite((char *)extra); p1 < p2; p1++, p2--) { + for (char *p1 = skipwhite(extra); p1 < p2; p1++, p2--) { const char t = *p1; *p1 = *p2; *p2 = t; } } - p_extra = (char *)extra; + p_extra = extra; c_extra = NUL; } else { c_extra = ' '; @@ -1327,14 +1357,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Draw the 'statuscolumn' if option is set. if (statuscol.draw) { if (statuscol.textp == NULL) { - get_statuscol_str(wp, lnum, row, startrow, filler_lines, cul_attr, sign_num_attr, - sign_cul_attr, extra, foldinfo, sattrs, &statuscol); + get_statuscol_str(wp, lnum, row, startrow, filler_lines, cul_attr, + sign_num_attr, sign_cul_attr, &statuscol, foldinfo, sattrs); if (wp->w_redr_statuscol) { - return 0; + break; } } - get_statuscol_display_info(&draw_state, &char_attr, &n_extra, &c_extra, - &c_final, extra, &p_extra, &statuscol); + get_statuscol_display_info(&statuscol, &draw_state, &char_attr, + &n_extra, &c_extra, &c_final, &p_extra); } } @@ -1413,7 +1443,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } char_attr = win_hl_attr(wp, HLF_DED); } - char *const sbr = (char *)get_showbreak_value(wp); + char *const sbr = get_showbreak_value(wp); if (*sbr != NUL && need_showbreak) { // Draw 'showbreak' at the start of each broken line. p_extra = sbr; @@ -1488,7 +1518,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && has_fold && col == win_col_offset && n_extra == 0 - && row == startrow) { + && row == startrow + filler_lines) { char_attr = win_hl_attr(wp, HLF_FL); linenr_T lnume = lnum + foldinfo.fi_lines - 1; @@ -1509,7 +1539,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && has_fold && col < grid->cols && n_extra == 0 - && row == startrow) { + && row == startrow + filler_lines) { // fill rest of line with 'fold' c_extra = wp->w_p_fcs_chars.fold; c_final = NUL; @@ -1521,7 +1551,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && has_fold && col >= grid->cols && n_extra != 0 - && row == startrow) { + && row == startrow + filler_lines) { // Truncate the folding. n_extra = 0; } @@ -1710,14 +1740,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, || (mb_l > 1 && (!vim_isprintc(mb_c)))) { // Illegal UTF-8 byte: display as <xx>. // Non-BMP character : display as ? or fullwidth ?. - transchar_hex((char *)extra, mb_c); + transchar_hex(extra, mb_c); if (wp->w_p_rl) { // reverse - rl_mirror((char *)extra); + rl_mirror(extra); } - p_extra = (char *)extra; + p_extra = extra; c = (uint8_t)(*p_extra); - mb_c = mb_ptr2char_adv((const char_u **)&p_extra); + mb_c = mb_ptr2char_adv((const char **)&p_extra); mb_utf8 = (c >= 0x80); n_extra = (int)strlen(p_extra); c_extra = NUL; @@ -1805,7 +1835,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, syntax_attr = get_syntax_attr((colnr_T)v - 1, has_spell ? &can_spell : NULL, false); - if (did_emsg) { + if (did_emsg) { // -V547 wp->w_s->b_syn_error = true; has_syntax = false; } else { @@ -1890,7 +1920,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, p = prev_ptr; } cap_col -= (int)(prev_ptr - line); - size_t tmplen = spell_check(wp, (char_u *)p, &spell_hlf, &cap_col, nochange); + size_t tmplen = spell_check(wp, p, &spell_hlf, &cap_col, nochange); assert(tmplen <= INT_MAX); len = (int)tmplen; word_end = (int)v + len; @@ -1960,7 +1990,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // We have just drawn the showbreak value, no need to add // space for it again. if (vcol == vcol_sbr) { - n_extra -= mb_charlen((char *)get_showbreak_value(wp)); + n_extra -= mb_charlen(get_showbreak_value(wp)); if (n_extra < 0) { n_extra = 0; } @@ -2056,12 +2086,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (c == TAB && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) { int tab_len = 0; long vcol_adjusted = vcol; // removed showbreak length - char_u *const sbr = get_showbreak_value(wp); + char *const sbr = get_showbreak_value(wp); // Only adjust the tab_len, when at the first column after the // showbreak value was drawn. if (*sbr != NUL && vcol == vcol_sbr && wp->w_p_wrap) { - vcol_adjusted = vcol - mb_charlen((char *)sbr); + vcol_adjusted = vcol - mb_charlen(sbr); } // tab amount depends on current column tab_len = tabstop_padding((colnr_T)vcol_adjusted, @@ -2734,7 +2764,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // 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 ((wp->w_p_rl ? (col < 0) : (col >= grid->cols)) - && foldinfo.fi_lines == 0 + && (!has_fold || virt_line_offset >= 0) && (draw_state != WL_LINE || *ptr != NUL || filler_todo > 0 @@ -2751,15 +2781,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && !wp->w_p_rl; // Not right-to-left. int draw_col = col - boguscols; - if (filler_todo > 0) { - int index = filler_todo - (filler_lines - n_virt_lines); - if (index > 0) { - int i = (int)kv_size(virt_lines) - index; - assert(i >= 0); - int offset = kv_A(virt_lines, i).left_col ? 0 : win_col_offset; - draw_virt_text_item(buf, offset, kv_A(virt_lines, i).line, - kHlModeReplace, grid->cols, 0); - } + 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 { draw_virt_text(wp, buf, win_col_offset, &draw_col, grid->cols, row); } @@ -2819,16 +2843,18 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, need_showbreak = true; } if (statuscol.draw) { - if (row == startrow + 1 || row == startrow + filler_lines) { + if (row == startrow + filler_lines + 1 || row == startrow + filler_lines) { // Re-evaluate 'statuscolumn' for the first wrapped row and non filler line statuscol.textp = NULL; - } else { // Otherwise just reset the text/hlrec pointers + } else if (statuscol.textp) { + // Draw the already built 'statuscolumn' on the next wrapped or filler line statuscol.textp = statuscol.text; statuscol.hlrecp = statuscol.hlrec; } // Fall back to default columns if the 'n' flag isn't in 'cpo' statuscol.draw = vim_strchr(p_cpo, CPO_NUMCOL) == NULL; } filler_todo--; + virt_line_offset = -1; // When the filler lines are actually below the last line of the // file, don't draw the line itself, break here. if (filler_todo == 0 && (wp->w_botfill || end_fill)) { |