diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/vim.c | 6 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/change.c | 5 | ||||
-rw-r--r-- | src/nvim/charset.c | 298 | ||||
-rw-r--r-- | src/nvim/cursor.c | 1 | ||||
-rw-r--r-- | src/nvim/edit.c | 7 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 7 | ||||
-rw-r--r-- | src/nvim/ex_cmds.c | 3 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 4 | ||||
-rw-r--r-- | src/nvim/fold.c | 1 | ||||
-rw-r--r-- | src/nvim/getchar.c | 1 | ||||
-rw-r--r-- | src/nvim/indent.c | 1 | ||||
-rw-r--r-- | src/nvim/misc1.c | 172 | ||||
-rw-r--r-- | src/nvim/mouse.c | 31 | ||||
-rw-r--r-- | src/nvim/move.c | 117 | ||||
-rw-r--r-- | src/nvim/normal.c | 9 | ||||
-rw-r--r-- | src/nvim/ops.c | 1 | ||||
-rw-r--r-- | src/nvim/plines.c | 481 | ||||
-rw-r--r-- | src/nvim/plines.h | 9 | ||||
-rw-r--r-- | src/nvim/regexp.c | 1 | ||||
-rw-r--r-- | src/nvim/screen.c | 5 | ||||
-rw-r--r-- | src/nvim/window.c | 1 |
22 files changed, 603 insertions, 560 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 58ee53a408..400dbb126c 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2301,7 +2301,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, } } } - ParserLine plines[] = { + ParserLine parser_lines[] = { { .data = expr.data, .size = expr.size, @@ -2309,7 +2309,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, }, { NULL, 0, false }, }; - ParserLine *plines_p = plines; + ParserLine *plines_p = parser_lines; ParserHighlight colors; kvi_init(colors); ParserHighlight *const colors_p = (highlight ? &colors : NULL); @@ -2335,7 +2335,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, ret.items[ret.size++] = (KeyValuePair) { .key = STATIC_CSTR_TO_STRING("len"), .value = INTEGER_OBJ((Integer)(pstate.pos.line == 1 - ? plines[0].size + ? parser_lines[0].size : pstate.pos.col)), }; if (east.err.msg != NULL) { diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 1247e48c5f..b03d69a04c 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -1298,7 +1298,7 @@ struct window_S { /* * w_cline_height is the number of physical lines taken by the buffer line - * that the cursor is on. We use this to avoid extra calls to plines(). + * that the cursor is on. We use this to avoid extra calls to plines_win(). */ int w_cline_height; // current size of cursor line bool w_cline_folded; // cursor line is folded diff --git a/src/nvim/change.c b/src/nvim/change.c index 49e403425a..41e1e3911b 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -22,6 +22,7 @@ #include "nvim/misc1.h" #include "nvim/move.h" #include "nvim/option.h" +#include "nvim/plines.h" #include "nvim/screen.h" #include "nvim/search.h" #include "nvim/state.h" @@ -593,9 +594,9 @@ void ins_char_bytes(char_u *buf, size_t charlen) // cells. May result in adding spaces to fill a gap. colnr_T vcol; getvcol(curwin, &curwin->w_cursor, NULL, &vcol, NULL); - colnr_T new_vcol = vcol + chartabsize(buf, vcol); + colnr_T new_vcol = vcol + win_chartabsize(curwin, buf, vcol); while (oldp[col + oldlen] != NUL && vcol < new_vcol) { - vcol += chartabsize(oldp + col + oldlen, vcol); + vcol += win_chartabsize(curwin, oldp + col + oldlen, vcol); // Don't need to remove a TAB that takes us to the right // position. if (vcol > new_vcol && oldp[col + oldlen] == TAB) { diff --git a/src/nvim/charset.c b/src/nvim/charset.c index e2d844a351..0252ef4e9c 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -25,6 +25,7 @@ #include "nvim/move.h" #include "nvim/option.h" #include "nvim/os_unix.h" +#include "nvim/plines.h" #include "nvim/state.h" #include "nvim/strings.h" #include "nvim/path.h" @@ -733,80 +734,6 @@ int vim_strnsize(char_u *s, int len) return size; } -/// Return the number of characters 'c' will take on the screen, taking -/// into account the size of a tab. -/// Use a define to make it fast, this is used very often!!! -/// Also see getvcol() below. -/// -/// @param p -/// @param col -/// -/// @return Number of characters. -#define RET_WIN_BUF_CHARTABSIZE(wp, buf, p, col) \ - if (*(p) == TAB && (!(wp)->w_p_list || wp->w_p_lcs_chars.tab1)) { \ - return tabstop_padding(col, (buf)->b_p_ts, (buf)->b_p_vts_array); \ - } else { \ - return ptr2cells(p); \ - } - -int chartabsize(char_u *p, colnr_T col) -{ - RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, p, col) -} - -static int win_chartabsize(win_T *wp, char_u *p, colnr_T col) -{ - RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, p, col) -} - -/// Return the number of characters the string 's' will take on the screen, -/// taking into account the size of a tab. -/// -/// @param s -/// -/// @return Number of characters the string will take on the screen. -int linetabsize(char_u *s) -{ - return linetabsize_col(0, s); -} - -/// Like linetabsize(), but starting at column "startcol". -/// -/// @param startcol -/// @param s -/// -/// @return Number of characters the string will take on the screen. -int linetabsize_col(int startcol, char_u *s) -{ - colnr_T col = startcol; - char_u *line = s; /* pointer to start of line, for breakindent */ - - while (*s != NUL) { - col += lbr_chartabsize_adv(line, &s, col); - } - return (int)col; -} - -/// Like linetabsize(), but for a given window instead of the current one. -/// -/// @param wp -/// @param line -/// @param len -/// -/// @return Number of characters the string will take on the screen. -unsigned int win_linetabsize(win_T *wp, char_u *line, colnr_T len) -{ - colnr_T col = 0; - - for (char_u *s = line; - *s != NUL && (len == MAXCOL || s < line + len); - MB_PTR_ADV(s)) { - col += win_lbr_chartabsize(wp, line, s, col, NULL); - } - - return (unsigned int)col; -} - /// Check that "c" is a normal identifier character: /// Letters and characters from the 'isident' option. /// @@ -936,229 +863,6 @@ bool vim_isprintc_strict(int c) return c > 0 && (g_chartab[c] & CT_PRINT_CHAR); } -/// like chartabsize(), but also check for line breaks on the screen -/// -/// @param line -/// @param s -/// @param col -/// -/// @return The number of characters taken up on the screen. -int lbr_chartabsize(char_u *line, unsigned char *s, colnr_T col) -{ - if (!curwin->w_p_lbr && (*p_sbr == NUL) && !curwin->w_p_bri) { - if (curwin->w_p_wrap) { - return win_nolbr_chartabsize(curwin, s, col, NULL); - } - RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, s, col) - } - return win_lbr_chartabsize(curwin, line == NULL ? s: line, s, col, NULL); -} - -/// Call lbr_chartabsize() and advance the pointer. -/// -/// @param line -/// @param s -/// @param col -/// -/// @return The number of characters take up on the screen. -int lbr_chartabsize_adv(char_u *line, char_u **s, colnr_T col) -{ - int retval; - - retval = lbr_chartabsize(line, *s, col); - MB_PTR_ADV(*s); - return retval; -} - -/// This function is used very often, keep it fast!!!! -/// -/// If "headp" not NULL, set *headp to the size of what we for 'showbreak' -/// string at start of line. Warning: *headp is only set if it's a non-zero -/// value, init to 0 before calling. -/// -/// @param wp -/// @param line -/// @param s -/// @param col -/// @param headp -/// -/// @return The number of characters taken up on the screen. -int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *headp) -{ - colnr_T col2; - colnr_T col_adj = 0; /* col + screen size of tab */ - colnr_T colmax; - int added; - int mb_added = 0; - int numberextra; - char_u *ps; - int n; - - // No 'linebreak', 'showbreak' and 'breakindent': return quickly. - if (!wp->w_p_lbr && !wp->w_p_bri && (*p_sbr == NUL)) { - if (wp->w_p_wrap) { - return win_nolbr_chartabsize(wp, s, col, headp); - } - RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, s, col) - } - - // First get normal size, without 'linebreak' - int size = win_chartabsize(wp, s, col); - int c = *s; - if (*s == TAB) { - col_adj = size - 1; - } - - // If 'linebreak' set check at a blank before a non-blank if the line - // needs a break here - if (wp->w_p_lbr - && vim_isbreak(c) - && !vim_isbreak((int)s[1]) - && wp->w_p_wrap - && (wp->w_width_inner != 0)) { - // Count all characters from first non-blank after a blank up to next - // non-blank after a blank. - numberextra = win_col_off(wp); - col2 = col; - colmax = (colnr_T)(wp->w_width_inner - numberextra - col_adj); - - if (col >= colmax) { - colmax += col_adj; - n = colmax + win_col_off2(wp); - - if (n > 0) { - colmax += (((col - colmax) / n) + 1) * n - col_adj; - } - } - - for (;;) { - ps = s; - MB_PTR_ADV(s); - c = *s; - - if (!(c != NUL - && (vim_isbreak(c) || col2 == col || !vim_isbreak((int)(*ps))))) { - break; - } - - col2 += win_chartabsize(wp, s, col2); - - if (col2 >= colmax) { /* doesn't fit */ - size = colmax - col + col_adj; - break; - } - } - } else if ((size == 2) - && (MB_BYTE2LEN(*s) > 1) - && wp->w_p_wrap - && in_win_border(wp, col)) { - // Count the ">" in the last column. - ++size; - mb_added = 1; - } - - // May have to add something for 'breakindent' and/or 'showbreak' - // string at start of line. - // Set *headp to the size of what we add. - added = 0; - - if ((*p_sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && (col != 0)) { - colnr_T sbrlen = 0; - int numberwidth = win_col_off(wp); - - numberextra = numberwidth; - col += numberextra + mb_added; - - if (col >= (colnr_T)wp->w_width_inner) { - col -= wp->w_width_inner; - numberextra = wp->w_width_inner - (numberextra - win_col_off2(wp)); - if (col >= numberextra && numberextra > 0) { - col %= numberextra; - } - if (*p_sbr != NUL) { - sbrlen = (colnr_T)MB_CHARLEN(p_sbr); - if (col >= sbrlen) { - col -= sbrlen; - } - } - if (col >= numberextra && numberextra > 0) { - col %= numberextra; - } else if (col > 0 && numberextra > 0) { - col += numberwidth - win_col_off2(wp); - } - - numberwidth -= win_col_off2(wp); - } - - if (col == 0 || (col + size + sbrlen > (colnr_T)wp->w_width_inner)) { - if (*p_sbr != NUL) { - if (size + sbrlen + numberwidth > (colnr_T)wp->w_width_inner) { - // Calculate effective window width. - int width = (colnr_T)wp->w_width_inner - sbrlen - numberwidth; - int prev_width = col ? ((colnr_T)wp->w_width_inner - (sbrlen + col)) - : 0; - - if (width <= 0) { - width = 1; - } - added += ((size - prev_width) / width) * vim_strsize(p_sbr); - if ((size - prev_width) % width) { - // Wrapped, add another length of 'sbr'. - added += vim_strsize(p_sbr); - } - } else { - added += vim_strsize(p_sbr); - } - } - - if (wp->w_p_bri) - added += get_breakindent_win(wp, line); - - size += added; - if (col != 0) { - added = 0; - } - } - } - - if (headp != NULL) { - *headp = added + mb_added; - } - return size; -} - -/// Like win_lbr_chartabsize(), except that we know 'linebreak' is off and -/// 'wrap' is on. This means we need to check for a double-byte character that -/// doesn't fit at the end of the screen line. -/// -/// @param wp -/// @param s -/// @param col -/// @param headp -/// -/// @return The number of characters take up on the screen. -static int win_nolbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp) -{ - int n; - - if ((*s == TAB) && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) { - return tabstop_padding(col, - wp->w_buffer->b_p_ts, - wp->w_buffer->b_p_vts_array); - } - n = ptr2cells(s); - - // Add one cell for a double-width character in the last column of the - // window, displayed with a ">". - if ((n == 2) && (MB_BYTE2LEN(*s) > 1) && in_win_border(wp, col)) { - if (headp != NULL) { - *headp = 1; - } - return 3; - } - return n; -} - /// Check that virtual column "vcol" is in the rightmost column of window "wp". /// /// @param wp window diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c index 5d2210dc7d..d4a68adeda 100644 --- a/src/nvim/cursor.c +++ b/src/nvim/cursor.c @@ -13,6 +13,7 @@ #include "nvim/memory.h" #include "nvim/misc1.h" #include "nvim/move.h" +#include "nvim/plines.h" #include "nvim/screen.h" #include "nvim/extmark.h" #include "nvim/state.h" diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 2305faa20c..fec8da2c3c 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -41,6 +41,7 @@ #include "nvim/option.h" #include "nvim/path.h" #include "nvim/popupmnu.h" +#include "nvim/plines.h" #include "nvim/quickfix.h" #include "nvim/regexp.h" #include "nvim/screen.h" @@ -7187,7 +7188,7 @@ static void replace_do_bs(int limit_col) // Get the number of screen cells used by the character we are // going to delete. getvcol(curwin, &curwin->w_cursor, NULL, &start_vcol, NULL); - orig_vcols = chartabsize(get_cursor_pos_ptr(), start_vcol); + orig_vcols = win_chartabsize(curwin, get_cursor_pos_ptr(), start_vcol); } (void)del_char_after_col(limit_col); if (l_State & VREPLACE_FLAG) { @@ -7201,8 +7202,8 @@ static void replace_do_bs(int limit_col) p = get_cursor_pos_ptr(); ins_len = (int)STRLEN(p) - orig_len; vcol = start_vcol; - for (i = 0; i < ins_len; ++i) { - vcol += chartabsize(p + i, vcol); + for (i = 0; i < ins_len; i++) { + vcol += win_chartabsize(curwin, p + i, vcol); i += (*mb_ptr2len)(p) - 1; } vcol -= start_vcol; diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 21c858373c..4e409cca50 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -47,6 +47,7 @@ #include "nvim/os/input.h" #include "nvim/os/shell.h" #include "nvim/path.h" +#include "nvim/plines.h" #include "nvim/popupmnu.h" #include "nvim/quickfix.h" #include "nvim/regexp.h" @@ -1055,8 +1056,10 @@ static void f_col(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (virtual_active() && fp == &curwin->w_cursor) { char_u *p = get_cursor_pos_ptr(); - if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p, - curwin->w_virtcol - curwin->w_cursor.coladd)) { + if (curwin->w_cursor.coladd + >= (colnr_T)win_chartabsize(curwin, p, + (curwin->w_virtcol + - curwin->w_cursor.coladd))) { int l; if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL) diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 3ad1fb1adc..041140211e 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -55,6 +55,7 @@ #include "nvim/option.h" #include "nvim/os_unix.h" #include "nvim/path.h" +#include "nvim/plines.h" #include "nvim/quickfix.h" #include "nvim/regexp.h" #include "nvim/screen.h" @@ -828,7 +829,7 @@ void ex_retab(exarg_T *eap) } if (ptr[col] == NUL) break; - vcol += chartabsize(ptr + col, (colnr_T)vcol); + vcol += win_chartabsize(curwin, ptr + col, (colnr_T)vcol); col += utfc_ptr2len(ptr + col); } if (new_line == NULL) /* out of memory */ diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 2b3d773ca4..af8a23f5cc 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2593,7 +2593,7 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline, ColoredCmdline *const ret_ccline_colors) FUNC_ATTR_NONNULL_ALL { - ParserLine plines[] = { + ParserLine parser_lines[] = { { .data = (const char *)colored_ccline->cmdbuff, .size = STRLEN(colored_ccline->cmdbuff), @@ -2601,7 +2601,7 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline, }, { NULL, 0, false }, }; - ParserLine *plines_p = plines; + ParserLine *plines_p = parser_lines; ParserHighlight colors; kvi_init(colors); ParserState pstate; diff --git a/src/nvim/fold.c b/src/nvim/fold.c index ad8418034a..6989c29d57 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -29,6 +29,7 @@ #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/misc1.h" +#include "nvim/plines.h" #include "nvim/garray.h" #include "nvim/move.h" #include "nvim/option.h" diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index b0d06b7a30..f955fe8859 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -34,6 +34,7 @@ #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/misc1.h" +#include "nvim/plines.h" #include "nvim/keymap.h" #include "nvim/garray.h" #include "nvim/move.h" diff --git a/src/nvim/indent.c b/src/nvim/indent.c index bfb77688b0..a6df0e97e6 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -19,6 +19,7 @@ #include "nvim/misc1.h" #include "nvim/move.h" #include "nvim/option.h" +#include "nvim/plines.h" #include "nvim/regexp.h" #include "nvim/screen.h" #include "nvim/search.h" diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 771174b854..6d94632687 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -349,178 +349,6 @@ int get_last_leader_offset(char_u *line, char_u **flags) return result; } -/* - * Return the number of window lines occupied by buffer line "lnum". - */ -int plines(const linenr_T lnum) -{ - return plines_win(curwin, lnum, true); -} - -int plines_win( - win_T *const wp, - const linenr_T lnum, - const bool winheight // when true limit to window height -) -{ - /* Check for filler lines above this buffer line. When folded the result - * is one line anyway. */ - return plines_win_nofill(wp, lnum, winheight) + diff_check_fill(wp, lnum); -} - -int plines_nofill(const linenr_T lnum) -{ - return plines_win_nofill(curwin, lnum, true); -} - -int plines_win_nofill( - win_T *const wp, - const linenr_T lnum, - const bool winheight // when true limit to window height -) -{ - if (!wp->w_p_wrap) { - return 1; - } - - if (wp->w_width_inner == 0) { - return 1; - } - - // A folded lines is handled just like an empty line. - if (lineFolded(wp, lnum)) { - return 1; - } - - const int lines = plines_win_nofold(wp, lnum); - if (winheight && lines > wp->w_height_inner) { - return wp->w_height_inner; - } - return lines; -} - -/* - * Return number of window lines physical line "lnum" will occupy in window - * "wp". Does not care about folding, 'wrap' or 'diff'. - */ -int plines_win_nofold(win_T *wp, linenr_T lnum) -{ - char_u *s; - unsigned int col; - int width; - - s = ml_get_buf(wp->w_buffer, lnum, FALSE); - if (*s == NUL) /* empty line */ - return 1; - col = win_linetabsize(wp, s, MAXCOL); - - // If list mode is on, then the '$' at the end of the line may take up one - // extra column. - if (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL) { - col += 1; - } - - /* - * Add column offset for 'number', 'relativenumber' and 'foldcolumn'. - */ - width = wp->w_width_inner - win_col_off(wp); - if (width <= 0 || col > 32000) { - return 32000; // bigger than the number of screen columns - } - if (col <= (unsigned int)width) { - return 1; - } - col -= (unsigned int)width; - width += win_col_off2(wp); - assert(col <= INT_MAX && (int)col < INT_MAX - (width -1)); - return ((int)col + (width - 1)) / width + 1; -} - -/* - * Like plines_win(), but only reports the number of physical screen lines - * used from the start of the line to the given column number. - */ -int plines_win_col(win_T *wp, linenr_T lnum, long column) -{ - // Check for filler lines above this buffer line. When folded the result - // is one line anyway. - int lines = diff_check_fill(wp, lnum); - - if (!wp->w_p_wrap) - return lines + 1; - - if (wp->w_width_inner == 0) { - return lines + 1; - } - - char_u *line = ml_get_buf(wp->w_buffer, lnum, false); - char_u *s = line; - - colnr_T col = 0; - while (*s != NUL && --column >= 0) { - col += win_lbr_chartabsize(wp, line, s, col, NULL); - MB_PTR_ADV(s); - } - - // If *s is a TAB, and the TAB is not displayed as ^I, and we're not in - // INSERT mode, then col must be adjusted so that it represents the last - // screen position of the TAB. This only fixes an error when the TAB wraps - // from one screen line to the next (when 'columns' is not a multiple of - // 'ts') -- webb. - if (*s == TAB && (State & NORMAL) - && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) { - col += win_lbr_chartabsize(wp, line, s, col, NULL) - 1; - } - - // Add column offset for 'number', 'relativenumber', 'foldcolumn', etc. - int width = wp->w_width_inner - win_col_off(wp); - if (width <= 0) { - return 9999; - } - - lines += 1; - if (col > width) - lines += (col - width) / (width + win_col_off2(wp)) + 1; - return lines; -} - -/// Get the number of screen lines lnum takes up. This takes care of -/// both folds and topfill, and limits to the current window height. -/// -/// @param[in] wp window line is in -/// @param[in] lnum line number -/// @param[out] nextp if not NULL, the line after a fold -/// @param[out] foldedp if not NULL, whether lnum is on a fold -/// @param[in] cache whether to use the window's cache for folds -/// -/// @return the total number of screen lines -int plines_win_full(win_T *wp, linenr_T lnum, linenr_T *const nextp, - bool *const foldedp, const bool cache) -{ - bool folded = hasFoldingWin(wp, lnum, NULL, nextp, cache, NULL); - if (foldedp) { - *foldedp = folded; - } - if (folded) { - return 1; - } else if (lnum == wp->w_topline) { - return plines_win_nofill(wp, lnum, true) + wp->w_topfill; - } - return plines_win(wp, lnum, true); -} - -int plines_m_win(win_T *wp, linenr_T first, linenr_T last) -{ - int count = 0; - - while (first <= last) { - linenr_T next = first; - count += plines_win_full(wp, first, &next, NULL, false); - first = next + 1; - } - return count; -} - int gchar_pos(pos_T *pos) FUNC_ATTR_NONNULL_ARG(1) { diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index f1ad0ed105..6c25525936 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -18,6 +18,7 @@ #include "nvim/diff.h" #include "nvim/move.h" #include "nvim/misc1.h" +#include "nvim/plines.h" #include "nvim/cursor.h" #include "nvim/buffer_defs.h" #include "nvim/memline.h" @@ -236,12 +237,14 @@ retnomove: if (row < 0) { count = 0; for (first = true; curwin->w_topline > 1; ) { - if (curwin->w_topfill < diff_check(curwin, curwin->w_topline)) - ++count; - else - count += plines(curwin->w_topline - 1); - if (!first && count > -row) + if (curwin->w_topfill < diff_check(curwin, curwin->w_topline)) { + count++; + } else { + count += plines_win(curwin, curwin->w_topline - 1, true); + } + if (!first && count > -row) { break; + } first = false; (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL); if (curwin->w_topfill < diff_check(curwin, curwin->w_topline)) { @@ -262,7 +265,7 @@ retnomove: if (curwin->w_topfill > 0) { ++count; } else { - count += plines(curwin->w_topline); + count += plines_win(curwin, curwin->w_topline, true); } if (!first && count > row - curwin->w_height_inner + 1) { @@ -522,7 +525,7 @@ static colnr_T scroll_line_len(linenr_T lnum) char_u *line = ml_get(lnum); if (*line != NUL) { for (;;) { - int numchar = chartabsize(line, col); + int numchar = win_chartabsize(curwin, line, col); MB_PTR_ADV(line); if (*line == NUL) { // don't count the last character break; @@ -618,10 +621,10 @@ static int mouse_adjust_click(win_T *wp, int row, int col) // scanned *up to* `col`, nudging it left or right when concealed characters // are encountered. // - // chartabsize() is used to keep track of the virtual column position relative - // to the line's bytes. For example: if col == 9 and the line starts with a - // tab that's 8 columns wide, we would want the cursor to be highlighting the - // second byte, not the ninth. + // win_chartabsize() is used to keep track of the virtual column position + // relative to the line's bytes. For example: if col == 9 and the line + // starts with a tab that's 8 columns wide, we would want the cursor to be + // highlighting the second byte, not the ninth. linenr_T lnum = wp->w_cursor.lnum; char_u *line = ml_get(lnum); @@ -645,7 +648,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) // checked for concealed characters. vcol = 0; while (vcol < offset && *ptr != NUL) { - vcol += chartabsize(ptr, vcol); + vcol += win_chartabsize(curwin, ptr, vcol); ptr += utfc_ptr2len(ptr); } @@ -656,7 +659,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) vcol = offset; ptr_end = ptr_row_offset; while (vcol < col && *ptr_end != NUL) { - vcol += chartabsize(ptr_end, vcol); + vcol += win_chartabsize(curwin, ptr_end, vcol); ptr_end += utfc_ptr2len(ptr_end); } @@ -671,7 +674,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) #define decr() nudge--; ptr_end -= utfc_ptr2len(ptr_end) while (ptr < ptr_end && *ptr != NUL) { - cwidth = chartabsize(ptr, vcol); + cwidth = win_chartabsize(curwin, ptr, vcol); vcol += cwidth; if (cwidth > 1 && *ptr == '\t' && nudge > 0) { // A tab will "absorb" any previous adjustments. diff --git a/src/nvim/move.c b/src/nvim/move.c index 293f51f2d9..09815d1e6a 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -27,6 +27,7 @@ #include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/misc1.h" +#include "nvim/plines.h" #include "nvim/option.h" #include "nvim/popupmnu.h" #include "nvim/screen.h" @@ -1055,8 +1056,9 @@ bool scrolldown(long line_count, int byfold) line_count -= curwin->w_topline - first - 1; curwin->w_botline -= curwin->w_topline - first; curwin->w_topline = first; - } else - done += plines_nofill(curwin->w_topline); + } else { + done += plines_win_nofill(curwin, curwin->w_topline, true); + } } --curwin->w_botline; /* approximate w_botline */ invalidate_botline(); @@ -1090,8 +1092,9 @@ bool scrolldown(long line_count, int byfold) curwin->w_cursor.lnum = 1; else curwin->w_cursor.lnum = first - 1; - } else - wrow -= plines(curwin->w_cursor.lnum--); + } else { + wrow -= plines_win(curwin, curwin->w_cursor.lnum--, true); + } curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL); moved = true; @@ -1194,7 +1197,7 @@ check_topfill ( */ static void max_topfill(void) { - int n = plines_nofill(curwin->w_topline); + int n = plines_win_nofill(curwin, curwin->w_topline, true); if (n >= curwin->w_height_inner) { curwin->w_topfill = 0; } else { @@ -1221,19 +1224,16 @@ void scrolldown_clamp(void) validate_cursor(); /* w_wrow needs to be valid */ - /* - * Compute the row number of the last row of the cursor line - * and make sure it doesn't go off the screen. Make sure the cursor - * doesn't go past 'scrolloff' lines from the screen end. - */ + // Compute the row number of the last row of the cursor line + // and make sure it doesn't go off the screen. Make sure the cursor + // doesn't go past 'scrolloff' lines from the screen end. int end_row = curwin->w_wrow; - if (can_fill) - ++end_row; - else - end_row += plines_nofill(curwin->w_topline - 1); - if (curwin->w_p_wrap - && curwin->w_width_inner != 0 - ) { + if (can_fill) { + end_row++; + } else { + end_row += plines_win_nofill(curwin, curwin->w_topline - 1, true); + } + if (curwin->w_p_wrap && curwin->w_width_inner != 0) { validate_cheight(); validate_virtcol(); end_row += curwin->w_cline_height - 1 - @@ -1266,16 +1266,13 @@ void scrollup_clamp(void) validate_cursor(); /* w_wrow needs to be valid */ - /* - * Compute the row number of the first row of the cursor line - * and make sure it doesn't go off the screen. Make sure the cursor - * doesn't go before 'scrolloff' lines from the screen start. - */ - int start_row = curwin->w_wrow - plines_nofill(curwin->w_topline) - - curwin->w_topfill; - if (curwin->w_p_wrap - && curwin->w_width_inner != 0 - ) { + // Compute the row number of the first row of the cursor line + // and make sure it doesn't go off the screen. Make sure the cursor + // doesn't go before 'scrolloff' lines from the screen start. + int start_row = (curwin->w_wrow + - plines_win_nofill(curwin, curwin->w_topline, true) + - curwin->w_topfill); + if (curwin->w_p_wrap && curwin->w_width_inner != 0) { validate_virtcol(); start_row -= curwin->w_virtcol / curwin->w_width_inner; } @@ -1422,14 +1419,15 @@ void scroll_cursor_top(int min_scroll, int always) while (top > 0) { int i = hasFolding(top, &top, NULL) ? 1 // count one logical line for a sequence of folded lines - : plines_nofill(top); + : plines_win_nofill(curwin, top, true); used += i; if (extra + i <= off && bot < curbuf->b_ml.ml_line_count) { - if (hasFolding(bot, NULL, &bot)) - /* count one logical line for a sequence of folded lines */ - ++used; - else - used += plines(bot); + if (hasFolding(bot, NULL, &bot)) { + // count one logical line for a sequence of folded lines + used++; + } else { + used += plines_win(curwin, bot, true); + } } if (used > curwin->w_height_inner) { break; @@ -1555,12 +1553,12 @@ void scroll_cursor_bot(int min_scroll, int set_topbot) validate_botline(curwin); } - /* The lines of the cursor line itself are always used. */ - used = plines_nofill(cln); + // The lines of the cursor line itself are always used. + used = plines_win_nofill(curwin, cln, true); - /* If the cursor is below botline, we will at least scroll by the height - * of the cursor line. Correct for empty lines, which are really part of - * botline. */ + // If the cursor is below botline, we will at least scroll by the height + // of the cursor line. Correct for empty lines, which are really part of + // botline. if (cln >= curwin->w_botline) { scrolled = used; if (cln == curwin->w_botline) @@ -1704,7 +1702,7 @@ void scroll_cursor_halfway(int atend) loff.lnum = boff.lnum = curwin->w_cursor.lnum; (void)hasFolding(loff.lnum, &loff.lnum, &boff.lnum); - int used = plines_nofill(loff.lnum); + int used = plines_win_nofill(curwin, loff.lnum, true); loff.fill = 0; boff.fill = 0; linenr_T topline = loff.lnum; @@ -1809,17 +1807,19 @@ void cursor_correct(void) int below = curwin->w_filler_rows; /* screen lines below botline */ while ((above < above_wanted || below < below_wanted) && topline < botline) { if (below < below_wanted && (below <= above || above >= above_wanted)) { - if (hasFolding(botline, &botline, NULL)) - ++below; - else - below += plines(botline); - --botline; + if (hasFolding(botline, &botline, NULL)) { + below++; + } else { + below += plines_win(curwin, botline, true); + } + botline--; } if (above < above_wanted && (above < below || below >= below_wanted)) { - if (hasFolding(topline, NULL, &topline)) - ++above; - else - above += plines_nofill(topline); + if (hasFolding(topline, NULL, &topline)) { + above++; + } else { + above += plines_win_nofill(curwin, topline, true); + } /* Count filler lines below this line as context. */ if (topline < botline) @@ -2047,10 +2047,11 @@ static void get_scroll_overlap(lineoff_T *lp, int dir) { int min_height = curwin->w_height_inner - 2; - if (lp->fill > 0) + if (lp->fill > 0) { lp->height = 1; - else - lp->height = plines_nofill(lp->lnum); + } else { + lp->height = plines_win_nofill(curwin, lp->lnum, true); + } int h1 = lp->height; if (h1 > min_height) return; /* no overlap */ @@ -2120,7 +2121,7 @@ void halfpage(bool flag, linenr_T Prenum) n--; curwin->w_topfill--; } else { - i = plines_nofill(curwin->w_topline); + i = plines_win_nofill(curwin, curwin->w_topline, true); n -= i; if (n < 0 && scrolled > 0) break; @@ -2146,12 +2147,12 @@ void halfpage(bool flag, linenr_T Prenum) else { room += i; do { - i = plines(curwin->w_botline); - if (i > room) + i = plines_win(curwin, curwin->w_botline, true); + if (i > room) { break; - (void)hasFolding(curwin->w_botline, NULL, - &curwin->w_botline); - ++curwin->w_botline; + } + (void)hasFolding(curwin->w_botline, NULL, &curwin->w_botline); + curwin->w_botline++; room -= i; } while (curwin->w_botline <= curbuf->b_ml.ml_line_count); } @@ -2180,7 +2181,7 @@ void halfpage(bool flag, linenr_T Prenum) n--; curwin->w_topfill++; } else { - i = plines_nofill(curwin->w_topline - 1); + i = plines_win_nofill(curwin, curwin->w_topline - 1, true); n -= i; if (n < 0 && scrolled > 0) break; diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 54ca216a53..2a530db934 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -45,6 +45,7 @@ #include "nvim/mouse.h" #include "nvim/ops.h" #include "nvim/option.h" +#include "nvim/plines.h" #include "nvim/quickfix.h" #include "nvim/screen.h" #include "nvim/search.h" @@ -5122,11 +5123,13 @@ static void nv_scroll(cmdarg_T *cap) --n; break; } - used += plines(curwin->w_topline + n); - if (used >= half) + used += plines_win(curwin, curwin->w_topline + n, true); + if (used >= half) { break; - if (hasFolding(curwin->w_topline + n, NULL, &lnum)) + } + if (hasFolding(curwin->w_topline + n, NULL, &lnum)) { n = lnum - curwin->w_topline; + } } if (n > 0 && used > curwin->w_height_inner) { n--; diff --git a/src/nvim/ops.c b/src/nvim/ops.c index c51dd09d40..a6eda26d75 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -41,6 +41,7 @@ #include "nvim/normal.h" #include "nvim/option.h" #include "nvim/path.h" +#include "nvim/plines.h" #include "nvim/screen.h" #include "nvim/search.h" #include "nvim/state.h" diff --git a/src/nvim/plines.c b/src/nvim/plines.c new file mode 100644 index 0000000000..6718b7f7a4 --- /dev/null +++ b/src/nvim/plines.c @@ -0,0 +1,481 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + +// plines.c: calculate the vertical and horizontal size of text in a window + +#include <assert.h> +#include <inttypes.h> +#include <stdbool.h> +#include <string.h> +#include <limits.h> + +#include "nvim/vim.h" +#include "nvim/ascii.h" +#include "nvim/plines.h" +#include "nvim/charset.h" +#include "nvim/cursor.h" +#include "nvim/diff.h" +#include "nvim/func_attr.h" +#include "nvim/fold.h" +#include "nvim/indent.h" +#include "nvim/main.h" +#include "nvim/mbyte.h" +#include "nvim/memline.h" +#include "nvim/memory.h" +#include "nvim/move.h" +#include "nvim/option.h" +#include "nvim/screen.h" +#include "nvim/strings.h" +#include "nvim/window.h" +#include "nvim/buffer.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "plines.c.generated.h" +#endif + +/// Functions calculating vertical size of text when displayed inside a window. +/// Calls horizontal size functions defined below. + +/// @param winheight when true limit to window height +int plines_win(win_T *wp, linenr_T lnum, bool winheight) +{ + // Check for filler lines above this buffer line. When folded the result + // is one line anyway. + return plines_win_nofill(wp, lnum, winheight) + diff_check_fill(wp, lnum); +} + +/// @param winheight when true limit to window height +int plines_win_nofill(win_T *wp, linenr_T lnum, bool winheight) +{ + if (!wp->w_p_wrap) { + return 1; + } + + if (wp->w_width_inner == 0) { + return 1; + } + + // A folded lines is handled just like an empty line. + if (lineFolded(wp, lnum)) { + return 1; + } + + const int lines = plines_win_nofold(wp, lnum); + if (winheight && lines > wp->w_height_inner) { + return wp->w_height_inner; + } + return lines; +} + +/// @Return number of window lines physical line "lnum" will occupy in window +/// "wp". Does not care about folding, 'wrap' or 'diff'. +int plines_win_nofold(win_T *wp, linenr_T lnum) +{ + char_u *s; + unsigned int col; + int width; + + s = ml_get_buf(wp->w_buffer, lnum, false); + if (*s == NUL) { // empty line + return 1; + } + col = win_linetabsize(wp, s, MAXCOL); + + // If list mode is on, then the '$' at the end of the line may take up one + // extra column. + if (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL) { + col += 1; + } + + // Add column offset for 'number', 'relativenumber' and 'foldcolumn'. + width = wp->w_width_inner - win_col_off(wp); + if (width <= 0 || col > 32000) { + return 32000; // bigger than the number of screen columns + } + if (col <= (unsigned int)width) { + return 1; + } + col -= (unsigned int)width; + width += win_col_off2(wp); + assert(col <= INT_MAX && (int)col < INT_MAX - (width -1)); + return ((int)col + (width - 1)) / width + 1; +} + +/// Like plines_win(), but only reports the number of physical screen lines +/// used from the start of the line to the given column number. +int plines_win_col(win_T *wp, linenr_T lnum, long column) +{ + // Check for filler lines above this buffer line. When folded the result + // is one line anyway. + int lines = diff_check_fill(wp, lnum); + + if (!wp->w_p_wrap) { + return lines + 1; + } + + if (wp->w_width_inner == 0) { + return lines + 1; + } + + char_u *line = ml_get_buf(wp->w_buffer, lnum, false); + char_u *s = line; + + colnr_T col = 0; + while (*s != NUL && --column >= 0) { + col += win_lbr_chartabsize(wp, line, s, col, NULL); + MB_PTR_ADV(s); + } + + // If *s is a TAB, and the TAB is not displayed as ^I, and we're not in + // INSERT mode, then col must be adjusted so that it represents the last + // screen position of the TAB. This only fixes an error when the TAB wraps + // from one screen line to the next (when 'columns' is not a multiple of + // 'ts') -- webb. + if (*s == TAB && (State & NORMAL) + && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) { + col += win_lbr_chartabsize(wp, line, s, col, NULL) - 1; + } + + // Add column offset for 'number', 'relativenumber', 'foldcolumn', etc. + int width = wp->w_width_inner - win_col_off(wp); + if (width <= 0) { + return 9999; + } + + lines += 1; + if (col > width) { + lines += (col - width) / (width + win_col_off2(wp)) + 1; + } + return lines; +} + +/// Get the number of screen lines lnum takes up. This takes care of +/// both folds and topfill, and limits to the current window height. +/// +/// @param[in] wp window line is in +/// @param[in] lnum line number +/// @param[out] nextp if not NULL, the line after a fold +/// @param[out] foldedp if not NULL, whether lnum is on a fold +/// @param[in] cache whether to use the window's cache for folds +/// +/// @return the total number of screen lines +int plines_win_full(win_T *wp, linenr_T lnum, linenr_T *const nextp, + bool *const foldedp, const bool cache) +{ + bool folded = hasFoldingWin(wp, lnum, NULL, nextp, cache, NULL); + if (foldedp) { + *foldedp = folded; + } + if (folded) { + return 1; + } else if (lnum == wp->w_topline) { + return plines_win_nofill(wp, lnum, true) + wp->w_topfill; + } + return plines_win(wp, lnum, true); +} + +int plines_m_win(win_T *wp, linenr_T first, linenr_T last) +{ + int count = 0; + + while (first <= last) { + linenr_T next = first; + count += plines_win_full(wp, first, &next, NULL, false); + first = next + 1; + } + return count; +} + +/// Functions calculating horizontal size of text, when displayed in a window. + +/// Return the number of characters 'c' will take on the screen, taking +/// into account the size of a tab. +/// Also see getvcol() +/// +/// @param p +/// @param col +/// +/// @return Number of characters. +int win_chartabsize(win_T *wp, char_u *p, colnr_T col) +{ + buf_T *buf = wp->w_buffer; + if (*p == TAB && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) { + return tabstop_padding(col, buf->b_p_ts, buf->b_p_vts_array); + } else { + return ptr2cells(p); + } +} + +/// Return the number of characters the string 's' will take on the screen, +/// taking into account the size of a tab. +/// +/// @param s +/// +/// @return Number of characters the string will take on the screen. +int linetabsize(char_u *s) +{ + return linetabsize_col(0, s); +} + +/// Like linetabsize(), but starting at column "startcol". +/// +/// @param startcol +/// @param s +/// +/// @return Number of characters the string will take on the screen. +int linetabsize_col(int startcol, char_u *s) +{ + colnr_T col = startcol; + char_u *line = s; // pointer to start of line, for breakindent + + while (*s != NUL) { + col += lbr_chartabsize_adv(line, &s, col); + } + return (int)col; +} + +/// Like linetabsize(), but for a given window instead of the current one. +/// +/// @param wp +/// @param line +/// @param len +/// +/// @return Number of characters the string will take on the screen. +unsigned int win_linetabsize(win_T *wp, char_u *line, colnr_T len) +{ + colnr_T col = 0; + + for (char_u *s = line; + *s != NUL && (len == MAXCOL || s < line + len); + MB_PTR_ADV(s)) { + col += win_lbr_chartabsize(wp, line, s, col, NULL); + } + + return (unsigned int)col; +} + +/// like win_chartabsize(), but also check for line breaks on the screen +/// +/// @param line +/// @param s +/// @param col +/// +/// @return The number of characters taken up on the screen. +int lbr_chartabsize(char_u *line, unsigned char *s, colnr_T col) +{ + if (!curwin->w_p_lbr && (*p_sbr == NUL) && !curwin->w_p_bri) { + if (curwin->w_p_wrap) { + return win_nolbr_chartabsize(curwin, s, col, NULL); + } + return win_chartabsize(curwin, s, col); + } + return win_lbr_chartabsize(curwin, line == NULL ? s: line, s, col, NULL); +} + +/// Call lbr_chartabsize() and advance the pointer. +/// +/// @param line +/// @param s +/// @param col +/// +/// @return The number of characters take up on the screen. +int lbr_chartabsize_adv(char_u *line, char_u **s, colnr_T col) +{ + int retval; + + retval = lbr_chartabsize(line, *s, col); + MB_PTR_ADV(*s); + return retval; +} + +/// This function is used very often, keep it fast!!!! +/// +/// If "headp" not NULL, set *headp to the size of what we for 'showbreak' +/// string at start of line. Warning: *headp is only set if it's a non-zero +/// value, init to 0 before calling. +/// +/// @param wp +/// @param line +/// @param s +/// @param col +/// @param headp +/// +/// @return The number of characters taken up on the screen. +int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, + colnr_T col, int *headp) +{ + colnr_T col2; + colnr_T col_adj = 0; // col + screen size of tab + colnr_T colmax; + int added; + int mb_added = 0; + int numberextra; + char_u *ps; + int n; + + // No 'linebreak', 'showbreak' and 'breakindent': return quickly. + if (!wp->w_p_lbr && !wp->w_p_bri && (*p_sbr == NUL)) { + if (wp->w_p_wrap) { + return win_nolbr_chartabsize(wp, s, col, headp); + } + return win_chartabsize(wp, s, col); + } + + // First get normal size, without 'linebreak' + int size = win_chartabsize(wp, s, col); + int c = *s; + if (*s == TAB) { + col_adj = size - 1; + } + + // If 'linebreak' set check at a blank before a non-blank if the line + // needs a break here + if (wp->w_p_lbr + && vim_isbreak(c) + && !vim_isbreak((int)s[1]) + && wp->w_p_wrap + && (wp->w_width_inner != 0)) { + // Count all characters from first non-blank after a blank up to next + // non-blank after a blank. + numberextra = win_col_off(wp); + col2 = col; + colmax = (colnr_T)(wp->w_width_inner - numberextra - col_adj); + + if (col >= colmax) { + colmax += col_adj; + n = colmax + win_col_off2(wp); + + if (n > 0) { + colmax += (((col - colmax) / n) + 1) * n - col_adj; + } + } + + for (;;) { + ps = s; + MB_PTR_ADV(s); + c = *s; + + if (!(c != NUL + && (vim_isbreak(c) || col2 == col || !vim_isbreak((int)(*ps))))) { + break; + } + + col2 += win_chartabsize(wp, s, col2); + + if (col2 >= colmax) { // doesn't fit + size = colmax - col + col_adj; + break; + } + } + } else if ((size == 2) + && (MB_BYTE2LEN(*s) > 1) + && wp->w_p_wrap + && in_win_border(wp, col)) { + // Count the ">" in the last column. + size++; + mb_added = 1; + } + + // May have to add something for 'breakindent' and/or 'showbreak' + // string at start of line. + // Set *headp to the size of what we add. + added = 0; + + if ((*p_sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && (col != 0)) { + colnr_T sbrlen = 0; + int numberwidth = win_col_off(wp); + + numberextra = numberwidth; + col += numberextra + mb_added; + + if (col >= (colnr_T)wp->w_width_inner) { + col -= wp->w_width_inner; + numberextra = wp->w_width_inner - (numberextra - win_col_off2(wp)); + if (col >= numberextra && numberextra > 0) { + col %= numberextra; + } + if (*p_sbr != NUL) { + sbrlen = (colnr_T)MB_CHARLEN(p_sbr); + if (col >= sbrlen) { + col -= sbrlen; + } + } + if (col >= numberextra && numberextra > 0) { + col %= numberextra; + } else if (col > 0 && numberextra > 0) { + col += numberwidth - win_col_off2(wp); + } + + numberwidth -= win_col_off2(wp); + } + + if (col == 0 || (col + size + sbrlen > (colnr_T)wp->w_width_inner)) { + if (*p_sbr != NUL) { + if (size + sbrlen + numberwidth > (colnr_T)wp->w_width_inner) { + // Calculate effective window width. + int width = (colnr_T)wp->w_width_inner - sbrlen - numberwidth; + int prev_width = col ? ((colnr_T)wp->w_width_inner - (sbrlen + col)) + : 0; + + if (width <= 0) { + width = 1; + } + added += ((size - prev_width) / width) * vim_strsize(p_sbr); + if ((size - prev_width) % width) { + // Wrapped, add another length of 'sbr'. + added += vim_strsize(p_sbr); + } + } else { + added += vim_strsize(p_sbr); + } + } + + if (wp->w_p_bri) { + added += get_breakindent_win(wp, line); + } + + size += added; + if (col != 0) { + added = 0; + } + } + } + + if (headp != NULL) { + *headp = added + mb_added; + } + return size; +} + +/// Like win_lbr_chartabsize(), except that we know 'linebreak' is off and +/// 'wrap' is on. This means we need to check for a double-byte character that +/// doesn't fit at the end of the screen line. +/// +/// @param wp +/// @param s +/// @param col +/// @param headp +/// +/// @return The number of characters take up on the screen. +static int win_nolbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp) +{ + int n; + + if ((*s == TAB) && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) { + return tabstop_padding(col, + wp->w_buffer->b_p_ts, + wp->w_buffer->b_p_vts_array); + } + n = ptr2cells(s); + + // Add one cell for a double-width character in the last column of the + // window, displayed with a ">". + if ((n == 2) && (MB_BYTE2LEN(*s) > 1) && in_win_border(wp, col)) { + if (headp != NULL) { + *headp = 1; + } + return 3; + } + return n; +} + diff --git a/src/nvim/plines.h b/src/nvim/plines.h new file mode 100644 index 0000000000..32778b69f1 --- /dev/null +++ b/src/nvim/plines.h @@ -0,0 +1,9 @@ +#ifndef NVIM_PLINES_H +#define NVIM_PLINES_H + +#include "nvim/vim.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "plines.h.generated.h" +#endif +#endif // NVIM_PLINES_H diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index c2ef217638..6379174938 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -63,6 +63,7 @@ #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/misc1.h" +#include "nvim/plines.h" #include "nvim/garray.h" #include "nvim/strings.h" diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 2fc5777937..38ed2816ba 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -101,6 +101,7 @@ #include "nvim/option.h" #include "nvim/os_unix.h" #include "nvim/path.h" +#include "nvim/plines.h" #include "nvim/popupmnu.h" #include "nvim/quickfix.h" #include "nvim/regexp.h" @@ -1694,7 +1695,7 @@ static void win_update(win_T *wp, Providers *providers) /* * There is a trick with w_botline. If we invalidate it on each * change that might modify it, this will cause a lot of expensive - * calls to plines() in update_topline() each time. Therefore the + * calls to plines_win() in update_topline() each time. Therefore the * value of w_botline is often approximated, and this value is used to * compute the value of w_topline. If the value of w_botline was * wrong, check that the value of w_topline is correct (cursor is on @@ -4119,7 +4120,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, /* * Update w_cline_height and w_cline_folded if the cursor line was - * updated (saves a call to plines() later). + * updated (saves a call to plines_win() later). */ if (wp == curwin && lnum == curwin->w_cursor.lnum) { curwin->w_cline_row = startrow; diff --git a/src/nvim/window.c b/src/nvim/window.c index 2f43faef50..fe6ab5af55 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -31,6 +31,7 @@ #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/misc1.h" +#include "nvim/plines.h" #include "nvim/file_search.h" #include "nvim/garray.h" #include "nvim/move.h" |