diff options
| author | bfredl <bjorn.linse@gmail.com> | 2022-08-27 11:28:11 +0200 |
|---|---|---|
| committer | bfredl <bjorn.linse@gmail.com> | 2022-08-29 12:05:34 +0200 |
| commit | ea4e9c71ccaf406fe7aa6b47d461cdab2d6c01e9 (patch) | |
| tree | d8c14449741cdfcbf3fcb65d518a7ee0a15a70bb | |
| parent | 7a9b5937966d3db852c84b8eb232e77d92d3c355 (diff) | |
| download | rneovim-ea4e9c71ccaf406fe7aa6b47d461cdab2d6c01e9.tar.gz rneovim-ea4e9c71ccaf406fe7aa6b47d461cdab2d6c01e9.tar.bz2 rneovim-ea4e9c71ccaf406fe7aa6b47d461cdab2d6c01e9.zip | |
refactor(plines): use a struct for chartabsize state
This is a refactor extracted from vim-patch 9.0.0067: cannot show virtual text
The logic for inline virtual text is going to be different in nvim than
text property based text in vim, but this refactor is still useful,
as calculation of displayed linesize is going to be stateful in a
similar way.
| -rw-r--r-- | src/nvim/change.c | 4 | ||||
| -rw-r--r-- | src/nvim/charset.c | 24 | ||||
| -rw-r--r-- | src/nvim/cursor.c | 16 | ||||
| -rw-r--r-- | src/nvim/drawline.c | 28 | ||||
| -rw-r--r-- | src/nvim/edit.c | 80 | ||||
| -rw-r--r-- | src/nvim/eval/funcs.c | 6 | ||||
| -rw-r--r-- | src/nvim/ex_cmds.c | 2 | ||||
| -rw-r--r-- | src/nvim/getchar.c | 19 | ||||
| -rw-r--r-- | src/nvim/indent.c | 52 | ||||
| -rw-r--r-- | src/nvim/mouse.c | 26 | ||||
| -rw-r--r-- | src/nvim/ops.c | 101 | ||||
| -rw-r--r-- | src/nvim/plines.c | 182 | ||||
| -rw-r--r-- | src/nvim/plines.h | 14 | ||||
| -rw-r--r-- | src/nvim/regexp.c | 2 | ||||
| -rw-r--r-- | src/nvim/regexp_bt.c | 1 | ||||
| -rw-r--r-- | src/nvim/regexp_nfa.c | 2 |
16 files changed, 354 insertions, 205 deletions
diff --git a/src/nvim/change.c b/src/nvim/change.c index 04dfb20a1b..074700f4df 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -653,9 +653,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 + win_chartabsize(curwin, buf, vcol); + colnr_T new_vcol = vcol + win_chartabsize(curwin, (char *)buf, vcol); while (oldp[col + oldlen] != NUL && vcol < new_vcol) { - vcol += win_chartabsize(curwin, oldp + col + oldlen, vcol); + vcol += win_chartabsize(curwin, (char *)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 dc62b85716..3632c3d70b 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -930,14 +930,18 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en posptr -= utf_head_off(line, posptr); } + chartabsize_T cts; + init_chartabsize_arg(&cts, wp, pos->lnum, 0, line, line); + // This function is used very often, do some speed optimizations. // When 'list', 'linebreak', 'showbreak' and 'breakindent' are not set - // use a simple loop. + // and there are no virtual text use a simple loop. // Also use this when 'list' is set but tabs take their normal size. if ((!wp->w_p_list || (wp->w_p_lcs_chars.tab1 != NUL)) && !wp->w_p_lbr && *get_showbreak_value(wp) == NUL - && !wp->w_p_bri) { + && !wp->w_p_bri + && !cts.cts_has_virt_text) { for (;;) { head = 0; int c = *ptr; @@ -984,25 +988,29 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en } else { for (;;) { // A tab gets expanded, depending on the current column + // Other things also take up space. head = 0; - incr = win_lbr_chartabsize(wp, line, ptr, vcol, &head); + incr = win_lbr_chartabsize(&cts, &head); // make sure we don't go past the end of the line - if (*ptr == NUL) { + if (*cts.cts_ptr == NUL) { // NUL at end of line only takes one column incr = 1; break; } - if ((posptr != NULL) && (ptr >= posptr)) { + if ((posptr != NULL) && ((char_u *)cts.cts_ptr >= posptr)) { // character at pos->col break; } - vcol += incr; - MB_PTR_ADV(ptr); + cts.cts_vcol += incr; + MB_PTR_ADV(cts.cts_ptr); } + vcol = cts.cts_vcol; + ptr = (char_u *)cts.cts_ptr; } + clear_chartabsize_arg(&cts); if (start != NULL) { *start = vcol + head; @@ -1013,6 +1021,8 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en } if (cursor != NULL) { + // cursor is after inserted text + vcol += cts.cts_cur_text_width; if ((*ptr == TAB) && (State & MODE_NORMAL) && !wp->w_p_list diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c index 14ebc11cbf..ed0488cf76 100644 --- a/src/nvim/cursor.c +++ b/src/nvim/cursor.c @@ -137,14 +137,18 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a } } - char_u *ptr = line; - while (col <= wcol && *ptr != NUL) { + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, pos->lnum, 0, line, line); + while (cts.cts_vcol <= wcol && *cts.cts_ptr != NUL) { // Count a tab for what it's worth (if list mode not on) - csize = win_lbr_chartabsize(curwin, line, ptr, col, &head); - MB_PTR_ADV(ptr); - col += csize; + csize = win_lbr_chartabsize(&cts, &head); + MB_PTR_ADV(cts.cts_ptr); + cts.cts_vcol += csize; } - idx = (int)(ptr - line); + col = cts.cts_vcol; + idx = (int)(cts.cts_ptr - (char *)line); + clear_chartabsize_arg(&cts); + // Handle all the special cases. The virtual_active() check // is needed to ensure that a virtual position off the end of // a line has the correct indexing. The one_more comparison diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 9132d6666e..4b5f6c6c06 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -940,12 +940,19 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } 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); + 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 = (char_u *)cts.cts_ptr; + MB_PTR_ADV(cts.cts_ptr); } + vcol = cts.cts_vcol; + ptr = (char_u *)cts.cts_ptr; + clear_chartabsize_arg(&cts); // When: // - 'cuc' is set, or @@ -963,11 +970,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((char *)ptr) >= charsize || *ptr == TAB) { n_skip = (int)(v - vcol); } } @@ -1798,8 +1805,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && !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; + 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. @@ -1825,6 +1834,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 == ' '); diff --git a/src/nvim/edit.c b/src/nvim/edit.c index ed625e1d6e..e785a46dae 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1665,28 +1665,28 @@ void change_indent(int type, int amount, int round, int replaced, int call_chang } else if (!(State & MODE_INSERT)) { new_cursor_col = curwin->w_cursor.col; } else { - /* - * Compute the screen column where the cursor should be. - */ + // Compute the screen column where the cursor should be. vcol = get_indent() - vcol; curwin->w_virtcol = (colnr_T)((vcol < 0) ? 0 : vcol); - /* - * Advance the cursor until we reach the right screen column. - */ - vcol = last_vcol = 0; - new_cursor_col = -1; + // Advance the cursor until we reach the right screen column. + last_vcol = 0; ptr = get_cursor_line_ptr(); - while (vcol <= (int)curwin->w_virtcol) { - last_vcol = vcol; - if (new_cursor_col >= 0) { - new_cursor_col += utfc_ptr2len((char *)ptr + new_cursor_col); - } else { - new_cursor_col++; + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, 0, 0, ptr, ptr); + while (cts.cts_vcol <= (int)curwin->w_virtcol) { + last_vcol = cts.cts_vcol; + if (cts.cts_vcol > 0) { + MB_PTR_ADV(cts.cts_ptr); + } + if (*cts.cts_ptr == NUL) { + break; } - vcol += lbr_chartabsize(ptr, ptr + new_cursor_col, (colnr_T)vcol); + cts.cts_vcol += lbr_chartabsize(&cts); } vcol = last_vcol; + new_cursor_col = (int)(cts.cts_ptr - cts.cts_line); + clear_chartabsize_arg(&cts); /* * May need to insert spaces to be able to position the cursor on @@ -2991,7 +2991,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 = win_chartabsize(curwin, get_cursor_pos_ptr(), start_vcol); + orig_vcols = win_chartabsize(curwin, (char *)get_cursor_pos_ptr(), start_vcol); } (void)del_char_after_col(limit_col); if (l_State & VREPLACE_FLAG) { @@ -3006,7 +3006,7 @@ static void replace_do_bs(int limit_col) ins_len = (int)STRLEN(p) - orig_len; vcol = start_vcol; for (i = 0; i < ins_len; i++) { - vcol += win_chartabsize(curwin, p + i, vcol); + vcol += win_chartabsize(curwin, (char *)p + i, vcol); i += utfc_ptr2len((char *)p) - 1; } vcol -= start_vcol; @@ -4644,11 +4644,15 @@ static bool ins_tab(void) getvcol(curwin, &fpos, &vcol, NULL, NULL); getvcol(curwin, cursor, &want_vcol, NULL, NULL); + char_u *tab = (char_u *)"\t"; + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, 0, vcol, tab, tab); + // Use as many TABs as possible. Beware of 'breakindent', 'showbreak' // and 'linebreak' adding extra virtual columns. while (ascii_iswhite(*ptr)) { - i = lbr_chartabsize(NULL, (char_u *)"\t", vcol); - if (vcol + i > want_vcol) { + i = lbr_chartabsize(&cts); + if (cts.cts_vcol + i > want_vcol) { break; } if (*ptr != TAB) { @@ -4663,19 +4667,24 @@ static bool ins_tab(void) } fpos.col++; ptr++; - vcol += i; + cts.cts_vcol += i; } + vcol = cts.cts_vcol; + clear_chartabsize_arg(&cts); if (change_col >= 0) { int repl_off = 0; - char_u *line = ptr; - // Skip over the spaces we need. - while (vcol < want_vcol && *ptr == ' ') { - vcol += lbr_chartabsize(line, ptr, vcol); - ptr++; + init_chartabsize_arg(&cts, curwin, 0, vcol, ptr, ptr); + while (cts.cts_vcol < want_vcol && *cts.cts_ptr == ' ') { + cts.cts_vcol += lbr_chartabsize(&cts); + cts.cts_ptr++; repl_off++; } + ptr = (char_u *)cts.cts_ptr; + vcol = cts.cts_vcol; + clear_chartabsize_arg(&cts); + if (vcol > want_vcol) { // Must have a char with 'showbreak' just before it. ptr--; @@ -4855,7 +4864,6 @@ static int ins_digraph(void) int ins_copychar(linenr_T lnum) { int c; - int temp; char_u *ptr, *prev_ptr; char_u *line; @@ -4865,17 +4873,23 @@ int ins_copychar(linenr_T lnum) } // try to advance to the cursor column - temp = 0; - line = ptr = ml_get(lnum); - prev_ptr = ptr; + line = ml_get(lnum); + prev_ptr = line; validate_virtcol(); - while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL) { - prev_ptr = ptr; - temp += lbr_chartabsize_adv(line, &ptr, (colnr_T)temp); + + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, lnum, 0, line, line); + while (cts.cts_vcol < curwin->w_virtcol && *cts.cts_ptr != NUL) { + prev_ptr = (char_u *)cts.cts_ptr; + cts.cts_vcol += lbr_chartabsize_adv(&cts); } - if ((colnr_T)temp > curwin->w_virtcol) { + + if (cts.cts_vcol > curwin->w_virtcol) { ptr = prev_ptr; + } else { + ptr = (char_u *)cts.cts_ptr; } + clear_chartabsize_arg(&cts); c = utf_ptr2char((char *)ptr); if (c == NUL) { diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 581f187140..f3a00ffeb2 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -849,11 +849,11 @@ static void get_col(typval_T *argvars, typval_T *rettv, bool charcol) // col(".") when the cursor is on the NUL at the end of the line // because of "coladd" can be seen as an extra column. if (virtual_active() && fp == &curwin->w_cursor) { - char_u *p = get_cursor_pos_ptr(); + char *p = (char *)get_cursor_pos_ptr(); 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 = utfc_ptr2len((char *)p))] == NUL) { + if (*p != NUL && p[(l = utfc_ptr2len(p))] == NUL) { col += l; } } @@ -8512,7 +8512,7 @@ static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv, EvalFuncData f col = (int)tv_get_number(&argvars[1]); } - rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, (char_u *)s) - col); + rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, (char *)s) - col); } /// "strwidth()" function diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index a72cddc0a9..3bb900b57f 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -841,7 +841,7 @@ void ex_retab(exarg_T *eap) if (ptr[col] == NUL) { break; } - vcol += win_chartabsize(curwin, (char_u *)ptr + col, (colnr_T)vcol); + vcol += win_chartabsize(curwin, ptr + col, (colnr_T)vcol); if (vcol >= MAXCOL) { emsg(_(e_resulting_text_too_long)); break; diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index c1c5680cb0..f875fda13d 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -2547,7 +2547,7 @@ static int vgetorpeek(bool advance) && (State & MODE_INSERT) && (p_timeout || (keylen == KEYLEN_PART_KEY && p_ttimeout)) && (c = inchar(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len, 3, 25L)) == 0) { - colnr_T col = 0, vcol; + colnr_T col = 0; char_u *ptr; if (mode_displayed) { @@ -2565,15 +2565,20 @@ static int vgetorpeek(bool advance) // We are expecting to truncate the trailing // white-space, so find the last non-white // character -- webb - col = vcol = curwin->w_wcol = 0; + curwin->w_wcol = 0; ptr = get_cursor_line_ptr(); - while (col < curwin->w_cursor.col) { - if (!ascii_iswhite(ptr[col])) { - curwin->w_wcol = vcol; + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, + curwin->w_cursor.lnum, 0, ptr, ptr); + while ((char_u *)cts.cts_ptr < ptr + curwin->w_cursor.col) { + if (!ascii_iswhite(*cts.cts_ptr)) { + curwin->w_wcol = cts.cts_vcol; } - vcol += lbr_chartabsize(ptr, ptr + col, vcol); - col += utfc_ptr2len((char *)ptr + col); + cts.cts_vcol += lbr_chartabsize(&cts); + cts.cts_ptr += utfc_ptr2len(cts.cts_ptr); } + clear_chartabsize_arg(&cts); + curwin->w_wrow = curwin->w_cline_row + curwin->w_wcol / curwin->w_width_inner; curwin->w_wcol %= curwin->w_width_inner; diff --git a/src/nvim/indent.c b/src/nvim/indent.c index c4805283c2..8aa8492dae 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -1034,13 +1034,15 @@ int get_lisp_indent(void) amount = 2; } else { char_u *line = that; - - amount = 0; - - while (*that && col) { - amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount); + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, pos->lnum, 0, line, line); + while (*cts.cts_ptr != NUL && col > 0) { + cts.cts_vcol += lbr_chartabsize_adv(&cts); col--; } + amount = cts.cts_vcol; + that = (char_u *)cts.cts_ptr; + clear_chartabsize_arg(&cts); // Some keywords require "body" indenting rules (the // non-standard-lisp ones are Scheme special forms): @@ -1056,10 +1058,15 @@ int get_lisp_indent(void) } firsttry = amount; - while (ascii_iswhite(*that)) { - amount += lbr_chartabsize(line, that, (colnr_T)amount); - that++; + init_chartabsize_arg(&cts, curwin, (colnr_T)(that - line), + amount, line, that); + while (ascii_iswhite(*cts.cts_ptr)) { + cts.cts_vcol += lbr_chartabsize(&cts); + cts.cts_ptr++; } + that = (char_u *)cts.cts_ptr; + amount = cts.cts_vcol; + clear_chartabsize_arg(&cts); if (*that && (*that != ';')) { // Not a comment line. @@ -1072,33 +1079,38 @@ int get_lisp_indent(void) parencount = 0; quotecount = 0; + init_chartabsize_arg(&cts, curwin, + (colnr_T)(that - line), amount, line, that); if (vi_lisp || ((*that != '"') && (*that != '\'') && (*that != '#') && ((*that < '0') || (*that > '9')))) { - while (*that - && (!ascii_iswhite(*that) || quotecount || parencount) - && (!((*that == '(' || *that == '[') + while (*cts.cts_ptr + && (!ascii_iswhite(*cts.cts_ptr) || quotecount || parencount) + && (!((*cts.cts_ptr == '(' || *cts.cts_ptr == '[') && !quotecount && !parencount && vi_lisp))) { - if (*that == '"') { + if (*cts.cts_ptr == '"') { quotecount = !quotecount; } - if (((*that == '(') || (*that == '[')) && !quotecount) { + if (((*cts.cts_ptr == '(') || (*cts.cts_ptr == '[')) && !quotecount) { parencount++; } - if (((*that == ')') || (*that == ']')) && !quotecount) { + if (((*cts.cts_ptr == ')') || (*cts.cts_ptr == ']')) && !quotecount) { parencount--; } - if ((*that == '\\') && (*(that + 1) != NUL)) { - amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount); + if ((*cts.cts_ptr == '\\') && (*(cts.cts_ptr + 1) != NUL)) { + cts.cts_vcol += lbr_chartabsize_adv(&cts); } - amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount); + cts.cts_vcol += lbr_chartabsize_adv(&cts); } } - while (ascii_iswhite(*that)) { - amount += lbr_chartabsize(line, that, (colnr_T)amount); - that++; + while (ascii_iswhite(*cts.cts_ptr)) { + cts.cts_vcol += lbr_chartabsize(&cts); + cts.cts_ptr++; } + that = (char_u *)cts.cts_ptr; + amount = cts.cts_vcol; + clear_chartabsize_arg(&cts); if (!*that || (*that == ';')) { amount = firsttry; diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 3dfbeec048..5ebe97aa61 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -631,14 +631,16 @@ colnr_T vcol2col(win_T *const wp, const linenr_T lnum, const colnr_T vcol) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { // try to advance to the specified column - char_u *ptr = ml_get_buf(wp->w_buffer, lnum, false); - char_u *const line = ptr; - colnr_T count = 0; - while (count < vcol && *ptr != NUL) { - count += win_lbr_chartabsize(wp, line, ptr, count, NULL); - MB_PTR_ADV(ptr); - } - return (colnr_T)(ptr - line); + char_u *line = ml_get_buf(wp->w_buffer, lnum, false); + chartabsize_T cts; + init_chartabsize_arg(&cts, wp, lnum, 0, line, line); + while (cts.cts_vcol < vcol && *cts.cts_ptr != NUL) { + cts.cts_vcol += win_lbr_chartabsize(&cts, NULL); + MB_PTR_ADV(cts.cts_ptr); + } + clear_chartabsize_arg(&cts); + + return (colnr_T)((char_u *)cts.cts_ptr - line); } /// Set UI mouse depending on current mode and 'mouse'. @@ -667,7 +669,7 @@ static colnr_T scroll_line_len(linenr_T lnum) char_u *line = ml_get(lnum); if (*line != NUL) { for (;;) { - int numchar = win_chartabsize(curwin, line, col); + int numchar = win_chartabsize(curwin, (char *)line, col); MB_PTR_ADV(line); if (*line == NUL) { // don't count the last character break; @@ -790,7 +792,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 += win_chartabsize(curwin, ptr, vcol); + vcol += win_chartabsize(curwin, (char *)ptr, vcol); ptr += utfc_ptr2len((char *)ptr); } @@ -801,7 +803,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 += win_chartabsize(curwin, ptr_end, vcol); + vcol += win_chartabsize(curwin, (char *)ptr_end, vcol); ptr_end += utfc_ptr2len((char *)ptr_end); } @@ -816,7 +818,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) #define DECR() nudge--; ptr_end -= utfc_ptr2len((char *)ptr_end) while (ptr < ptr_end && *ptr != NUL) { - cwidth = win_chartabsize(curwin, ptr, vcol); + cwidth = win_chartabsize(curwin, (char *)ptr, vcol); vcol += cwidth; if (cwidth > 1 && *ptr == '\t' && nudge > 0) { // A tab will "absorb" any previous adjustments. diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 0fc15b9382..896cfa6098 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -378,12 +378,20 @@ static void shift_block(oparg_T *oap, int amount) bd.startspaces = 0; } } - for (; ascii_iswhite(*bd.textstart);) { - // TODO(fmoralesc): is passing bd.textstart for start of the line OK? - incr = lbr_chartabsize_adv(bd.textstart, &bd.textstart, bd.start_vcol); + + // TODO(vim): is passing bd.textstart for start of the line OK? + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, + bd.start_vcol, bd.textstart, bd.textstart); + while (ascii_iswhite(*cts.cts_ptr)) { + incr = lbr_chartabsize_adv(&cts); total += incr; - bd.start_vcol += incr; + cts.cts_vcol += incr; } + bd.textstart = (char_u *)cts.cts_ptr; + bd.start_vcol = cts.cts_vcol; + clear_chartabsize_arg(&cts); + // OK, now total=all the VWS reqd, and textstart points at the 1st // non-ws char in the block. if (!curbuf->b_p_et) { @@ -438,10 +446,16 @@ static void shift_block(oparg_T *oap, int amount) // The character's column is in "bd.start_vcol". colnr_T non_white_col = bd.start_vcol; - while (ascii_iswhite(*non_white)) { - incr = lbr_chartabsize_adv(bd.textstart, &non_white, non_white_col); - non_white_col += incr; + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, + non_white_col, bd.textstart, non_white); + while (ascii_iswhite(*cts.cts_ptr)) { + incr = lbr_chartabsize_adv(&cts); + cts.cts_vcol += incr; } + non_white_col = cts.cts_vcol; + non_white = (char_u *)cts.cts_ptr; + clear_chartabsize_arg(&cts); const colnr_T block_space_width = non_white_col - oap->start_vcol; // We will shift by "total" or "block_space_width", whichever is less. @@ -462,17 +476,19 @@ static void shift_block(oparg_T *oap, int amount) if (bd.startspaces) { verbatim_copy_width -= bd.start_char_vcols; } - while (verbatim_copy_width < destination_col) { - char_u *line = verbatim_copy_end; - - // TODO: is passing verbatim_copy_end for start of the line OK? - incr = lbr_chartabsize(line, verbatim_copy_end, verbatim_copy_width); - if (verbatim_copy_width + incr > destination_col) { + init_chartabsize_arg(&cts, curwin, 0, verbatim_copy_width, + bd.textstart, verbatim_copy_end); + while (cts.cts_vcol < destination_col) { + incr = lbr_chartabsize(&cts); + if (cts.cts_vcol + incr > destination_col) { break; } - verbatim_copy_width += incr; - MB_PTR_ADV(verbatim_copy_end); + cts.cts_vcol += incr; + MB_PTR_ADV(cts.cts_ptr); } + verbatim_copy_width = cts.cts_vcol; + verbatim_copy_end = (char_u *)cts.cts_ptr; + clear_chartabsize_arg(&cts); // If "destination_col" is different from the width of the initial // part of the line that will be copied, it means we encountered a tab @@ -1550,6 +1566,7 @@ int op_delete(oparg_T *oap) // Put deleted text into register 1 and shift number registers if the // delete contains a line break, or when using a specific operator (Vi // compatible) + if (oap->motion_type == kMTLineWise || oap->line_count > 1 || oap->use_reg_one) { shift_delete_registers(is_append_register(oap->regname)); reg = &y_regs[1]; @@ -3280,12 +3297,19 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) // get the old line and advance to the position to insert at oldp = get_cursor_line_ptr(); oldlen = STRLEN(oldp); - for (ptr = oldp; vcol < col && *ptr;) { + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, 0, + oldp, oldp); + + while (cts.cts_vcol < col && *cts.cts_ptr != NUL) { // Count a tab for what it's worth (if list mode not on) - incr = lbr_chartabsize_adv(oldp, &ptr, vcol); - vcol += incr; + incr = lbr_chartabsize_adv(&cts); + cts.cts_vcol += incr; } + vcol = cts.cts_vcol; + ptr = (char_u *)cts.cts_ptr; bd.textcol = (colnr_T)(ptr - oldp); + clear_chartabsize_arg(&cts); shortline = (vcol < col) || (vcol == col && !*ptr); @@ -3312,9 +3336,14 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) // calculate number of spaces required to fill right side of // block spaces = y_width + 1; + init_chartabsize_arg(&cts, curwin, 0, 0, + (char_u *)y_array[i], (char_u *)y_array[i]); for (int j = 0; j < yanklen; j++) { - spaces -= lbr_chartabsize(NULL, (char_u *)(&y_array[i][j]), 0); + spaces -= lbr_chartabsize(&cts); + cts.cts_ptr++; + cts.cts_vcol = 0; } + clear_chartabsize_arg(&cts); if (spaces < 0) { spaces = 0; } @@ -4227,22 +4256,28 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bool bdp->start_char_vcols = 0; line = ml_get(lnum); - pstart = line; prev_pstart = line; - while (bdp->start_vcol < oap->start_vcol && *pstart) { + + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, lnum, bdp->start_vcol, line, line); + while (cts.cts_vcol < oap->start_vcol && *cts.cts_ptr != NUL) { // Count a tab for what it's worth (if list mode not on) - incr = lbr_chartabsize(line, pstart, bdp->start_vcol); - bdp->start_vcol += incr; - if (ascii_iswhite(*pstart)) { + incr = lbr_chartabsize(&cts); + cts.cts_vcol += incr; + if (ascii_iswhite(*cts.cts_ptr)) { bdp->pre_whitesp += incr; bdp->pre_whitesp_c++; } else { bdp->pre_whitesp = 0; bdp->pre_whitesp_c = 0; } - prev_pstart = pstart; - MB_PTR_ADV(pstart); + prev_pstart = (char_u *)cts.cts_ptr; + MB_PTR_ADV(cts.cts_ptr); } + bdp->start_vcol = cts.cts_vcol; + pstart = (char_u *)cts.cts_ptr; + clear_chartabsize_arg(&cts); + bdp->start_char_vcols = incr; if (bdp->start_vcol < oap->start_vcol) { // line too short bdp->end_vcol = bdp->start_vcol; @@ -4278,13 +4313,19 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bool } } } else { + init_chartabsize_arg(&cts, curwin, lnum, bdp->end_vcol, + line, pend); prev_pend = pend; - while (bdp->end_vcol <= oap->end_vcol && *pend != NUL) { + while (cts.cts_vcol <= oap->end_vcol && *cts.cts_ptr != NUL) { // Count a tab for what it's worth (if list mode not on) - prev_pend = pend; - incr = lbr_chartabsize_adv(line, &pend, bdp->end_vcol); - bdp->end_vcol += incr; + prev_pend = (char_u *)cts.cts_ptr; + incr = lbr_chartabsize_adv(&cts); + cts.cts_vcol += incr; } + bdp->end_vcol = cts.cts_vcol; + pend = (char_u *)cts.cts_ptr; + clear_chartabsize_arg(&cts); + if (bdp->end_vcol <= oap->end_vcol && (!is_del || oap->op_type == OP_APPEND diff --git a/src/nvim/plines.c b/src/nvim/plines.c index 70bdbd8b1d..f13e83ca9b 100644 --- a/src/nvim/plines.c +++ b/src/nvim/plines.c @@ -98,15 +98,15 @@ int plines_win_nofill(win_T *wp, linenr_T lnum, bool winheight) /// "wp". Does not care about folding, 'wrap' or 'diff'. int plines_win_nofold(win_T *wp, linenr_T lnum) { - char_u *s; + char *s; unsigned int col; int width; - s = ml_get_buf(wp->w_buffer, lnum, false); + s = (char *)ml_get_buf(wp->w_buffer, lnum, false); if (*s == NUL) { // empty line return 1; } - col = win_linetabsize(wp, s, MAXCOL); + col = win_linetabsize(wp, lnum, (char_u *)s, MAXCOL); // If list mode is on, then the '$' at the end of the line may take up one // extra column. @@ -145,23 +145,27 @@ int plines_win_col(win_T *wp, linenr_T lnum, long column) } 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); + chartabsize_T cts; + + init_chartabsize_arg(&cts, wp, lnum, 0, line, line); + while (*cts.cts_ptr != NUL && --column >= 0) { + cts.cts_vcol += win_lbr_chartabsize(&cts, NULL); + MB_PTR_ADV(cts.cts_ptr); } - // If *s is a TAB, and the TAB is not displayed as ^I, and we're not in - // MODE_INSERT state, then col must be adjusted so that it represents the + // If *cts.cts_ptr is a TAB, and the TAB is not displayed as ^I, and we're not + // in MODE_INSERT state, 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 & MODE_NORMAL) + col = cts.cts_vcol; + if (*cts.cts_ptr == TAB && (State & MODE_NORMAL) && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) { - col += win_lbr_chartabsize(wp, line, s, col, NULL) - 1; + col += win_lbr_chartabsize(&cts, NULL) - 1; } + clear_chartabsize_arg(&cts); // Add column offset for 'number', 'relativenumber', 'foldcolumn', etc. |