]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.0233: removing multiple text properties takes many calls v9.0.0233
authorBen Jackson <puremourning@gmail.com>
Sat, 20 Aug 2022 19:54:51 +0000 (20:54 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 20 Aug 2022 19:54:51 +0000 (20:54 +0100)
Problem:    Removing multiple text properties takes many calls.
Solution:   Pass a list to prop_remove(). (Ben Jackson, closes #10945)

src/errors.h
src/testdir/test_textprop.vim
src/textprop.c
src/version.c

index bc1145db8c2780cc9180b869c74966b3a6c0a683..716ec32d8eb791996531057602265844d8eb0ce4 100644 (file)
@@ -2208,8 +2208,8 @@ EXTERN char e_failed_to_convert_returned_python_object_to_vim_value[]
        INIT(= N_("E859: Failed to convert returned python object to a Vim value"));
 #endif
 #ifdef FEAT_PROP_POPUP
-EXTERN char e_need_id_and_type_with_both[]
-       INIT(= N_("E860: Need 'id' and 'type' with 'both'"));
+EXTERN char e_need_id_and_type_or_types_with_both[]
+       INIT(= N_("E860: Need 'id' and 'type' or 'types' with 'both'"));
 # ifdef FEAT_TERMINAL
 EXTERN char e_cannot_open_second_popup_with_terminal[]
        INIT(= N_("E861: Cannot open a second popup with a terminal"));
@@ -3316,3 +3316,7 @@ EXTERN char e_cannot_use_negative_id_after_adding_textprop_with_text[]
 EXTERN char e_can_only_use_text_align_when_column_is_zero[]
        INIT(= N_("E1294: Can only use text_align when column is zero"));
 #endif
+#ifdef FEAT_PROP_POPUP
+EXTERN char e_cannot_specify_both_type_and_types[]
+       INIT(= N_("E1295: Cannot specify both 'type' and 'types'"));
+#endif
index 496e73836ef11cedd79ea91672820cb79e8d803f..a7646209e8e7736187a273f84996d1403a84b6b9 100644 (file)
@@ -161,7 +161,7 @@ func Test_prop_find()
     \ ]
 
   " Starting at line 5 col 1 this should find the prop at line 5 col 4.
-  call cursor(5,1)
+  call cursor(5, 1)
   let result = prop_find({'type': 'prop_name'}, 'f')
   call assert_equal(expected[2], result)
 
@@ -182,7 +182,7 @@ func Test_prop_find()
   " with skipstart set to false, if the start position is anywhere between the
   " start and end lines of a text prop (searching forward or backward), the
   " result should be the prop on the first line (the line with 'start' set to 1).
-  call cursor(3,1)
+  call cursor(3, 1)
   let result = prop_find({'type': 'prop_name'}, 'f')
   unlet result.length
   call assert_equal(expected[1], result)
@@ -230,12 +230,12 @@ func Test_prop_find()
   endwhile
 
   " Starting from line 6 col 1 search backwards for prop with id 10.
-  call cursor(6,1)
+  call cursor(6, 1)
   let result = prop_find({'id': 10, 'skipstart': 1}, 'b')
   call assert_equal(expected[0], result)
 
   " Starting from line 1 col 1 search forwards for prop with id 12.
-  call cursor(1,1)
+  call cursor(1, 1)
   let result = prop_find({'id': 12}, 'f')
   call assert_equal(expected[2], result)
 
@@ -426,6 +426,37 @@ func Test_prop_remove()
 
   call DeletePropTypes()
   bwipe!
+
+  new
+  call AddPropTypes()
+  call SetupPropsInFirstLine()
+  let props = Get_expected_props() " [whole, one, two, three]
+  call assert_equal(props, prop_list(1))
+
+  " remove one by types
+  call assert_equal(1, prop_remove({'types': ['one', 'two', 'three']}, 1))
+  unlet props[1] " [whole, two, three]
+  call assert_equal(props, prop_list(1))
+
+  " remove 'all' by types
+  call assert_equal(2, prop_remove({'types': ['three', 'whole'], 'all': 1}, 1))
+  unlet props[0] " [two, three]
+  unlet props[1] " [three]
+  call assert_equal(props, prop_list(1))
+
+  " remove none by types
+  call assert_equal(0, prop_remove({'types': ['three', 'whole'], 'all': 1}, 1))
+  call assert_equal(props, prop_list(1))
+
+  " no types
+  call assert_fails("call prop_remove({'types': []}, 1)", 'E968:')
+  call assert_fails("call prop_remove({'types': ['not_a_real_type']}, 1)", 'E971:')
+
+  " only one of types and type can be supplied
+  call assert_fails("call prop_remove({'type': 'one', 'types': ['three'], 'all': 1}, 1)", 'E1295:')
+
+  call DeletePropTypes()
+  bwipe!
 endfunc
 
 def Test_prop_add_vim9()
@@ -1396,7 +1427,7 @@ endfunc
 func Test_textprop_invalid_highlight()
   call assert_fails("call prop_type_add('dni', {'highlight': 'DoesNotExist'})", 'E970:')
   new
-  call setline(1, ['asdf','asdf'])
+  call setline(1, ['asdf', 'asdf'])
   call prop_add(1, 1, {'length': 4, 'type': 'dni'})
   redraw
   bwipe!
@@ -2207,7 +2238,7 @@ func Test_prop_find_prev_on_same_line()
     call prop_add(1, col, #{type: 'misspell', length: 2})
   endfor
 
-  call cursor(1,18)
+  call cursor(1, 18)
   let expected = [
     \ #{lnum: 1, id: 0, col: 14, end: 1, type: 'misspell', type_bufnr: 0, length: 2, start: 1},
     \ #{lnum: 1, id: 0, col: 24, end: 1, type: 'misspell', type_bufnr: 0, length: 2, start: 1}
@@ -2310,7 +2341,7 @@ func Test_prop_insert_multiline()
   call assert_equal(lines, getline(1, '$'))
   let expected = [
       \ {'lnum': 1, 'id': 0, 'col': 4, 'type_bufnr': 0, 'end': 0, 'type': 'one',
-      \ 'length': 4 ,'start': 1},
+      \ 'length': 4 , 'start': 1},
       \ {'lnum': 2, 'id': 0, 'col': 1, 'type_bufnr': 0, 'end': 0, 'type': 'one',
       \ 'length': 7, 'start': 0},
       \ {'lnum': 3, 'id': 0, 'col': 1, 'type_bufnr': 0, 'end': 0, 'type': 'one',
index d90d57fac36a95d487291cf395eed3e209e9d0cc..2fb8a531223776a1dbdfd65cd2088501f01224e8 100644 (file)
@@ -1010,7 +1010,7 @@ f_prop_find(typval_T *argvars, typval_T *rettv)
     }
     if (both && (!id_found || type_id == -1))
     {
-       emsg(_(e_need_id_and_type_with_both));
+       emsg(_(e_need_id_and_type_or_types_with_both));
        return;
     }
 
@@ -1378,7 +1378,9 @@ f_prop_remove(typval_T *argvars, typval_T *rettv)
     buf_T      *buf = curbuf;
     int                do_all;
     int                id = -MAXCOL;
-    int                type_id = -1;
+    int                type_id = -1;       // for a single "type"
+    int                *type_ids = NULL;   // array, for a list of "types", allocated
+    int                num_type_ids = 0;   // number of elements in "type_ids"
     int                both;
     int                did_remove_text = FALSE;
 
@@ -1420,6 +1422,9 @@ f_prop_remove(typval_T *argvars, typval_T *rettv)
 
     if (dict_has_key(dict, "id"))
        id = dict_get_number(dict, "id");
+
+    // if a specific type was supplied "type": check that (and ignore "types".
+    // Otherwise check against the list of "types".
     if (dict_has_key(dict, "type"))
     {
        char_u      *name = dict_get_string(dict, "type", FALSE);
@@ -1429,17 +1434,48 @@ f_prop_remove(typval_T *argvars, typval_T *rettv)
            return;
        type_id = type->pt_id;
     }
+    if (dict_has_key(dict, "types"))
+    {
+       typval_T types;
+       listitem_T *li = NULL;
+
+       dict_get_tv(dict, "types", &types);
+       if (types.v_type == VAR_LIST && types.vval.v_list->lv_len > 0)
+       {
+           type_ids = alloc( sizeof(int) * types.vval.v_list->lv_len );
+
+           FOR_ALL_LIST_ITEMS(types.vval.v_list, li)
+           {
+               proptype_T *prop_type;
+
+               if (li->li_tv.v_type != VAR_STRING)
+                   continue;
+
+               prop_type = lookup_prop_type(li->li_tv.vval.v_string, buf);
+
+               if (!prop_type)
+                   goto cleanup_prop_remove;
+
+               type_ids[num_type_ids++] = prop_type->pt_id;
+           }
+       }
+    }
     both = dict_get_bool(dict, "both", FALSE);
 
-    if (id == -MAXCOL && type_id == -1)
+    if (id == -MAXCOL && (type_id == -1 && num_type_ids == 0))
     {
        emsg(_(e_need_at_least_one_of_id_or_type));
-       return;
+       goto cleanup_prop_remove;
     }
-    if (both && (id == -MAXCOL || type_id == -1))
+    if (both && (id == -MAXCOL || (type_id == -1 && num_type_ids == 0)))
     {
-       emsg(_(e_need_id_and_type_with_both));
-       return;
+       emsg(_(e_need_id_and_type_or_types_with_both));
+       goto cleanup_prop_remove;
+    }
+    if (type_id != -1 && num_type_ids > 0)
+    {
+       emsg(_(e_cannot_specify_both_type_and_types));
+       goto cleanup_prop_remove;
     }
 
     if (end == 0)
@@ -1464,10 +1500,26 @@ f_prop_remove(typval_T *argvars, typval_T *rettv)
                char_u *cur_prop = buf->b_ml.ml_line_ptr + len
                                                    + idx * sizeof(textprop_T);
                size_t  taillen;
+               int matches_id = 0;
+               int matches_type = 0;
 
                mch_memmove(&textprop, cur_prop, sizeof(textprop_T));
-               if (both ? textprop.tp_id == id && textprop.tp_type == type_id
-                        : textprop.tp_id == id || textprop.tp_type == type_id)
+
+               matches_id = textprop.tp_id == id;
+               if (num_type_ids > 0)
+               {
+                   int idx2;
+
+                   for (idx2 = 0; !matches_type && idx2 < num_type_ids; ++idx2)
+                       matches_type = textprop.tp_type == type_ids[idx2];
+               }
+               else
+               {
+                   matches_type = textprop.tp_type == type_id;
+               }
+
+               if (both ? matches_id && matches_type
+                        : matches_id || matches_type)
                {
                    if (!(buf->b_ml.ml_flags & ML_LINE_DIRTY))
                    {
@@ -1475,7 +1527,7 @@ f_prop_remove(typval_T *argvars, typval_T *rettv)
 
                        // need to allocate the line to be able to change it
                        if (newptr == NULL)
-                           return;
+                           goto cleanup_prop_remove;
                        mch_memmove(newptr, buf->b_ml.ml_line_ptr,
                                                        buf->b_ml.ml_line_len);
                        if (buf->b_ml.ml_flags & ML_ALLOCATED)
@@ -1537,6 +1589,9 @@ f_prop_remove(typval_T *argvars, typval_T *rettv)
                         && ((char_u **)gap->ga_data)[gap->ga_len - 1] == NULL)
            --gap->ga_len;
     }
+
+cleanup_prop_remove:
+    vim_free(type_ids);
 }
 
 /*
index 0943fc14e21594c20f6b4d9f28726c42ac02af91..92b55eecbcb65179a6660a5fefbd3941bc5705d7 100644 (file)
@@ -731,6 +731,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    233,
 /**/
     232,
 /**/