diff options
author | Bram Moolenaar <Bram@vim.org> | 2022-07-25 18:13:54 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-07-25 18:13:54 +0100 |
commit | 7f9969c559b51446632ac7e8f76cde07e7d0078d (patch) | |
tree | 77868549433487dbadb8833a1b6a63d522adaa72 /src | |
parent | b529cfbd04c02e31cfa88f2c8d88b5ff532d4f7d (diff) |
patch 9.0.0067: cannot show virtual textv9.0.0067
Problem: Cannot show virtual text.
Solution: Initial changes for virtual text support, using text properties.
Diffstat (limited to 'src')
-rw-r--r-- | src/beval.c | 2 | ||||
-rw-r--r-- | src/charset.c | 307 | ||||
-rw-r--r-- | src/drawline.c | 70 | ||||
-rw-r--r-- | src/edit.c | 51 | ||||
-rw-r--r-- | src/errors.h | 4 | ||||
-rw-r--r-- | src/evalfunc.c | 2 | ||||
-rw-r--r-- | src/getchar.c | 24 | ||||
-rw-r--r-- | src/indent.c | 80 | ||||
-rw-r--r-- | src/misc1.c | 30 | ||||
-rw-r--r-- | src/misc2.c | 19 | ||||
-rw-r--r-- | src/mouse.c | 20 | ||||
-rw-r--r-- | src/ops.c | 86 | ||||
-rw-r--r-- | src/popupwin.c | 2 | ||||
-rw-r--r-- | src/proto/charset.pro | 10 | ||||
-rw-r--r-- | src/proto/textprop.pro | 2 | ||||
-rw-r--r-- | src/regexp.c | 2 | ||||
-rw-r--r-- | src/regexp_bt.c | 4 | ||||
-rw-r--r-- | src/regexp_nfa.c | 4 | ||||
-rw-r--r-- | src/register.c | 26 | ||||
-rw-r--r-- | src/structs.h | 21 | ||||
-rw-r--r-- | src/testdir/dumps/Test_prop_inserts_text.dump | 6 | ||||
-rw-r--r-- | src/testdir/test_textprop.vim | 23 | ||||
-rw-r--r-- | src/textprop.c | 102 | ||||
-rw-r--r-- | src/version.c | 2 |
24 files changed, 639 insertions, 260 deletions
diff --git a/src/beval.c b/src/beval.c index 4b89af3667..79ffff5f4d 100644 --- a/src/beval.c +++ b/src/beval.c @@ -47,7 +47,7 @@ find_word_under_cursor( { // Not past end of the file. lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE); - if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL)) + if (col <= win_linetabsize(wp, lnum, lbuf, (colnr_T)MAXCOL)) { // Not past end of line. if (getword) diff --git a/src/charset.c b/src/charset.c index 203a8fe0f9..2df64c9904 100644 --- a/src/charset.c +++ b/src/charset.c @@ -12,8 +12,8 @@ #if defined(HAVE_WCHAR_H) # include <wchar.h> // for towupper() and towlower() #endif -static int win_nolbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp); +static int win_nolbr_chartabsize(chartabsize_T *cts, int *headp); static unsigned nr2hex(unsigned c); static int chartab_initialized = FALSE; @@ -737,8 +737,9 @@ win_chartabsize(win_T *wp, char_u *p, colnr_T col) #endif /* - * Return the number of characters the string 's' will take on the screen, + * Return the number of characters the string "s" will take on the screen, * taking into account the size of a tab. + * Does not handle text properties, since "s" is not a buffer line. */ int linetabsize(char_u *s) @@ -747,32 +748,34 @@ linetabsize(char_u *s) } /* - * Like linetabsize(), but starting at column "startcol". + * Like linetabsize(), but "s" starts at column "startcol". */ int linetabsize_col(int startcol, char_u *s) { - colnr_T col = startcol; - char_u *line = s; // pointer to start of line, for breakindent + chartabsize_T cts; - while (*s != NUL) - col += lbr_chartabsize_adv(line, &s, col); - return (int)col; + init_chartabsize_arg(&cts, curwin, 0, startcol, s, s); + while (*cts.cts_ptr != NUL) + cts.cts_vcol += lbr_chartabsize_adv(&cts); + clear_chartabsize_arg(&cts); + return (int)cts.cts_vcol; } /* * Like linetabsize(), but for a given window instead of the current one. */ int -win_linetabsize(win_T *wp, char_u *line, colnr_T len) +win_linetabsize(win_T *wp, linenr_T lnum, char_u *line, colnr_T len) { - colnr_T col = 0; - char_u *s; + chartabsize_T cts; - for (s = line; *s != NUL && (len == MAXCOL || s < line + len); - MB_PTR_ADV(s)) - col += win_lbr_chartabsize(wp, line, s, col, NULL); - return (int)col; + init_chartabsize_arg(&cts, wp, lnum, 0, line, line); + for ( ; *cts.cts_ptr != NUL && (len == MAXCOL || cts.cts_ptr < line + len); + MB_PTR_ADV(cts.cts_ptr)) + cts.cts_vcol += win_lbr_chartabsize(&cts, NULL); + clear_chartabsize_arg(&cts); + return (int)cts.cts_vcol; } /* @@ -893,25 +896,101 @@ vim_isprintc_strict(int c) } /* - * like chartabsize(), but also check for line breaks on the screen + * Prepare the structure passed to chartabsize functions. + * "line" is the start of the line, "ptr" is the first relevant character. + * When "lnum" is zero do not use text properties that insert text. + */ + void +init_chartabsize_arg( + chartabsize_T *cts, + win_T *wp, + linenr_T lnum, + colnr_T col, + char_u *line, + char_u *ptr) +{ + cts->cts_win = wp; + cts->cts_lnum = lnum; + cts->cts_vcol = col; + cts->cts_line = line; + cts->cts_ptr = ptr; +#ifdef FEAT_PROP_POPUP + cts->cts_text_prop_count = 0; + cts->cts_has_prop_with_text = FALSE; + cts->cts_cur_text_width = 0; + if (lnum > 0) + { + char_u *prop_start; + + cts->cts_text_prop_count = get_text_props(wp->w_buffer, lnum, + &prop_start, FALSE); + if (cts->cts_text_prop_count > 0) + { + // Make a copy of the properties, so that they are properly + // aligned. + cts->cts_text_props = ALLOC_MULT(textprop_T, + cts->cts_text_prop_count); + if (cts->cts_text_props == NULL) + cts->cts_text_prop_count = 0; + else + { + int i; + + mch_memmove(cts->cts_text_props, prop_start, + cts->cts_text_prop_count * sizeof(textprop_T)); + for (i = 0; i < cts->cts_text_prop_count; ++i) + if (cts->cts_text_props[i].tp_id < 0) + { + cts->cts_has_prop_with_text = TRUE; + break; + } + if (!cts->cts_has_prop_with_text) + { + // won't use the text properties, free them + vim_free(cts->cts_text_props); + cts->cts_text_prop_count = 0; + } + } + } + } +#endif +} + +/* + * Free any allocated item in "cts". + */ + void +clear_chartabsize_arg(chartabsize_T *cts) +{ + if (cts->cts_text_prop_count > 0) + vim_free(cts->cts_text_props); +} + +/* + * Like chartabsize(), but also check for line breaks on the screen and text + * properties that insert text. */ int -lbr_chartabsize( - char_u *line UNUSED, // start of the line - unsigned char *s, - colnr_T col) +lbr_chartabsize(chartabsize_T *cts) { -#ifdef FEAT_LINEBREAK - if (!curwin->w_p_lbr && *get_showbreak_value(curwin) == NUL - && !curwin->w_p_bri) +#if defined(FEAT_LINEBREAK) || defined(FEAT_PROP_POPUP) + if (1 +# ifdef FEAT_LINEBREAK + && !curwin->w_p_lbr && *get_showbreak_value(curwin) == NUL + && !curwin->w_p_bri +# endif +# ifdef FEAT_PROP_POPUP + && !cts->cts_has_prop_with_text +#endif + ) { #endif if (curwin->w_p_wrap) - return win_nolbr_chartabsize(curwin, s, col, NULL); - RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, s, col) -#ifdef FEAT_LINEBREAK + return win_nolbr_chartabsize(cts, NULL); + RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, cts->cts_ptr, cts->cts_vcol) +#if defined(FEAT_LINEBREAK) || defined(FEAT_PROP_POPUP) } - return win_lbr_chartabsize(curwin, line == NULL ? s : line, s, col, NULL); + return win_lbr_chartabsize(cts, NULL); #endif } @@ -919,19 +998,19 @@ lbr_chartabsize( * Call lbr_chartabsize() and advance the pointer. */ int -lbr_chartabsize_adv( - char_u *line, // start of the line - char_u **s, - colnr_T col) +lbr_chartabsize_adv(chartabsize_T *cts) { int retval; - retval = lbr_chartabsize(line, *s, col); - MB_PTR_ADV(*s); + retval = lbr_chartabsize(cts); + MB_PTR_ADV(cts->cts_ptr); return retval; } /* + * Return the screen size of the character indicated by "cts". + * "cts->cts_cur_text_width" is set to the extra size for a text property that + * inserts text. * This function is used very often, keep it fast!!!! * * If "headp" not NULL, set *headp to the size of what we for 'showbreak' @@ -940,17 +1019,18 @@ lbr_chartabsize_adv( */ int win_lbr_chartabsize( - win_T *wp, - char_u *line UNUSED, // start of the line - char_u *s, - colnr_T col, - int *headp UNUSED) + chartabsize_T *cts, + int *headp UNUSED) { + win_T *wp = cts->cts_win; + char_u *line = cts->cts_line; // start of the line + char_u *s = cts->cts_ptr; + colnr_T vcol = cts->cts_vcol; #ifdef FEAT_LINEBREAK int c; int size; colnr_T col2; - colnr_T col_adj = 0; // col + screen size of tab + colnr_T col_adj = 0; // vcol + screen size of tab colnr_T colmax; int added; int mb_added = 0; @@ -959,23 +1039,66 @@ win_lbr_chartabsize( int tab_corr = (*s == TAB); int n; char_u *sbr; +#endif + +#if defined(FEAT_PROP_POPUP) + cts->cts_cur_text_width = 0; +#endif +#if defined(FEAT_LINEBREAK) || defined(FEAT_PROP_POPUP) /* - * No 'linebreak', 'showbreak' and 'breakindent': return quickly. + * No 'linebreak', 'showbreak', 'breakindent' and text properties that + * insert text: return quickly. */ - if (!wp->w_p_lbr && !wp->w_p_bri && *get_showbreak_value(wp) == NUL) + if (1 +# ifdef FEAT_LINEBREAK + && !wp->w_p_lbr && !wp->w_p_bri && *get_showbreak_value(wp) == NUL +# endif +# ifdef FEAT_PROP_POPUP + && !cts->cts_has_prop_with_text +# endif + ) #endif { if (wp->w_p_wrap) - return win_nolbr_chartabsize(wp, s, col, headp); - RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, s, col) + return win_nolbr_chartabsize(cts, headp); + RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, s, vcol) } -#ifdef FEAT_LINEBREAK +#if defined(FEAT_LINEBREAK) || defined(FEAT_PROP_POPUP) /* - * First get normal size, without 'linebreak' + * First get the normal size, without 'linebreak' or text properties */ - size = win_chartabsize(wp, s, col); + size = win_chartabsize(wp, s, vcol); + +# ifdef FEAT_PROP_POPUP + if (cts->cts_has_prop_with_text) + { + int i; + int col = (int)(s - line); + + for (i = 0; i < cts->cts_text_prop_count; ++i) + { + textprop_T *tp = cts->cts_text_props + i; + + if (tp->tp_id < 0 + && tp->tp_col - 1 >= col && tp->tp_col - 1 < col + size + && -tp->tp_id <= wp->w_buffer->b_textprop_text.ga_len) + { + char_u *p = ((char_u **)wp->w_buffer->b_textprop_text.ga_data)[ + -tp->tp_id - 1]; + // TODO: count screen cells + cts->cts_cur_text_width = STRLEN(p); + size += cts->cts_cur_text_width; + break; + } + if (tp->tp_col - 1 > col) + break; + } + } +# endif + +# ifdef FEAT_LINEBREAK c = *s; if (tab_corr) col_adj = size - 1; @@ -995,14 +1118,14 @@ win_lbr_chartabsize( * non-blank after a blank. */ numberextra = win_col_off(wp); - col2 = col; + col2 = vcol; colmax = (colnr_T)(wp->w_width - numberextra - col_adj); - if (col >= colmax) + if (vcol >= colmax) { colmax += col_adj; n = colmax + win_col_off2(wp); if (n > 0) - colmax += (((col - colmax) / n) + 1) * n - col_adj; + colmax += (((vcol - colmax) / n) + 1) * n - col_adj; } for (;;) @@ -1013,19 +1136,19 @@ win_lbr_chartabsize( if (!(c != NUL && (VIM_ISBREAK(c) || (!VIM_ISBREAK(c) - && (col2 == col || !VIM_ISBREAK((int)*ps)))))) + && (col2 == vcol || !VIM_ISBREAK((int)*ps)))))) break; col2 += win_chartabsize(wp, s, col2); if (col2 >= colmax) // doesn't fit { - size = colmax - col + col_adj; + size = colmax - vcol + col_adj; break; } } } else if (has_mbyte && size == 2 && MB_BYTE2LEN(*s) > 1 - && wp->w_p_wrap && in_win_border(wp, col)) + && wp->w_p_wrap && in_win_border(wp, vcol)) { ++size; // Count the ">" in the last column. mb_added = 1; @@ -1039,33 +1162,33 @@ win_lbr_chartabsize( */ added = 0; sbr = c == NUL ? empty_option : get_showbreak_value(wp); - if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && col != 0) + if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && vcol != 0) { colnr_T sbrlen = 0; int numberwidth = win_col_off(wp); numberextra = numberwidth; - col += numberextra + mb_added; - if (col >= (colnr_T)wp->w_width) + vcol += numberextra + mb_added; + if (vcol >= (colnr_T)wp->w_width) { - col -= wp->w_width; + vcol -= wp->w_width; numberextra = wp->w_width - (numberextra - win_col_off2(wp)); - if (col >= numberextra && numberextra > 0) - col %= numberextra; + if (vcol >= numberextra && numberextra > 0) + vcol %= numberextra; if (*sbr != NUL) { sbrlen = (colnr_T)MB_CHARLEN(sbr); - if (col >= sbrlen) - col -= sbrlen; + if (vcol >= sbrlen) + vcol -= sbrlen; } - if (col >= numberextra && numberextra > 0) - col = col % numberextra; - else if (col > 0 && numberextra > 0) - col += numberwidth - win_col_off2(wp); + if (vcol >= numberextra && numberextra > 0) + vcol = vcol % numberextra; + else if (vcol > 0 && numberextra > 0) + vcol += numberwidth - win_col_off2(wp); numberwidth -= win_col_off2(wp); } - if (col == 0 || col + size + sbrlen > (colnr_T)wp->w_width) + if (vcol == 0 || vcol + size + sbrlen > (colnr_T)wp->w_width) { added = 0; if (*sbr != NUL) @@ -1074,8 +1197,8 @@ win_lbr_chartabsize( { // calculate effective window width int width = (colnr_T)wp->w_width - sbrlen - numberwidth; - int prev_width = col - ? ((colnr_T)wp->w_width - (sbrlen + col)) : 0; + int prev_width = vcol + ? ((colnr_T)wp->w_width - (sbrlen + vcol)) : 0; if (width <= 0) width = (colnr_T)1; @@ -1091,28 +1214,32 @@ win_lbr_chartabsize( added += get_breakindent_win(wp, line); size += added; - if (col != 0) + if (vcol != 0) added = 0; } } if (headp != NULL) *headp = added + mb_added; return size; +# endif #endif } /* - * 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. + * Like win_lbr_chartabsize(), except that we know 'linebreak' is off, 'wrap' + * is on and there are no properties that insert text. This means we need to + * check for a double-byte character that doesn't fit at the end of the screen + * line. + * Only uses "cts_win", "cts_ptr" and "cts_vcol" from "cts". */ static int win_nolbr_chartabsize( - win_T *wp, - char_u *s, - colnr_T col, - int *headp) + chartabsize_T *cts, + int *headp) { + win_T *wp = cts->cts_win; + char_u *s = cts->cts_ptr; + colnr_T col = cts->cts_vcol; int n; if (*s == TAB && (!wp->w_p_list || wp->w_lcs_chars.tab1)) @@ -1187,6 +1314,7 @@ getvcol( #endif int ts = wp->w_buffer->b_p_ts; int c; + chartabsize_T cts; vcol = 0; line = ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE); @@ -1209,16 +1337,21 @@ getvcol( posptr -= (*mb_head_off)(line, posptr); } + 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 text properties with "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_lcs_chars.tab1 != NUL) #ifdef FEAT_LINEBREAK && !wp->w_p_lbr && *get_showbreak_value(wp) == NUL && !wp->w_p_bri #endif +#ifdef FEAT_PROP_POPUP + && !cts.cts_has_prop_with_text +#endif ) { for (;;) @@ -1274,29 +1407,39 @@ getvcol( { for (;;) { - // A tab gets expanded, depending on the current column + // 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) { incr = 1; // NUL at end of line only takes one column break; } - if (posptr != NULL && ptr >= posptr) // character at pos->col + if (posptr != NULL && 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 = cts.cts_ptr; } + clear_chartabsize_arg(&cts); + if (start != NULL) *start = vcol + head; if (end != NULL) *end = vcol + incr - 1; if (cursor != NULL) { +#ifdef FEAT_PROP_POPUP + // cursor is after inserted text + vcol += cts.cts_cur_text_width; +#endif if (*ptr == TAB && (State & MODE_NORMAL) && !wp->w_p_list diff --git a/src/drawline.c b/src/drawline.c index e91ef291dc..d474de26c0 100644 --- a/src/drawline.c +++ b/src/drawline.c @@ -326,6 +326,7 @@ win_line( int text_props_active = 0; proptype_T *text_prop_type = NULL; int text_prop_attr = 0; + int text_prop_id = 0; // active property ID int text_prop_combine = FALSE; #endif #ifdef FEAT_SPELL @@ -816,15 +817,21 @@ win_line( v = wp->w_leftcol; if (v > 0 && !number_only) { - char_u *prev_ptr = ptr; + char_u *prev_ptr = ptr; + chartabsize_T cts; + int charsize; - while (vcol < v && *ptr != NUL) + init_chartabsize_arg(&cts, wp, lnum, vcol, line, ptr); + while (cts.cts_vcol < v && *cts.cts_ptr != NUL) { - c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL); - vcol += c; - prev_ptr = ptr; - MB_PTR_ADV(ptr); + 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 @@ -844,11 +851,11 @@ win_line( // 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 (( (*mb_ptr2cells)(ptr) >= c || *ptr == TAB) && col == 0) + if (( (*mb_ptr2cells)(ptr) >= charsize || *ptr == TAB) && col == 0) n_skip = v - vcol; } @@ -1476,8 +1483,12 @@ win_line( text_prop_attr = 0; text_prop_combine = FALSE; text_prop_type = NULL; + text_prop_id = 0; if (text_props_active > 0) { + int used_tpi; + int used_attr = 0; + // Sort the properties on priority and/or starting last. // Then combine the attributes, highest priority last. current_text_props = text_props; @@ -1491,15 +1502,43 @@ win_line( proptype_T *pt = text_prop_type_by_id( wp->w_buffer, text_props[tpi].tp_type); - if (pt != NULL && pt->pt_hl_id > 0) + if (pt != NULL && pt->pt_hl_id > 0 + && text_props[tpi].tp_id != -MAXCOL) { - int pt_attr = syn_id2attr(pt->pt_hl_id); - + used_attr = syn_id2attr(pt->pt_hl_id); text_prop_type = pt; text_prop_attr = - hl_combine_attr(text_prop_attr, pt_attr); + hl_combine_attr(text_prop_attr, used_attr); text_prop_combine = pt->pt_flags & PT_FLAG_COMBINE; + text_prop_id = text_props[tpi].tp_id; + used_tpi = tpi; + } + } + if (n_extra == 0 && text_prop_id < 0 + && -text_prop_id + <= wp->w_buffer->b_textprop_text.ga_len) + { + char_u *p = ((char_u **)wp->w_buffer + ->b_textprop_text.ga_data)[ + -text_prop_id - 1]; + if (p != NULL) + { + p_extra = p; + n_extra = STRLEN(p); + extra_attr = used_attr; + n_attr = n_extra; + text_prop_attr = 0; + + // If the cursor is on or after this position, + // move it forward. + if (wp == curwin + && lnum == curwin->w_cursor.lnum + && curwin->w_cursor.col >= vcol) + curwin->w_cursor.col += n_extra; } + // reset the ID in the copy to avoid it being used + // again + text_props[used_tpi].tp_id = -MAXCOL; } } } @@ -2025,10 +2064,10 @@ win_line( int mb_off = has_mbyte ? (*mb_head_off)(line, ptr - 1) : 0; char_u *p = ptr - (mb_off + 1); + chartabsize_T cts; - // TODO: is passing p for start of the line OK? - n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol, - NULL) - 1; + init_chartabsize_arg(&cts, wp, lnum, 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. @@ -2069,6 +2108,7 @@ win_line( if (!wp->w_p_list) c = ' '; } + clear_chartabsize_arg(&cts); } #endif diff --git a/src/edit.c b/src/edit.c index 2009be1377..54c53ffc00 100644 --- a/src/edit.c +++ b/src/edit.c @@ -4905,6 +4905,8 @@ ins_tab(void) colnr_T want_vcol, vcol; int change_col = -1; int save_list = curwin->w_p_list; + char_u *tab = (char_u *)"\t"; + chartabsize_T cts; /* * Get the current line. For MODE_VREPLACE state, don't make real @@ -4950,12 +4952,14 @@ ins_tab(void) getvcol(curwin, &fpos, &vcol, NULL, NULL); getvcol(curwin, cursor, &want_vcol, NULL, NULL); + 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 (VIM_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) { @@ -4970,21 +4974,27 @@ 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; + int repl_off = 0; // Skip over the spaces we need. - while (vcol < want_vcol && *ptr == ' ') + init_chartabsize_arg(&cts, curwin, 0, vcol, ptr, ptr); + while (cts.cts_vcol < want_vcol && *cts.cts_ptr == ' ') { - vcol += lbr_chartabsize(line, ptr, vcol); - ++ptr; + cts.cts_vcol += lbr_chartabsize(&cts); + ++cts.cts_ptr; ++repl_off; } + ptr = cts.cts_ptr; + vcol = cts.cts_vcol; + clear_chartabsize_arg(&cts); + if (vcol > want_vcol) { // Must have a char with 'showbreak' just before it. @@ -5220,10 +5230,10 @@ ins_digraph(void) int ins_copychar(linenr_T lnum) { - int c; - int temp; - char_u *ptr, *prev_ptr; - char_u *line; + int c; + char_u *ptr, *prev_ptr; + char_u *line; + chartabsize_T cts; if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) { @@ -5233,16 +5243,19 @@ ins_copychar(linenr_T lnum) // try to advance to the cursor column validate_virtcol(); - temp = 0; - line = ptr = ml_get(lnum); - prev_ptr = ptr; - while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL) + line = ml_get(lnum); + prev_ptr = line; + init_chartabsize_arg(&cts, curwin, lnum, 0, line, line); + while (cts.cts_vcol < curwin->w_virtcol && *cts.cts_ptr != NUL) { - prev_ptr = ptr; - temp += lbr_chartabsize_adv(line, &ptr, (colnr_T)temp); + prev_ptr = 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 = cts.cts_ptr; + clear_chartabsize_arg(&cts); c = (*mb_ptr2char)(ptr); if (c == NUL) diff --git a/src/errors.h b/src/errors.h index 965187f785..e8008fd34d 100644 --- a/src/errors.h +++ b/src/errors.h @@ -3310,3 +3310,7 @@ EXTERN char e_invalid_argument_nr[] EXTERN char e_cmdline_window_already_open[] INIT(= N_("E1292: Command-line window is already open")); #endif +#ifdef FEAT_PROP_POPUP +EXTERN char e_cannot_use_negative_id_after_adding_textprop_with_text[] + INIT(= N_("E1291: Cannot use a negative id after adding a textprop with text")); +#endif diff --git a/src/evalfunc.c b/src/evalfunc.c index 8d6255d48b..1505418fb9 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -2218,7 +2218,7 @@ static funcentry_T global_functions[] = {"prompt_setprompt", 2, 2, FEARG_1, arg2_buffer_string, ret_void, JOB_FUNC(f_prompt_setprompt)}, {"prop_add", 3, 3, FEARG_1, arg3_number_number_dict, - ret_void, PROP_FUNC(f_prop_add)}, + ret_number, PROP_FUNC(f_prop_add)}, {"prop_add_list", 2, 2, FEARG_1, arg2_dict_any_list_any, ret_void, PROP_FUNC(f_prop_add_list)}, {"prop_clear", 1, 3, FEARG_1, arg3_number_number_dict, diff --git a/src/getchar.c b/src/getchar.c index fc15daaf7d..a3de6509f5 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -3210,7 +3210,7 @@ vgetorpeek(int advance) && (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) @@ -3242,24 +3242,30 @@ vgetorpeek(int advance) { if (did_ai) { + chartabsize_T cts; + /* * 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 = ml_get_curline(); - while (col < curwin->w_cursor.col) + init_chartabsize_arg(&cts, curwin, + curwin->w_cursor.lnum, 0, ptr, ptr); + while (cts.cts_ptr < ptr + curwin->w_cursor.col) { - if (!VIM_ISWHITE(ptr[col])) - curwin->w_wcol = vcol; - vcol += lbr_chartabsize(ptr, ptr + col, - vcol); + if (!VIM_ISWHITE(*cts.cts_ptr)) + curwin->w_wcol = cts.cts_vcol; + cts.cts_vcol += lbr_chartabsize(&cts); if (has_mbyte) - col += (*mb_ptr2len)(ptr + col); + cts.cts_ptr += + (*mb_ptr2len)(cts.cts_ptr); else - ++col; + ++cts.cts_ptr; } + clear_chartabsize_arg(&cts); + curwin->w_wrow = curwin->w_cline_row + curwin->w_wcol / curwin->w_width; curwin->w_wcol %= curwin->w_width; diff --git a/src/indent.c b/src/indent.c index 61497eb4f5..90ad5e2e7b 100644 --- a/src/indent.c +++ b/src/indent.c @@ -1350,26 +1350,28 @@ change_indent( new_cursor_col = curwin->w_cursor.col; else { + chartabsize_T cts; + // 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; + last_vcol = 0; ptr = ml_get_curline(); - while (vcol <= (int)curwin->w_virtcol) + init_chartabsize_arg(&cts, curwin, 0, 0, ptr, ptr); + while (cts.cts_vcol <= (int)curwin->w_virtcol) { - last_vcol = vcol; - if (has_mbyte && new_cursor_col >= 0) - new_cursor_col += (*mb_ptr2len)(ptr + new_cursor_col); - else - ++new_cursor_col; - if (ptr[new_cursor_col] == NUL) + 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 = cts.cts_ptr - cts.cts_line; + clear_chartabsize_arg(&cts); // May need to insert spaces to be able to position the cursor on // the right screen column. @@ -2064,14 +2066,18 @@ get_lisp_indent(void) amount = 2; else { - char_u *line = that; + char_u *line = that; + chartabsize_T cts; - amount = 0; - while (*that && col) + init_chartabsize_arg(&cts, curwin, pos->lnum, 0, line, line); + while (*cts.cts_ptr != NUL && col > 0) { - amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount); + cts.cts_vcol += lbr_chartabsize_adv(&cts); col--; } + amount = cts.cts_vcol; + that = cts.cts_ptr; + clear_chartabsize_arg(&cts); // Some keywords require "body" indenting rules (the // non-standard-lisp ones are Scheme special forms): @@ -2091,11 +2097,16 @@ get_lisp_indent(void) |