summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-07-25 18:13:54 +0100
committerBram Moolenaar <Bram@vim.org>2022-07-25 18:13:54 +0100
commit7f9969c559b51446632ac7e8f76cde07e7d0078d (patch)
tree77868549433487dbadb8833a1b6a63d522adaa72 /src
parentb529cfbd04c02e31cfa88f2c8d88b5ff532d4f7d (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.c2
-rw-r--r--src/charset.c307
-rw-r--r--src/drawline.c70
-rw-r--r--src/edit.c51
-rw-r--r--src/errors.h4
-rw-r--r--src/evalfunc.c2
-rw-r--r--src/getchar.c24
-rw-r--r--src/indent.c80
-rw-r--r--src/misc1.c30
-rw-r--r--src/misc2.c19
-rw-r--r--src/mouse.c20
-rw-r--r--src/ops.c86
-rw-r--r--src/popupwin.c2
-rw-r--r--src/proto/charset.pro10
-rw-r--r--src/proto/textprop.pro2
-rw-r--r--src/regexp.c2
-rw-r--r--src/regexp_bt.c4
-rw-r--r--src/regexp_nfa.c4
-rw-r--r--src/register.c26
-rw-r--r--src/structs.h21
-rw-r--r--src/testdir/dumps/Test_prop_inserts_text.dump6
-rw-r--r--src/testdir/test_textprop.vim23
-rw-r--r--src/textprop.c102
-rw-r--r--src/version.c2
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)