diff options
Diffstat (limited to 'src/nvim/drawline.c')
-rw-r--r-- | src/nvim/drawline.c | 480 |
1 files changed, 337 insertions, 143 deletions
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 2b1b2607fb..e24d86b353 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -5,38 +5,69 @@ // This is the middle level, drawscreen.c is the top and grid.c/screen.c the lower level. #include <assert.h> -#include <inttypes.h> +#include <limits.h> #include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> #include <string.h> #include "nvim/arabic.h" +#include "nvim/ascii.h" #include "nvim/buffer.h" #include "nvim/charset.h" #include "nvim/cursor.h" #include "nvim/cursor_shape.h" +#include "nvim/decoration.h" +#include "nvim/decoration_provider.h" #include "nvim/diff.h" #include "nvim/drawline.h" +#include "nvim/eval.h" +#include "nvim/extmark_defs.h" #include "nvim/fold.h" +#include "nvim/garray.h" +#include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/highlight.h" #include "nvim/highlight_group.h" #include "nvim/indent.h" +#include "nvim/mark.h" #include "nvim/match.h" +#include "nvim/mbyte.h" +#include "nvim/memline.h" +#include "nvim/memory.h" #include "nvim/move.h" #include "nvim/option.h" #include "nvim/plines.h" +#include "nvim/pos.h" #include "nvim/quickfix.h" -#include "nvim/search.h" +#include "nvim/screen.h" #include "nvim/sign.h" #include "nvim/spell.h" #include "nvim/state.h" +#include "nvim/statusline.h" +#include "nvim/strings.h" #include "nvim/syntax.h" -#include "nvim/undo.h" -#include "nvim/window.h" +#include "nvim/terminal.h" +#include "nvim/types.h" +#include "nvim/ui.h" +#include "nvim/vim.h" #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; + /// for line_putchar. Contains the state that needs to be remembered from /// putting one character to the next. typedef struct { @@ -109,9 +140,9 @@ static void margin_columns_win(win_T *wp, int *left_col, int *right_col) /// Handles composing chars and arabic shaping state. static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, bool rl, int vcol) { - const char_u *p = (char_u *)s->p; - int cells = utf_ptr2cells((char *)p); - int c_len = utfc_ptr2len((char *)p); + const char *p = s->p; + int cells = utf_ptr2cells(p); + int c_len = utfc_ptr2len(p); int u8c, u8cc[MAX_MCO]; if (cells > maxcells) { return -1; @@ -123,22 +154,22 @@ static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, b schar_from_ascii(dest[c], ' '); } goto done; - } else if (*p < 0x80 && u8cc[0] == 0) { - schar_from_ascii(dest[0], (char)(*p)); + } else if ((uint8_t)(*p) < 0x80 && u8cc[0] == 0) { + schar_from_ascii(dest[0], *p); s->prev_c = u8c; } else { if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c)) { // Do Arabic shaping. int pc, pc1, nc; int pcc[MAX_MCO]; - int firstbyte = *p; + int firstbyte = (uint8_t)(*p); // The idea of what is the previous and next // character depends on 'rightleft'. if (rl) { pc = s->prev_c; pc1 = s->prev_c1; - nc = utf_ptr2char((char *)p + c_len); + nc = utf_ptr2char(p + c_len); s->prev_c1 = u8cc[0]; } else { pc = utfc_ptr2char(p + c_len, pcc); @@ -277,7 +308,7 @@ static bool use_cursor_line_sign(win_T *wp, linenr_T lnum) } // Get information needed to display the sign in line 'lnum' in window 'wp'. -// If 'nrcol' is TRUE, the sign is going to be displayed in the number column. +// 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. // // @param count max number of signs @@ -285,8 +316,8 @@ static bool use_cursor_line_sign(win_T *wp, linenr_T lnum) // @param sign_idxp Index of the displayed sign static void get_sign_display_info(bool nrcol, win_T *wp, linenr_T lnum, SignTextAttrs sattrs[], int row, int startrow, int filler_lines, int filler_todo, - int *c_extrap, int *c_finalp, char_u *extra, size_t extra_size, - char_u **pp_extra, int *n_extrap, int *char_attrp, int sign_idx, + int *c_extrap, int *c_finalp, char *extra, size_t extra_size, + char **pp_extra, int *n_extrap, int *char_attrp, int sign_idx, int cul_attr) { // Draw cells with the sign value or blank. @@ -320,16 +351,16 @@ static void get_sign_display_info(bool nrcol, win_T *wp, linenr_T lnum, SignText STRCAT(extra, *pp_extra); STRCAT(extra, " "); *pp_extra = extra; - *n_extrap = (int)STRLEN(*pp_extra); + *n_extrap = (int)strlen(*pp_extra); } else { - size_t symbol_blen = STRLEN(*pp_extra); + size_t symbol_blen = strlen(*pp_extra); // TODO(oni-link): Is sign text already extended to // full cell width? assert((size_t)win_signcol_width(wp) >= mb_string2cells((char *)(*pp_extra))); // symbol(s) bytes + (filling spaces) (one byte each) *n_extrap = (int)symbol_blen + win_signcol_width(wp) - - (int)mb_string2cells((char *)(*pp_extra)); + (int)mb_string2cells(*pp_extra); assert(extra_size > symbol_blen); memset(extra, ' ', extra_size); @@ -367,6 +398,102 @@ static int get_sign_attrs(buf_T *buf, linenr_T lnum, SignTextAttrs *sattrs, int return num_signs; } +/// 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, statuscol_T *stcp, + foldinfo_T foldinfo, SignTextAttrs *sattrs) +{ + long relnum = -1; + bool use_cul = use_cursor_line_sign(wp, lnum); + int virtnum = row - startrow - filler_lines; + + set_vim_var_nr(VV_VIRTNUM, virtnum); + // 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 = 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, 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' + wp->w_nrwidth = MIN(MAX_NUMBERWIDTH, wp->w_nrwidth + stcp->truncate); + wp->w_nrwidth_width = wp->w_nrwidth; + } else { // 'statuscolumn' reset due to error + wp->w_nrwidth_line_count = 0; + wp->w_nrwidth = (wp->w_p_nu || wp->w_p_rnu) * number_width(wp); + } + wp->w_redr_statuscol = true; + return; + } + + // Reset text/highlight pointer and current attr for new line + stcp->textp = stcp->text; + stcp->hlrecp = stcp->hlrec; + stcp->cur_attr = stcp->num_attr; + stcp->text_end = stcp->text + strlen(stcp->text); + + int fill = stcp->width - width; + if (fill > 0) { + // Fill up with ' ' + memset(stcp->text_end, ' ', (size_t)fill); + *(stcp->text_end += fill) = NUL; + } +} + +/// Get information needed to display the next segment in the 'statuscolumn'. +/// If not yet at the end, prepare for next segment and decrement "draw_state". +/// +/// @param stcp Status column attributes +/// @param[out] draw_state Current draw state in win_line() +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; + do { + *draw_state = WL_STC; + *char_attr = stcp->cur_attr; + *pp_extra = stcp->textp; + *n_extrap = (int)((stcp->hlrecp->start ? stcp->hlrecp->start : stcp->text_end) - stcp->textp); + // Prepare for next highlight section if not yet at the end + if (stcp->textp + *n_extrap < stcp->text_end) { + int hl = stcp->hlrecp->userhl; + stcp->textp = stcp->hlrecp->start; + stcp->cur_attr = hl < 0 ? syn_id2attr(-stcp->hlrecp->userhl) + : hl > 0 ? hl : stcp->num_attr; + stcp->hlrecp++; + *draw_state = WL_STC - 1; + } + // Skip over empty highlight sections + } while (*n_extrap == 0 && stcp->textp < stcp->text_end); +} + /// Return true if CursorLineNr highlight is to be used for the number column. /// /// - 'cursorline' must be set @@ -386,7 +513,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 "; @@ -404,7 +531,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) @@ -480,29 +607,28 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, long vcol = 0; // virtual column (for tabs) long vcol_sbr = -1; // virtual column after showbreak long vcol_prev = -1; // "vcol" of previous character - char_u *line; // current line - char_u *ptr; // current position in "line" + char *line; // current line + char *ptr; // current position in "line" 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_u *p_extra = NULL; // string of extra chars, plus NUL - char_u *p_extra_free = NULL; // p_extra needs to be freed + char *p_extra = NULL; // string of extra chars, plus NUL + char *p_extra_free = NULL; // p_extra needs to be freed int c_extra = NUL; // extra chars, all the same int c_final = NUL; // final char, mandatory if set int extra_attr = 0; // attributes when n_extra != 0 - static char_u *at_end_str = (char_u *)""; // used for p_extra when displaying - // curwin->w_p_lcs_chars.eol at - // end-of-line + static char *at_end_str = ""; // used for p_extra when displaying curwin->w_p_lcs_chars.eol + // at end-of-line int lcs_eol_one = wp->w_p_lcs_chars.eol; // 'eol' until it's been used int lcs_prec_todo = wp->w_p_lcs_chars.prec; // 'prec' until it's been used bool has_fold = foldinfo.fi_level != 0 && foldinfo.fi_lines > 0; // saved "extra" items for when draw_state becomes WL_LINE (again) int saved_n_extra = 0; - char_u *saved_p_extra = NULL; + char *saved_p_extra = NULL; int saved_c_extra = 0; int saved_c_final = 0; int saved_char_attr = 0; @@ -525,7 +651,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, int char_attr = 0; // attributes for next character bool attr_pri = false; // char_attr has priority bool area_highlighting = false; // Visual or incsearch highlighting in this line - int attr = 0; // attributes for area highlighting + int vi_attr = 0; // attributes for Visual and incsearch highlighting int area_attr = 0; // attributes desired by highlighting int search_attr = 0; // attributes desired by 'hlsearch' int vcol_save_attr = 0; // saved attr for 'cursorcolumn' @@ -537,7 +663,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, int *color_cols = NULL; // pointer to according columns array bool has_spell = false; // this buffer has spell checking #define SPWORDLEN 150 - char_u nextline[SPWORDLEN * 2]; // text with start of the next line + char nextline[SPWORDLEN * 2]; // text with start of the next line int nextlinecol = 0; // column where nextline[] starts int nextline_idx = 0; // index in nextline[] where next line // starts @@ -576,7 +702,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, bool has_decor = false; // this buffer has decoration int win_col_offset = 0; // offset for window columns - char_u buf_fold[FOLD_TEXT_LEN]; // Hold value returned by get_foldtext + char buf_fold[FOLD_TEXT_LEN]; // Hold value returned by get_foldtext bool area_active = false; @@ -588,17 +714,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, int left_curline_col = 0; int right_curline_col = 0; - // draw_state: items that are drawn in sequence: -#define WL_START 0 // nothing done yet -#define WL_CMDLINE (WL_START + 1) // cmdline window column -#define WL_FOLD (WL_CMDLINE + 1) // 'foldcolumn' -#define WL_SIGN (WL_FOLD + 1) // column for signs -#define WL_NR (WL_SIGN + 1) // line number -#define WL_BRI (WL_NR + 1) // 'breakindent' -#define WL_SBR (WL_BRI + 1) // 'showbreak' or 'diff' -#define WL_LINE (WL_SBR + 1) // text in the line - int draw_state = WL_START; // what to draw next + LineDrawState draw_state = WL_START; // what to draw next + int match_conc = 0; ///< cchar for match functions + bool on_last_col = false; int syntax_flags = 0; int syntax_seqnr = 0; int prev_syntax_id = 0; @@ -608,7 +727,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, ///< force wrapping int vcol_off = 0; ///< offset for concealed characters int did_wcol = false; - int match_conc = 0; ///< cchar for match functions int old_boguscols = 0; #define VCOL_HLC (vcol - vcol_off) #define FIX_FOR_BOGUSCOLS \ @@ -654,7 +772,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, has_decor = decor_redraw_line(buf, lnum - 1, &decor_state); - providers_invoke_line(wp, providers, lnum - 1, &has_decor, provider_err); + decor_providers_invoke_line(wp, providers, lnum - 1, &has_decor, provider_err); if (*provider_err) { provider_err_virt_text(lnum, *provider_err); @@ -772,7 +890,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // if inverting in this line set area_highlighting if (fromcol >= 0) { area_highlighting = true; - attr = win_hl_attr(wp, HLF_V); + vi_attr = win_hl_attr(wp, HLF_V); } // handle 'incsearch' and ":s///c" highlighting } else if (highlight_match @@ -796,15 +914,16 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, tocol = fromcol + 1; } area_highlighting = true; - attr = win_hl_attr(wp, HLF_I); + vi_attr = win_hl_attr(wp, HLF_I); } } int bg_attr = win_bg_attr(wp); - filler_lines = diff_check(wp, lnum); - if (filler_lines < 0) { - if (filler_lines == -1) { + int linestatus = 0; + filler_lines = diff_check_with_linestatus(wp, lnum, &linestatus); + if (filler_lines < 0 || linestatus < 0) { + if (filler_lines == -1 || linestatus == -1) { if (diff_find_change(wp, lnum, &change_start, &change_end)) { diff_hlf = HLF_ADD; // added line } else if (change_start == 0) { @@ -815,11 +934,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } else { diff_hlf = HLF_ADD; // added line } - filler_lines = 0; + if (linestatus == 0) { + filler_lines = 0; + } 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; @@ -864,7 +985,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, line_attr_lowprio_save = line_attr_lowprio; } - line = end_fill ? (char_u *)"" : ml_get_buf(wp->w_buffer, lnum, false); + line = end_fill ? "" : ml_get_buf(wp->w_buffer, lnum, false); ptr = line; if (has_spell && !number_only) { @@ -881,7 +1002,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, nextlinecol = MAXCOL; nextline_idx = 0; } else { - v = (long)STRLEN(line); + v = (long)strlen(line); if (v < SPWORDLEN) { // Short line, use it completely and append the start of the // next line. @@ -892,7 +1013,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } else { // Long line, use only the last SPWORDLEN bytes. nextlinecol = (int)v - SPWORDLEN; - memmove(nextline, line + nextlinecol, SPWORDLEN); // -V512 + memmove(nextline, line + nextlinecol, SPWORDLEN); // -V1086 nextline_idx = SPWORDLEN + 1; } } @@ -909,7 +1030,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } // find start of trailing whitespace if (wp->w_p_lcs_chars.trail) { - trailcol = (colnr_T)STRLEN(ptr); + trailcol = (colnr_T)strlen(ptr); while (trailcol > (colnr_T)0 && ascii_iswhite(ptr[trailcol - 1])) { trailcol--; } @@ -939,13 +1060,20 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, v = wp->w_leftcol; } if (v > 0 && !number_only) { - char_u *prev_ptr = ptr; - while (vcol < v && *ptr != NUL) { - c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL); - vcol += c; - prev_ptr = ptr; - MB_PTR_ADV(ptr); + char *prev_ptr = ptr; + chartabsize_T cts; + int charsize; + + init_chartabsize_arg(&cts, wp, lnum, (colnr_T)vcol, line, ptr); + while (cts.cts_vcol < v && *cts.cts_ptr != NUL) { + charsize = win_lbr_chartabsize(&cts, NULL); + cts.cts_vcol += charsize; + prev_ptr = cts.cts_ptr; + MB_PTR_ADV(cts.cts_ptr); } + vcol = cts.cts_vcol; + ptr = cts.cts_ptr; + clear_chartabsize_arg(&cts); // When: // - 'cuc' is set, or @@ -963,11 +1091,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Handle a character that's not completely on the screen: Put ptr at // that character but skip the first few screen characters. if (vcol > v) { - vcol -= c; + vcol -= charsize; ptr = prev_ptr; // If the character fits on the screen, don't need to skip it. // Except for a TAB. - if (utf_ptr2cells((char *)ptr) >= c || *ptr == TAB) { + if (utf_ptr2cells(ptr) >= charsize || *ptr == TAB) { n_skip = (int)(v - vcol); } } @@ -1068,7 +1196,16 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, extra_check = true; } + statuscol_T statuscol = { 0 }; + if (*wp->w_p_stc != NUL) { + // Draw the 'statuscolumn' if option is set. + statuscol.draw = true; + statuscol.width = win_col_off(wp); + } + 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 @@ -1096,8 +1233,25 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } if (draw_state == WL_FOLD - 1 && n_extra == 0) { - int fdc = compute_foldcolumn(wp, 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) { + int fdc = compute_foldcolumn(wp, 0); draw_state = WL_FOLD; if (fdc > 0) { // Draw the 'foldcolumn'. Allocate a buffer, "extra" may @@ -1155,7 +1309,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } 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 = extra; *p_extra == ' '; p_extra++) { *p_extra = '-'; @@ -1163,10 +1317,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } if (wp->w_p_rl) { // reverse line numbers // like rl_mirror(), but keep the space at the end - char_u *p2 = (char_u *)skipwhite((char *)extra); + char *p2 = skipwhite(extra); p2 = skiptowhite(p2) - 1; - for (char_u *p1 = (char_u *)skipwhite((char *)extra); p1 < p2; p1++, p2--) { - const char_u t = *p1; + for (char *p1 = skipwhite(extra); p1 < p2; p1++, p2--) { + const char t = *p1; *p1 = *p2; *p2 = t; } @@ -1187,7 +1341,23 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } } - if (draw_state == WL_NR && n_extra == 0) { + if (draw_state == WL_STC - 1 && n_extra == 0) { + draw_state = WL_STC; + // 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, &statuscol, foldinfo, sattrs); + if (wp->w_redr_statuscol) { + break; + } + } + get_statuscol_display_info(&statuscol, &draw_state, &char_attr, + &n_extra, &c_extra, &c_final, &p_extra); + } + } + + if (draw_state == WL_STC && n_extra == 0) { win_col_offset = off; } @@ -1247,7 +1417,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } char_attr = 0; } else if (filler_todo > 0) { - // draw "deleted" diff line(s) + // Draw "deleted" diff line(s) if (char2cells(wp->w_p_fcs_chars.diff) > 1) { c_extra = '-'; c_final = NUL; @@ -1262,13 +1432,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } char_attr = win_hl_attr(wp, HLF_DED); } - char_u *const sbr = 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; c_extra = NUL; c_final = NUL; - n_extra = (int)STRLEN(sbr); + n_extra = (int)strlen(sbr); char_attr = win_hl_attr(wp, HLF_AT); if (wp->w_skipcol == 0 || !wp->w_p_wrap) { need_showbreak = false; @@ -1319,7 +1489,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && wp == curwin && lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol) - || (number_only && draw_state > WL_NR)) + || (number_only && draw_state > WL_STC)) && filler_todo <= 0) { draw_virt_text(wp, buf, win_col_offset, &col, grid->cols, row); grid_put_linebuf(grid, row, 0, col, -grid->cols, wp->w_p_rl, wp, bg_attr, false); @@ -1337,13 +1507,13 @@ 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; memset(buf_fold, ' ', FOLD_TEXT_LEN); p_extra = get_foldtext(wp, lnum, lnume, foldinfo, buf_fold); - n_extra = (int)STRLEN(p_extra); + n_extra = (int)strlen(p_extra); if (p_extra != buf_fold) { xfree(p_extra_free); @@ -1358,7 +1528,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; @@ -1370,7 +1540,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; } @@ -1379,11 +1549,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // handle Visual or match highlighting in this line if (vcol == fromcol || (vcol + 1 == fromcol && n_extra == 0 - && utf_ptr2cells((char *)ptr) > 1) + && utf_ptr2cells(ptr) > 1) || ((int)vcol_prev == fromcol_prev && vcol_prev < vcol // not at margin && vcol < tocol)) { - area_attr = attr; // start highlighting + area_attr = vi_attr; // start highlighting if (area_highlighting) { area_active = true; } @@ -1400,8 +1570,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // When another match, have to check for start again. v = (ptr - line); search_attr = update_search_hl(wp, lnum, (colnr_T)v, &line, &screen_search_hl, - &has_match_conc, - &match_conc, lcs_eol_one, &search_attr_from_match); + &has_match_conc, &match_conc, lcs_eol_one, + &on_last_col, &search_attr_from_match); ptr = line + v; // "line" may have been changed // Do not allow a conceal over EOL otherwise EOL will be missed @@ -1473,11 +1643,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, mb_utf8 = check_mb_utf8(&c, u8cc); } else { assert(p_extra != NULL); - c = *p_extra; + c = (uint8_t)(*p_extra); mb_c = c; // If the UTF-8 character is more than one byte: // Decode it into "mb_c". - mb_l = utfc_ptr2len((char *)p_extra); + mb_l = utfc_ptr2len(p_extra); mb_utf8 = false; if (mb_l > n_extra) { mb_l = 1; @@ -1526,11 +1696,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, XFREE_CLEAR(p_extra_free); // Get a character from the line itself. - c0 = c = *ptr; + c0 = c = (uint8_t)(*ptr); mb_c = c; // If the UTF-8 character is more than one byte: Decode it // into "mb_c". - mb_l = utfc_ptr2len((char *)ptr); + mb_l = utfc_ptr2len(ptr); mb_utf8 = false; if (mb_l > 1) { mb_c = utfc_ptr2char(ptr, u8cc); @@ -1559,16 +1729,16 @@ 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(extra); } p_extra = extra; - c = *p_extra; - mb_c = mb_ptr2char_adv((const char_u **)&p_extra); + c = (uint8_t)(*p_extra); + mb_c = mb_ptr2char_adv((const char **)&p_extra); mb_utf8 = (c >= 0x80); - n_extra = (int)STRLEN(p_extra); + n_extra = (int)strlen(p_extra); c_extra = NUL; c_final = NUL; if (area_attr == 0 && search_attr == 0) { @@ -1588,7 +1758,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (wp->w_p_rl) { pc = prev_c; pc1 = prev_c1; - nc = utf_ptr2char((char *)ptr + mb_l); + nc = utf_ptr2char(ptr + mb_l); prev_c1 = u8cc[0]; } else { pc = utfc_ptr2char(ptr + mb_l, pcc); @@ -1639,7 +1809,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, ptr++; if (extra_check) { - bool can_spell = true; + bool no_plain_buffer = (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) != 0; + bool can_spell = !no_plain_buffer; // Get syntax attribute, unless still at the start of the line // (double-wide char that doesn't fit). @@ -1653,7 +1824,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 { @@ -1691,6 +1862,27 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, char_attr = 0; } + if (has_decor && v > 0) { + bool selected = (area_active || (area_highlighting && noinvcur + && (colnr_T)vcol == wp->w_virtcol)); + int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v - 1, off, + selected, &decor_state); + if (extmark_attr != 0) { + if (!attr_pri) { + char_attr = hl_combine_attr(char_attr, extmark_attr); + } else { + char_attr = hl_combine_attr(extmark_attr, char_attr); + } + } + + decor_conceal = decor_state.conceal; + if (decor_conceal && decor_state.conceal_char) { + decor_conceal = 2; // really?? + } + + can_spell = TRISTATE_TO_BOOL(decor_state.spell, can_spell); + } + // Check spelling (unless at the end of the line). // Only do this when there is no syntax highlighting, the // @Spell cluster is not used or the current syntax item @@ -1699,11 +1891,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (has_spell && v >= word_end && v > cur_checked_col) { spell_attr = 0; if (!attr_pri) { - char_attr = syntax_attr; + char_attr = hl_combine_attr(char_attr, syntax_attr); } - if (c != 0 && (!has_syntax || can_spell)) { - char_u *prev_ptr; - char_u *p; + if (c != 0 && ((!has_syntax && !no_plain_buffer) || can_spell)) { + char *prev_ptr; + char *p; int len; hlf_T spell_hlf = HLF_COUNT; prev_ptr = ptr - mb_l; @@ -1774,32 +1966,15 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, char_attr = hl_combine_attr(term_attrs[vcol], char_attr); } - if (has_decor && v > 0) { - bool selected = (area_active || (area_highlighting && noinvcur - && (colnr_T)vcol == wp->w_virtcol)); - int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v - 1, off, - selected, &decor_state); - if (extmark_attr != 0) { - if (!attr_pri) { - char_attr = hl_combine_attr(char_attr, extmark_attr); - } else { - char_attr = hl_combine_attr(extmark_attr, char_attr); - } - } - - decor_conceal = decor_state.conceal; - if (decor_conceal && decor_state.conceal_char) { - decor_conceal = 2; // really?? - } - } - // Found last space before word: check for line break. if (wp->w_p_lbr && c0 == c && vim_isbreak(c) && !vim_isbreak((int)(*ptr))) { int mb_off = utf_head_off(line, ptr - 1); - char_u *p = ptr - (mb_off + 1); - // TODO(neovim): is passing p for start of the line OK? - n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol, NULL) - 1; + char *p = ptr - (mb_off + 1); + chartabsize_T cts; + + init_chartabsize_arg(&cts, wp, lnum, (colnr_T)vcol, line, p); + n_extra = win_lbr_chartabsize(&cts, NULL) - 1; // We have just drawn the showbreak value, no need to add // space for it again. @@ -1809,6 +1984,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, n_extra = 0; } } + if (on_last_col && c != TAB) { + // Do not continue search/match highlighting over the + // line break, but for TABs the highlighting should + // include the complete width of the character + search_attr = 0; + } if (c == TAB && n_extra + col > grid->cols) { n_extra = tabstop_padding((colnr_T)vcol, wp->w_buffer->b_p_ts, @@ -1825,6 +2006,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, c = ' '; } } + clear_chartabsize_arg(&cts); } in_multispace = c == ' ' && ((ptr > line + 1 && ptr[-2] == ' ') || *ptr == ' '); @@ -1893,7 +2075,7 @@ 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. @@ -1908,7 +2090,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (!wp->w_p_lbr || !wp->w_p_list) { n_extra = tab_len; } else { - char_u *p; + char *p; int i; int saved_nextra = n_extra; @@ -1949,7 +2131,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (wp->w_p_lcs_chars.tab3 && i == tab_len - 1) { lcs = wp->w_p_lcs_chars.tab3; } - p += utf_char2bytes(lcs, (char *)p); + p += utf_char2bytes(lcs, p); n_extra += utf_char2len(lcs) - (saved_nextra > 0 ? 1 : 0); } p_extra = p_extra_free; @@ -2041,7 +2223,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, mb_c = c; mb_utf8 = check_mb_utf8(&c, u8cc); } else if (c != NUL) { - p_extra = transchar_buf(wp->w_buffer, c); + p_extra = (char *)transchar_buf(wp->w_buffer, c); if (n_extra == 0) { n_extra = byte2cells(c) - 1; } @@ -2051,18 +2233,20 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, c_extra = NUL; c_final = NUL; if (wp->w_p_lbr) { - char_u *p; + char *p; - c = *p_extra; + c = (uint8_t)(*p_extra); p = xmalloc((size_t)n_extra + 1); memset(p, ' ', (size_t)n_extra); - STRNCPY(p, p_extra + 1, STRLEN(p_extra) - 1); // NOLINT(runtime/printf) + strncpy(p, // NOLINT(runtime/printf) + p_extra + 1, + (size_t)strlen(p_extra) - 1); p[n_extra] = NUL; xfree(p_extra_free); p_extra_free = p_extra = p; } else { n_extra = byte2cells(c) - 1; - c = *p_extra++; + c = (uint8_t)(*p_extra++); } n_attr = n_extra + 1; extra_attr = win_hl_attr(wp, HLF_8); @@ -2082,7 +2266,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (wp->w_p_cole > 0 && (wp != curwin || lnum != wp->w_cursor.lnum || conceal_cursor_line(wp)) && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0 || decor_conceal > 0) - && !(lnum_in_visual_area && vim_strchr((char *)wp->w_p_cocu, 'v') == NULL)) { + && !(lnum_in_visual_area && vim_strchr(wp->w_p_cocu, 'v') == NULL)) { char_attr = conceal_attr; if (((prev_syntax_id != syntax_seqnr && (syntax_flags & HL_CONCEAL) != 0) || has_match_conc > 1 || decor_conceal > 1) @@ -2170,7 +2354,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && wp->w_p_list && (wp->w_p_wrap ? (wp->w_skipcol > 0 && row == 0) : wp->w_leftcol > 0) && filler_todo <= 0 - && draw_state > WL_NR + && draw_state > WL_STC && c != NUL) { c = wp->w_p_lcs_chars.prec; lcs_prec_todo = NUL; @@ -2195,7 +2379,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // flag to indicate whether prevcol equals startcol of search_hl or // one of the matches bool prevcol_hl_flag = get_prevcol_hl_flag(wp, &screen_search_hl, - (long)(ptr - line) - 1); + (long)(ptr - line) - 1); // NOLINT(google-readability-casting) // Invert at least one char, used for Visual and empty line or // highlight match at end of line. If it's beyond the last @@ -2231,7 +2415,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (area_attr == 0 && !has_fold) { // Use attributes from match with highest priority among // 'search_hl' and the match list. - get_search_match_hl(wp, &screen_search_hl, (long)(ptr - line), &char_attr); + get_search_match_hl(wp, + &screen_search_hl, + (long)(ptr - line), // NOLINT(google-readability-casting) + &char_attr); } int eol_attr = char_attr; @@ -2461,7 +2648,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, col++; // UTF-8: Put a 0 in the second screen char. linebuf_char[off][0] = 0; - if (draw_state > WL_NR && filler_todo <= 0) { + if (draw_state > WL_STC && filler_todo <= 0) { vcol++; } // When "tocol" is halfway through a character, set it to the end of @@ -2544,7 +2731,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Only advance the "vcol" when after the 'number' or 'relativenumber' // column. - if (draw_state > WL_NR + if (draw_state > WL_STC && filler_todo <= 0) { vcol++; } @@ -2554,7 +2741,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } // restore attributes after "predeces" in 'listchars' - if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0) { + if (draw_state > WL_STC && n_attr3 > 0 && --n_attr3 == 0) { char_attr = saved_attr3; } @@ -2566,7 +2753,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 @@ -2583,15 +2770,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, offset); - } + 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); } @@ -2621,6 +2802,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // When the window is too narrow draw all "@" lines. if (draw_state != WL_LINE && filler_todo <= 0) { win_draw_end(wp, '@', ' ', true, row, wp->w_grid.rows, HLF_AT); + set_empty_rows(wp, row); row = endrow; } @@ -2649,7 +2831,19 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (filler_todo <= 0) { need_showbreak = true; } + if (statuscol.draw) { + 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 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)) { @@ -2659,7 +2853,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } // for every character in the line // After an empty line check first word for capital. - if (*skipwhite((char *)line) == NUL) { + if (*skipwhite(line) == NUL) { capcol_lnum = lnum + 1; cap_col = 0; } |