]> granicus.if.org Git - vim/commitdiff
patch 9.0.0067: cannot show virtual text v9.0.0067
authorBram Moolenaar <Bram@vim.org>
Mon, 25 Jul 2022 17:13:54 +0000 (18:13 +0100)
committerBram Moolenaar <Bram@vim.org>
Mon, 25 Jul 2022 17:13:54 +0000 (18:13 +0100)
Problem:    Cannot show virtual text.
Solution:   Initial changes for virtual text support, using text properties.

25 files changed:
runtime/doc/textprop.txt
src/beval.c
src/charset.c
src/drawline.c
src/edit.c
src/errors.h
src/evalfunc.c
src/getchar.c
src/indent.c
src/misc1.c
src/misc2.c
src/mouse.c
src/ops.c
src/popupwin.c
src/proto/charset.pro
src/proto/textprop.pro
src/regexp.c
src/regexp_bt.c
src/regexp_nfa.c
src/register.c
src/structs.h
src/testdir/dumps/Test_prop_inserts_text.dump [new file with mode: 0644]
src/testdir/test_textprop.vim
src/textprop.c
src/version.c

index fc71bb4c2e9705676709e04434b32b02969465f5..6b4c0235e894c68e29a8db97aa555870ec2fd7a7 100644 (file)
@@ -137,7 +137,11 @@ prop_add({lnum}, {col}, {props})
                   bufnr        buffer to add the property to; when omitted
                                the current buffer is used
                   id           user defined ID for the property; must be a
-                               number; when omitted zero is used
+                               number, should be positive; when using "text"
+                               then "id" must not be present and will be set
+                               automatically to a negative number; otherwise
+                               zero is used
+                  text         text to be displayed at {col}
                   type         name of the text property type
                All fields except "type" are optional.
 
@@ -157,6 +161,17 @@ prop_add({lnum}, {col}, {props})
                "type" will first be looked up in the buffer the property is
                added to. When not found, the global property types are used.
                If not found an error is given.
+                                                       *virtual-text*
+               When "text" is used this text will be displayed at the start
+               location of the text property.  The text of the buffer line
+               will be shifted to make room.  This is called "virtual text".
+               The text will be displayed but it is not part of the actual
+               buffer line, the cursor cannot be placed on it.  A mouse click
+               in the text will move the cursor to the first character after
+               the text.
+               A negative "id" will be chosen and is returned.  Once a
+               property with "text" has been added for a buffer then using a
+               negative "id" for any other property will give an error.
 
                Can also be used as a |method|: >
                        GetLnum()->prop_add(col, props)
@@ -181,6 +196,9 @@ prop_add_list({props}, [[{lnum}, {col}, {end-lnum}, {end-col}], ...])
                two items {end-lnum} and {end-col} specify the position just
                after the text.
 
+               It is not possible to add a text property with a "text" field
+               here.
+
                Example:
                        call prop_add_list(#{type: 'MyProp', id: 2},
                                        \ [[1, 4, 1, 7],
index 4b89af36672451c99fa77941450b7484e2bea06d..79ffff5f4d227e005660d2d6b66045ed08be4d81 100644 (file)
@@ -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)
index 203a8fe0f9456fad228ce38357ee5df57dff5d71..2df64c9904dd375dc56bb8cad47ea929bb987939 100644 (file)
@@ -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,15 +1337,20 @@ 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
        )
     {
@@ -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
index e91ef291dcc6db91775ccc823667546f2397cd3e..d474de26c0c5fb62c11c8745e9fd727e34ecc37d 100644 (file)
@@ -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
 
index 2009be1377462258026cac6bd7c32d7e05e895c6..54c53ffc0082e9614f9a0b2f575baca2ba2d509d 100644 (file)
@@ -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)
index 965187f785d7f33fcdffd00248caadae4e4d6fa8..e8008fd34dc126a20d42cf6d77fba6db6f923454 100644 (file)
@@ -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
index 8d6255d48bc7a5b565fb594b21488a7752ea69d3..1505418fb9a14ddb4aadc323685a0f36214264dd 100644 (file)
@@ -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,
index fc15daaf7dc4efb1a5853e0dc76add6e7a11c0b7..a3de6509f5ddc227d279124027ab88af800eaca6 100644 (file)
@@ -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;
index 61497eb4f5083d4ff628ac1c36e9919fd5bf185c..90ad5e2e7b4c477b54117035e067fc16212b4823 100644 (file)
@@ -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)
                    }
                    firsttry = amount;
 
-                   while (VIM_ISWHITE(*that))
+                   init_chartabsize_arg(&cts, curwin, (colnr_T)(that - line),
+                                                          amount, line, that);
+                   while (VIM_ISWHITE(*cts.cts_ptr))
                    {
-                       amount += lbr_chartabsize(line, that, (colnr_T)amount);
-                       ++that;
+                       cts.cts_vcol += lbr_chartabsize(&cts);
+                       ++cts.cts_ptr;
                    }
+                   that = cts.cts_ptr;
+                   amount = cts.cts_vcol;
+                   clear_chartabsize_arg(&cts);
 
                    if (*that && *that != ';') // not a comment line
                    {
@@ -2107,42 +2118,47 @@ 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
-                                   && (!VIM_ISWHITE(*that)
+                           while (*cts.cts_ptr
+                                   && (!VIM_ISWHITE(*cts.cts_ptr)
                                        || quotecount
                                        || parencount)
-                                   && (!((*that == '(' || *that == '[')
+                                   && (!((*cts.cts_ptr == '('
+                                                       || *cts.cts_ptr == '[')
                                            && !quotecount
                                            && !parencount
                                            && vi_lisp)))
                            {
-                               if (*that == '"')
+                               if (*cts.cts_ptr == '"')
                                    quotecount = !quotecount;
-                               if ((*that == '(' || *that == '[')
+                               if ((*cts.cts_ptr == '(' || *cts.cts_ptr == '[')
                                                               && !quotecount)
                                    ++parencount;
-                               if ((*that == ')' || *that == ']')
+                               if ((*cts.cts_ptr == ')' || *cts.cts_ptr == ']')
                                                               && !quotecount)
                                    --parencount;
-                               if (*that == '\\' && *(that+1) != NUL)
-                                   amount += lbr_chartabsize_adv(
-                                               line, &that, (colnr_T)amount);
-                               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);
+                               cts.cts_vcol += lbr_chartabsize_adv(&cts);
                            }
                        }
-                       while (VIM_ISWHITE(*that))
+                       while (VIM_ISWHITE(*cts.cts_ptr))
                        {
-                           amount += lbr_chartabsize(
-                                                line, that, (colnr_T)amount);
-                           that++;
+                           cts.cts_vcol += lbr_chartabsize(&cts);
+                           ++cts.cts_ptr;
                        }
+                       that = cts.cts_ptr;
+                       amount = cts.cts_vcol;
+                       clear_chartabsize_arg(&cts);
+
                        if (!*that || *that == ';')
                            amount = firsttry;
                    }
index 1ab31594135d059dd76a3bc782ea987e0d6914f1..76ac88e8d6c5e6542d6d56b9a113ca3a1098582f 100644 (file)
@@ -397,7 +397,7 @@ plines_win_nofold(win_T *wp, linenr_T lnum)
     s = ml_get_buf(wp->w_buffer, lnum, FALSE);
     if (*s == NUL)             // empty line
        return 1;
-    col = win_linetabsize(wp, s, (colnr_T)MAXCOL);
+    col = win_linetabsize(wp, lnum, s, (colnr_T)MAXCOL);
 
     /*
      * If list mode is on, then the '$' at the end of the line may take up one
@@ -427,10 +427,10 @@ plines_win_nofold(win_T *wp, linenr_T lnum)
 plines_win_col(win_T *wp, linenr_T lnum, long column)
 {
     long       col;
-    char_u     *s;
     int                lines = 0;
     int                width;
     char_u     *line;
+    chartabsize_T cts;
 
 #ifdef FEAT_DIFF
     // Check for filler lines above this buffer line.  When folded the result
@@ -444,25 +444,27 @@ plines_win_col(win_T *wp, linenr_T lnum, long column)
     if (wp->w_width == 0)
        return lines + 1;
 
-    line = s = ml_get_buf(wp->w_buffer, lnum, FALSE);
+    line = ml_get_buf(wp->w_buffer, lnum, FALSE);
 
-    col = 0;
-    while (*s != NUL && --column >= 0)
+    init_chartabsize_arg(&cts, wp, lnum, 0, line, line);
+    while (*cts.cts_ptr != NUL && --column >= 0)
     {
-       col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL);
-       MB_PTR_ADV(s);
+       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
-     * 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 *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_lcs_chars.tab1))
-       col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL) - 1;
+       col += win_lbr_chartabsize(&cts, NULL) - 1;
+    clear_chartabsize_arg(&cts);
 
     /*
      * Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.
index e03ca4936dca608d10a2e519a90a6870214b349d..c5149ff21bc24f773df347b67196907667f71585 100644 (file)
@@ -128,7 +128,6 @@ coladvance2(
 {
     colnr_T    wcol = wcol_arg;
     int                idx;
-    char_u     *ptr;
     char_u     *line;
     colnr_T    col = 0;
     int                csize = 0;
@@ -158,6 +157,7 @@ coladvance2(
     else
     {
        int width = curwin->w_width - win_col_off(curwin);
+       chartabsize_T cts;
 
        if (finetune
                && curwin->w_p_wrap
@@ -180,19 +180,22 @@ coladvance2(
            }
        }
 
-       ptr = line;
-       while (col <= wcol && *ptr != NUL)
+       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)
 #ifdef FEAT_LINEBREAK
-           csize = win_lbr_chartabsize(curwin, line, ptr, col, &head);
-           MB_PTR_ADV(ptr);
+           csize = win_lbr_chartabsize(&cts, &head);
+           MB_PTR_ADV(cts.cts_ptr);
 #else
-           csize = lbr_chartabsize_adv(line, &ptr, col);
+           csize = lbr_chartabsize_adv(&cts);
 #endif
-           col += csize;
+           cts.cts_vcol += csize;
        }
-       idx = (int)(ptr - line);
+       col = cts.cts_vcol;
+       idx = (int)(cts.cts_ptr - 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
index 724b5df1598f567be8085037b7af738dfbf5bec3..e92a73c033a90f77a3127d13ee5cfbf0948cc102 100644 (file)
@@ -3101,18 +3101,20 @@ mouse_find_win(int *rowp, int *colp, mouse_find_T popup UNUSED)
     int
 vcol2col(win_T *wp, linenr_T lnum, int vcol)
 {
-    // try to advance to the specified column
-    int                count = 0;
-    char_u     *ptr;
-    char_u     *line;
+    char_u         *line;
+    chartabsize_T   cts;
 
-    line = ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
-    while (count < vcol && *ptr != NUL)
+    // try to advance to the specified column
+    line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+    init_chartabsize_arg(&cts, wp, lnum, 0, line, line);
+    while (cts.cts_vcol < vcol && *cts.cts_ptr != NUL)
     {
-       count += win_lbr_chartabsize(wp, line, ptr, count, NULL);
-       MB_PTR_ADV(ptr);
+       cts.cts_vcol += win_lbr_chartabsize(&cts, NULL);
+       MB_PTR_ADV(cts.cts_ptr);
     }
-    return (int)(ptr - line);
+    clear_chartabsize_arg(&cts);
+
+    return (int)(cts.cts_ptr - line);
 }
 #endif
 
index fc499543fa0ff3402c1e43069998fca87e1ac2dc..3a7716472b785e30d41c9282bbec230a31e9c5d7 100644 (file)
--- a/src/ops.c
+++ b/src/ops.c
@@ -307,7 +307,8 @@ shift_block(oparg_T *oap, int amount)
 
     if (!left)
     {
-       int     tabs = 0, spaces = 0;
+       int             tabs = 0, spaces = 0;
+       chartabsize_T   cts;
 
        /*
         *  1. Get start vcol
@@ -332,13 +333,20 @@ shift_block(oparg_T *oap, int amount)
            else
                ++bd.textstart;
        }
-       for ( ; VIM_ISWHITE(*bd.textstart); )
+
+       // TODO: is passing bd.textstart for start of the line OK?
+       init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum,
+                                  bd.start_vcol, bd.textstart, bd.textstart);
+       for ( ; VIM_ISWHITE(*cts.cts_ptr); )
        {
-           // TODO: is passing bd.textstart for start of the line OK?
-           incr = lbr_chartabsize_adv(bd.textstart, &bd.textstart, bd.start_vcol);
+           incr = lbr_chartabsize_adv(&cts);
            total += incr;
-           bd.start_vcol += incr;
+           cts.cts_vcol += incr;
        }
+       bd.textstart = 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.
 #ifdef FEAT_VARTABS
@@ -381,6 +389,7 @@ shift_block(oparg_T *oap, int amount)
        size_t      shift_amount;
        char_u      *non_white = bd.textstart;
        colnr_T     non_white_col;
+       chartabsize_T cts;
 
        /*
         * Firstly, let's find the first non-whitespace character that is
@@ -399,11 +408,16 @@ shift_block(oparg_T *oap, int amount)
        // The character's column is in "bd.start_vcol".
        non_white_col = bd.start_vcol;
 
-       while (VIM_ISWHITE(*non_white))
+       init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum,
+                                  non_white_col, bd.textstart, non_white);
+       while (VIM_ISWHITE(*cts.cts_ptr))
        {
-           incr = lbr_chartabsize_adv(bd.textstart, &non_white, non_white_col);
-           non_white_col += incr;
+           incr = lbr_chartabsize_adv(&cts);
+           cts.cts_vcol += incr;
        }
+       non_white_col = cts.cts_vcol;
+       non_white = cts.cts_ptr;
+       clear_chartabsize_arg(&cts);
 
        block_space_width = non_white_col - oap->start_vcol;
        // We will shift by "total" or "block_space_width", whichever is less.
@@ -423,18 +437,19 @@ shift_block(oparg_T *oap, int amount)
        // column number.
        if (bd.startspaces)
            verbatim_copy_width -= bd.start_char_vcols;
-       while (verbatim_copy_width < destination_col)
+       init_chartabsize_arg(&cts, curwin, 0, verbatim_copy_width,
+                                            bd.textstart, verbatim_copy_end);
+       while (cts.cts_vcol < 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)
+           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 = 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
@@ -703,8 +718,6 @@ 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)
-        * Use the register name from before adjust_clip_reg() may have
-        * changed it.
         */
        if (oap->motion_type == MLINE || oap->line_count > 1
                                                           || oap->use_reg_one)
@@ -2213,6 +2226,7 @@ block_prep(
     char_u     *line;
     char_u     *prev_pstart;
     char_u     *prev_pend;
+    chartabsize_T cts;
 #ifdef FEAT_LINEBREAK
     int                lbr_saved = curwin->w_p_lbr;
 
@@ -2232,14 +2246,14 @@ block_prep(
     bdp->start_char_vcols = 0;
 
     line = ml_get(lnum);
-    pstart = line;
     prev_pstart = line;
-    while (bdp->start_vcol < oap->start_vcol && *pstart)
+    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 (VIM_ISWHITE(*pstart))
+       incr = lbr_chartabsize(&cts);
+       cts.cts_vcol += incr;
+       if (VIM_ISWHITE(*cts.cts_ptr))
        {
            bdp->pre_whitesp += incr;
            bdp->pre_whitesp_c++;
@@ -2249,9 +2263,13 @@ block_prep(
            bdp->pre_whitesp = 0;
            bdp->pre_whitesp_c = 0;
        }
-       prev_pstart = pstart;
-       MB_PTR_ADV(pstart);
+       prev_pstart = cts.cts_ptr;
+       MB_PTR_ADV(cts.cts_ptr);
     }
+    bdp->start_vcol = cts.cts_vcol;
+    pstart = cts.cts_ptr;
+    clear_chartabsize_arg(&cts);
+
     bdp->start_char_vcols = incr;
     if (bdp->start_vcol < oap->start_vcol)     // line too short
     {
@@ -2295,14 +2313,20 @@ block_prep(
        }
        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;
+               // count a tab for what it's worth (if list mode not on)
+               prev_pend = cts.cts_ptr;
+               incr = lbr_chartabsize_adv(&cts);
+               cts.cts_vcol += incr;
            }
+           bdp->end_vcol = cts.cts_vcol;
+           pend = cts.cts_ptr;
+           clear_chartabsize_arg(&cts);
+
            if (bdp->end_vcol <= oap->end_vcol
                    && (!is_del
                        || oap->op_type == OP_APPEND
index 78833400df12563d529c25119dbe8dfb99563894..6d12c92f4783832c356aba5d4789b1a07ae52074 100644 (file)
@@ -1371,7 +1371,7 @@ popup_adjust_position(win_T *wp)
        // "margin_width" is added to "len" where it matters.
        if (wp->w_width < maxwidth)
            wp->w_width = maxwidth;
-       len = win_linetabsize(wp, ml_get_buf(wp->w_buffer, lnum, FALSE),
+       len = win_linetabsize(wp, lnum, ml_get_buf(wp->w_buffer, lnum, FALSE),
                                                              (colnr_T)MAXCOL);
        wp->w_width = w_width;
 
index df097109c12ecf19d7c6ffec9cbfff8df9f235a7..97aa71e5c01d9e64d9a58404838f787050b0eb33 100644 (file)
@@ -17,7 +17,7 @@ int vim_strnsize(char_u *s, int len);
 int chartabsize(char_u *p, colnr_T col);
 int linetabsize(char_u *s);
 int linetabsize_col(int startcol, char_u *s);
-int win_linetabsize(win_T *wp, char_u *line, colnr_T len);
+int win_linetabsize(win_T *wp, linenr_T lnum, char_u *line, colnr_T len);
 int vim_isIDc(int c);
 int vim_isNormalIDc(int c);
 int vim_iswordc(int c);
@@ -28,9 +28,11 @@ int vim_isfilec(int c);
 int vim_isfilec_or_wc(int c);
 int vim_isprintc(int c);
 int vim_isprintc_strict(int c);
-int lbr_chartabsize(char_u *line, unsigned char *s, colnr_T col);
-int lbr_chartabsize_adv(char_u *line, char_u **s, colnr_T col);
-int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *headp);
+void init_chartabsize_arg(chartabsize_T *cts, win_T *wp, linenr_T lnum, colnr_T col, char_u *line, char_u *ptr);
+void clear_chartabsize_arg(chartabsize_T *cts);
+int lbr_chartabsize(chartabsize_T *cts);
+int lbr_chartabsize_adv(chartabsize_T *cts);
+int win_lbr_chartabsize(chartabsize_T *cts, int *headp);
 void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end);
 colnr_T getvcol_nolist(pos_T *posp);
 void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end);
index 72a900bfa8ec7d3d9ef5f426ad02ccf55b1d0bb0..4a6bab3083134ec41001a1811766a642cfe3d76b 100644 (file)
@@ -2,7 +2,7 @@
 int find_prop_type_id(char_u *name, buf_T *buf);
 void f_prop_add(typval_T *argvars, typval_T *rettv);
 void f_prop_add_list(typval_T *argvars, typval_T *rettv);
-void prop_add_common(linenr_T start_lnum, colnr_T start_col, dict_T *dict, buf_T *default_buf, typval_T *dict_arg);
+int prop_add_common(linenr_T start_lnum, colnr_T start_col, dict_T *dict, buf_T *default_buf, typval_T *dict_arg);
 int get_text_props(buf_T *buf, linenr_T lnum, char_u **props, int will_change);
 int count_props(linenr_T lnum, int only_starting);
 int find_visible_prop(win_T *wp, int type_id, int id, textprop_T *prop, linenr_T *found_lnum);
index f35a5e8002b111e58e81f4bd12cad85c39967c63..1a5cfd07cbd73a025a3c861b7b88e8d3f69c6071 100644 (file)
@@ -1303,7 +1303,7 @@ reg_match_visual(void)
        rex.line = reg_getline(rex.lnum);
        rex.input = rex.line + col;
 
-       cols = win_linetabsize(wp, rex.line, col);
+       cols = win_linetabsize(wp, rex.reg_firstlnum + rex.lnum, rex.line, col);
        if (cols < start || cols > end - (*p_sel == 'e'))
            return FALSE;
     }
index f8def10fe384b0a15254782683e70a15272c10d1..e7cb1f2ba34116f5fac70623eba1bf44789fdc40 100644 (file)
@@ -3441,7 +3441,9 @@ regmatch(
          case RE_VCOL:
            if (!re_num_cmp((long_u)win_linetabsize(
                            rex.reg_win == NULL ? curwin : rex.reg_win,
-                           rex.line, (colnr_T)(rex.input - rex.line)) + 1, scan))
+                           rex.reg_firstlnum + rex.lnum,
+                           rex.line,
+                           (colnr_T)(rex.input - rex.line)) + 1, scan))
                status = RA_NOMATCH;
            break;
 
index dd5f8edc383ccfe45268ac898958b638e3350348..0dbc6b5019f42d7662162c1b6dac29f93bd24169 100644 (file)
@@ -6775,7 +6775,9 @@ nfa_regmatch(
                    }
                    if (!result)
                        result = nfa_re_num_cmp(t->state->val, op,
-                               (long_u)win_linetabsize(wp, rex.line, col) + 1);
+                               (long_u)win_linetabsize(wp,
+                                               rex.reg_firstlnum + rex.lnum,
+                                               rex.line, col) + 1);
                    if (result)
                    {
                        add_here = TRUE;
index 30e2001da46fe8aa961cc183a74ffbb032da5f97..9a5e11b9ceb1be2bd816a6eed3736c7ee05c9a11 100644 (file)
@@ -1820,8 +1820,9 @@ do_put(
        bd.textcol = 0;
        for (i = 0; i < y_size; ++i)
        {
-           int spaces = 0;
-           char shortline;
+           int             spaces = 0;
+           char            shortline;
+           chartabsize_T   cts;
 
            bd.startspaces = 0;
            bd.endspaces = 0;
@@ -1839,13 +1840,19 @@ do_put(
            // get the old line and advance to the position to insert at
            oldp = ml_get_curline();
            oldlen = (int)STRLEN(oldp);
-           for (ptr = oldp; vcol < col && *ptr; )
+           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 = cts.cts_ptr;
            bd.textcol = (colnr_T)(ptr - oldp);
+           clear_chartabsize_arg(&cts);
 
            shortline = (vcol < col) || (vcol == col && !*ptr) ;
 
@@ -1876,8 +1883,15 @@ do_put(
                // calculate number of spaces required to fill right side of
                // block
                spaces = y_width + 1;
+               init_chartabsize_arg(&cts, curwin, 0, 0,
+                                                     y_array[i], y_array[i]);
                for (j = 0; j < yanklen; j++)
-                   spaces -= lbr_chartabsize(NULL, &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;
            }
index 11c3726f0432dbda5039af83395eefaa6c82c609..1d2aa0a8e28a69282cccd0ae18c3c7b2ed08b744 100644 (file)
@@ -806,8 +806,9 @@ typedef struct textprop_S
     int                tp_flags;       // TP_FLAG_ values
 } textprop_T;
 
-#define TP_FLAG_CONT_NEXT      1       // property continues in next line
-#define TP_FLAG_CONT_PREV      2       // property was continued from prev line
+#define TP_FLAG_CONT_NEXT      0x1     // property continues in next line
+#define TP_FLAG_CONT_PREV      0x2     // property was continued from prev line
+#define TP_VIRTUAL             0x4     // virtual text, uses tp_id
 
 /*
  * Structure defining a property type.
@@ -3074,6 +3075,7 @@ struct file_buffer
 #ifdef FEAT_PROP_POPUP
     int                b_has_textprop; // TRUE when text props were added
     hashtab_T  *b_proptypes;   // text property types local to buffer
+    garray_T   b_textprop_text; // stores text for props, index by (-id - 1)
 #endif
 
 #if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
@@ -4560,3 +4562,18 @@ typedef struct {
     char_u     *str;
     int                score;
 } fuzmatch_str_T;
+
+// Argument for lbr_chartabsize().
+typedef struct {
+    win_T      *cts_win;
+    linenr_T   cts_lnum;           // zero when not using text properties
+    char_u     *cts_line;          // start of the line
+    char_u     *cts_ptr;           // current position in line
+#ifdef FEAT_PROP_POPUP
+    int                cts_text_prop_count;    // number of text props
+    textprop_T *cts_text_props;        // text props (allocated) or NULL
+    char       cts_has_prop_with_text;  // TRUE if if a property inserts text
+    int         cts_cur_text_width;     // width of current inserted text
+#endif
+    int                cts_vcol;           // virtual column at current position
+} chartabsize_T;
diff --git a/src/testdir/dumps/Test_prop_inserts_text.dump b/src/testdir/dumps/Test_prop_inserts_text.dump
new file mode 100644 (file)
index 0000000..f536bd5
--- /dev/null
@@ -0,0 +1,6 @@
+|i+0&#ffffff0|n|s|e|r|t| |s|o|m|e| |t|e|x|t| |S+0#ffffff16#e000002|O|M|E| |h+0#0000000#ffffff0|e|r|e| |a|n|d| |o|t|h|e|r| |t|e|x|t| |O+0&#ffff4012|T|H|E|R| |t+0&#ffffff0|h|e|r|e| |a|n|d| |s|o
+|m|e| |m|o|r|e| |t|e|x|t| |a|f|t|e|r| |M+0&#5fd7ff255|O|R|E| |w+0&#ffffff0|r|a|p@1|i|n|g> @27
+|~+0#4040ff13&| @58
+|~| @58
+|~| @58
+| +0#0000000&@41|1|,|7@1|-|9|3| @6|A|l@1| 
index 1345045e6cddcef0a079e34b7037b60286dca470..66301439008d6da647c505da8d73156de0949724 100644 (file)
@@ -2187,4 +2187,27 @@ func Test_props_do_not_affect_byte_offsets_editline()
   bwipe!
 endfunc
 
+func Test_prop_inserts_text()
+  CheckRunVimInTerminal
+
+  " Just a basic check for now
+  let lines =<< trim END
+      call setline(1, 'insert some text here and other text there and some more text after wrapping')
+      call prop_type_add('someprop', #{highlight: 'ErrorMsg'})
+      call prop_type_add('otherprop', #{highlight: 'Search'})
+      call prop_type_add('moreprop', #{highlight: 'DiffAdd'})
+      call prop_add(1, 18, #{type: 'someprop', text: 'SOME '})
+      call prop_add(1, 38, #{type: 'otherprop', text: 'OTHER '})
+      call prop_add(1, 69, #{type: 'moreprop', text: 'MORE '})
+      redraw
+      normal $
+  END
+  call writefile(lines, 'XscriptPropsWithText')
+  let buf = RunVimInTerminal('-S XscriptPropsWithText', #{rows: 6, cols: 60})
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text', {})
+
+  call StopVimInTerminal(buf)
+  call delete('XscriptPropsWithText')
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
index 5c07195f4f94fea8c74b20a86fc82e64fc7722e2..d7db7aa3e12e40612f24180354e10ce8d6bec8c5 100644 (file)
@@ -150,7 +150,7 @@ get_bufnr_from_arg(typval_T *arg, buf_T **buf)
  * prop_add({lnum}, {col}, {props})
  */
     void
-f_prop_add(typval_T *argvars, typval_T *rettv UNUSED)
+f_prop_add(typval_T *argvars, typval_T *rettv)
 {
     linenr_T   start_lnum;
     colnr_T    start_col;
@@ -174,20 +174,22 @@ f_prop_add(typval_T *argvars, typval_T *rettv UNUSED)
        return;
     }
 
-    prop_add_common(start_lnum, start_col, argvars[2].vval.v_dict,
-                                                         curbuf, &argvars[2]);
+    rettv->vval.v_number = prop_add_common(start_lnum, start_col,
+                                argvars[2].vval.v_dict, curbuf, &argvars[2]);
 }
 
 /*
  * Attach a text property 'type_name' to the text starting
  * at [start_lnum, start_col] and ending at [end_lnum, end_col] in
- * the buffer 'buf' and assign identifier 'id'.
+ * the buffer "buf" and assign identifier "id".
+ * When "text" is not NULL add it to buf->b_textprop_text[-id - 1].
  */
     static int
 prop_add_one(
        buf_T           *buf,
        char_u          *type_name,
        int             id,
+       char_u          *text_arg,
        linenr_T        start_lnum,
        linenr_T        end_lnum,
        colnr_T         start_col,
@@ -202,26 +204,43 @@ prop_add_one(
     char_u     *newtext;
     int                i;
     textprop_T tmp_prop;
+    char_u     *text = text_arg;
+    int                res = FAIL;
 
     type = lookup_prop_type(type_name, buf);
     if (type == NULL)
-       return FAIL;
+       goto theend;
 
     if (start_lnum < 1 || start_lnum > buf->b_ml.ml_line_count)
     {
        semsg(_(e_invalid_line_number_nr), (long)start_lnum);
-       return FAIL;
+       goto theend;
     }
     if (end_lnum < start_lnum || end_lnum > buf->b_ml.ml_line_count)
     {
        semsg(_(e_invalid_line_number_nr), (long)end_lnum);
-       return FAIL;
+       goto theend;
     }
 
     if (buf->b_ml.ml_mfp == NULL)
     {
        emsg(_(e_cannot_add_text_property_to_unloaded_buffer));
-       return FAIL;
+       goto theend;
+    }
+
+    if (text != NULL)
+    {
+       garray_T *gap = &buf->b_textprop_text;
+
+       // double check we got the right ID
+       if (-id - 1 != gap->ga_len)
+           iemsg("text prop ID mismatch");
+       if (gap->ga_growsize == 0)
+           ga_init2(gap, sizeof(char *), 50);
+       if (ga_grow(gap, 1) == FAIL)
+           goto theend;
+       ((char_u **)gap->ga_data)[gap->ga_len++] = text;
+       text = NULL;
     }
 
     for (lnum = start_lnum; lnum <= end_lnum; ++lnum)
@@ -240,7 +259,7 @@ prop_add_one(
        if (col - 1 > (colnr_T)textlen)
        {
            semsg(_(e_invalid_column_number_nr), (long)start_col);
-           return FAIL;
+           goto theend;
        }
 
        if (lnum == end_lnum)
@@ -255,7 +274,7 @@ prop_add_one(
        // Allocate the new line with space for the new property.
        newtext = alloc(buf->b_ml.ml_line_len + sizeof(textprop_T));
        if (newtext == NULL)
-           return FAIL;
+           goto theend;
        // Copy the text, including terminating NUL.
        mch_memmove(newtext, buf->b_ml.ml_line_ptr, textlen);
 
@@ -295,7 +314,11 @@ prop_add_one(
     }
 
     changed_lines_buf(buf, start_lnum, end_lnum + 1, 0);
-    return OK;
+    res = OK;
+
+theend:
+    vim_free(text);
+    return res;
 }
 
 /*
@@ -367,7 +390,7 @@ f_prop_add_list(typval_T *argvars, typval_T *rettv UNUSED)
            emsg(_(e_invalid_argument));
            return;
        }
-       if (prop_add_one(buf, type_name, id, start_lnum, end_lnum,
+       if (prop_add_one(buf, type_name, id, NULL, start_lnum, end_lnum,
                                                start_col, end_col) == FAIL)
            return;
     }
@@ -375,12 +398,23 @@ f_prop_add_list(typval_T *argvars, typval_T *rettv UNUSED)
     redraw_buf_later(buf, VALID);
 }
 
+/*
+ * Get the next ID to use for a textprop with text in buffer "buf".
+ */
+    static int
+get_textprop_id(buf_T *buf)
+{
+    // TODO: recycle deleted entries
+    return -(buf->b_textprop_text.ga_len + 1);
+}
+
 /*
  * Shared between prop_add() and popup_create().
  * "dict_arg" is the function argument of a dict containing "bufnr".
  * it is NULL for popup_create().
+ * Returns the "id" used for "text" or zero.
  */
-    void
+    int
 prop_add_common(
        linenr_T    start_lnum,
        colnr_T     start_col,
@@ -393,11 +427,12 @@ prop_add_common(
     char_u     *type_name;
     buf_T      *buf = default_buf;
     int                id = 0;
+    char_u     *text = NULL;
 
     if (dict == NULL || !dict_has_key(dict, "type"))
     {
        emsg(_(e_missing_property_type_name));
-       return;
+       goto theend;
     }
     type_name = dict_get_string(dict, "type", FALSE);
 
@@ -407,7 +442,7 @@ prop_add_common(
        if (end_lnum < start_lnum)
        {
            semsg(_(e_invalid_value_for_argument_str), "end_lnum");
-           return;
+           goto theend;
        }
     }
     else
@@ -420,7 +455,7 @@ prop_add_common(
        if (length < 0 || end_lnum > start_lnum)
        {
            semsg(_(e_invalid_value_for_argument_str), "length");
-           return;
+           goto theend;
        }
        end_col = start_col + length;
     }
@@ -430,7 +465,7 @@ prop_add_common(
        if (end_col <= 0)
        {
            semsg(_(e_invalid_value_for_argument_str), "end_col");
-           return;
+           goto theend;
        }
     }
     else if (start_lnum == end_lnum)
@@ -441,17 +476,40 @@ prop_add_common(
     if (dict_has_key(dict, "id"))
        id = dict_get_number(dict, "id");
 
+    if (dict_has_key(dict, "text"))
+    {
+       text = dict_get_string(dict, "text", TRUE);
+       if (text == NULL)
+           goto theend;
+       // use a default length of 1 to make multiple props show up
+       end_col = start_col + 1;
+    }
+
     if (dict_arg != NULL && get_bufnr_from_arg(dict_arg, &buf) == FAIL)
-       return;
+       goto theend;
+
+    if (id < 0 && buf->b_textprop_text.ga_len > 0)
+    {
+       emsg(_(e_cannot_use_negative_id_after_adding_textprop_with_text));
+       goto theend;
+    }
+    if (text != NULL)
+       id = get_textprop_id(buf);
 
     // This must be done _before_ we add the property because property changes
     // trigger buffer (memline) reorganisation, which needs this flag to be
     // correctly set.
     buf->b_has_textprop = TRUE;  // this is never reset
 
-    prop_add_one(buf, type_name, id, start_lnum, end_lnum, start_col, end_col);
+    prop_add_one(buf, type_name, id, text,
+                                   start_lnum, end_lnum, start_col, end_col);
+    text = NULL;
 
     redraw_buf_later(buf, VALID);
+
+theend:
+    vim_free(text);
+    return id;
 }
 
 /*
@@ -954,9 +1012,9 @@ get_props_in_line(
        if ((prop_types == NULL
                    || prop_type_or_id_in_list(prop_types, prop_types_len,
                        prop.tp_type))
-               && (prop_ids == NULL ||
-                   prop_type_or_id_in_list(prop_ids, prop_ids_len,
-                       prop.tp_id)))
+               && (prop_ids == NULL
+                   || prop_type_or_id_in_list(prop_ids, prop_ids_len,
+                                                                prop.tp_id)))
        {
            dict_T *d = dict_alloc();
 
index 3b0f70e89e88a1239f12d3e51a758e8a43035fe7..ff2a8ae48d97eba5a5a10061bd665cdc94bfcd64 100644 (file)
@@ -735,6 +735,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    67,
 /**/
     66,
 /**/