]> granicus.if.org Git - vim/commitdiff
patch 9.0.0622: matchaddpos() can get slow when adding many matches v9.0.0622
authorBram Moolenaar <Bram@vim.org>
Thu, 29 Sep 2022 12:50:08 +0000 (13:50 +0100)
committerBram Moolenaar <Bram@vim.org>
Thu, 29 Sep 2022 12:50:08 +0000 (13:50 +0100)
Problem:    matchaddpos() can get slow when adding many matches.
Solution:   Update the next available match ID when manually picking an ID and
            remove check if the available ID can be used. (idea by Rick Howe)

runtime/doc/builtin.txt
src/match.c
src/testdir/test_match.vim
src/version.c
src/window.c

index 81758aff4e60cd39a781683aafa5adc8925378af..e5740a587aa59729ae1b91ac6e7073e6231e4097 100644 (file)
@@ -5864,7 +5864,7 @@ matchadd({group}, {pattern} [, {priority} [, {id} [, {dict}]]])
                respectively.  3 is reserved for use by the |matchparen|
                plugin.
                If the {id} argument is not specified or -1, |matchadd()|
-               automatically chooses a free ID.
+               automatically chooses a free ID, which is at least 1000.
 
                The optional {dict} argument allows for further custom
                values. Currently this is used to specify a match specific
index ecab28cef38645b0da311332c565871f77628eab..ceb317c381e9a4694efa93ba4792097ee724af20 100644 (file)
@@ -50,19 +50,28 @@ match_add(
        semsg(_(e_invalid_id_nr_must_be_greater_than_or_equal_to_one_1), id);
        return -1;
     }
-    if (id != -1)
+    if (id == -1)
     {
-       cur = wp->w_match_head;
-       while (cur != NULL)
-       {
+       // use the next available match ID
+       id = wp->w_next_match_id++;
+    }
+    else
+    {
+       // check the given ID is not already in use
+       for (cur = wp->w_match_head; cur != NULL; cur = cur->mit_next)
            if (cur->mit_id == id)
            {
                semsg(_(e_id_already_taken_nr), id);
                return -1;
            }
-           cur = cur->mit_next;
-       }
+
+       // Make sure the next match ID is always higher than the highest
+       // manually selected ID.  Add some extra in case a few more IDs are
+       // added soon.
+       if (wp->w_next_match_id < id + 100)
+           wp->w_next_match_id = id + 100;
     }
+
     if ((hlg_id = syn_namen2id(grp, (int)STRLEN(grp))) == 0)
     {
        semsg(_(e_no_such_highlight_group_name_str), grp);
@@ -74,17 +83,6 @@ match_add(
        return -1;
     }
 
-    // Find available match ID.
-    while (id == -1)
-    {
-       cur = wp->w_match_head;
-       while (cur != NULL && cur->mit_id != wp->w_next_match_id)
-           cur = cur->mit_next;
-       if (cur == NULL)
-           id = wp->w_next_match_id;
-       wp->w_next_match_id++;
-    }
-
     // Build new match.
     m = ALLOC_CLEAR_ONE(matchitem_T);
     if (m == NULL)
index 91e78a76827f92073a453945ae5085c14fa7384c..8be5bc0802c91ce4b28dd3f7255bc7d508289617 100644 (file)
@@ -36,8 +36,8 @@ function Test_match()
   let m1 = matchadd("MyGroup1", "TODO")
   let m2 = matchadd("MyGroup2", "FIXME", 42)
   let m3 = matchadd("MyGroup3", "XXX", 60, 17)
-  let ans = [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 4},
-        \    {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 42, 'id': 5},
+  let ans = [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1000},
+        \    {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 42, 'id': 1001},
         \    {'group': 'MyGroup3', 'pattern': 'XXX', 'priority': 60, 'id': 17}]
   call assert_equal(ans, getmatches())
 
@@ -119,7 +119,7 @@ function Test_match()
   call clearmatches()
 
   call setline(1, 'abcdΣabcdef')
-  eval "MyGroup1"->matchaddpos([[1, 4, 2], [1, 9, 2]])
+  eval "MyGroup1"->matchaddpos([[1, 4, 2], [1, 9, 2]], 10, 42)
   1
   redraw!
   let v1 = screenattr(1, 1)
@@ -130,7 +130,7 @@ function Test_match()
   let v8 = screenattr(1, 8)
   let v9 = screenattr(1, 9)
   let v10 = screenattr(1, 10)
-  call assert_equal([{'group': 'MyGroup1', 'id': 11, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1, 9, 2]}], getmatches())
+  call assert_equal([{'group': 'MyGroup1', 'id': 42, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1, 9, 2]}], getmatches())
   call assert_notequal(v1, v4)
   call assert_equal(v5, v4)
   call assert_equal(v6, v1)
@@ -144,7 +144,7 @@ function Test_match()
   let m=getmatches()
   call clearmatches()
   call setmatches(m)
-  call assert_equal([{'group': 'MyGroup1', 'id': 11, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1,9, 2]}, {'group': 'MyGroup1', 'pattern': '\%2lmatchadd', 'priority': 10, 'id': 12}], getmatches())
+  call assert_equal([{'group': 'MyGroup1', 'id': 42, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1,9, 2]}, {'group': 'MyGroup1', 'pattern': '\%2lmatchadd', 'priority': 10, 'id': 1106}], getmatches())
 
   highlight MyGroup1 NONE
   highlight MyGroup2 NONE
@@ -252,8 +252,8 @@ func Test_matchaddpos_otherwin()
 
   let savematches = getmatches(winid)
   let expect = [
-        \ {'group': 'Search', 'pattern': '4', 'priority': 10, 'id': 4},
-        \ {'group': 'Error', 'id': 5, 'priority': 10, 'pos1': [1, 2, 1], 'pos2': [2, 2, 1]},
+        \ {'group': 'Search', 'pattern': '4', 'priority': 10, 'id': 1000},
+        \ {'group': 'Error', 'id': 1001, 'priority': 10, 'pos1': [1, 2, 1], 'pos2': [2, 2, 1]},
         \]
   call assert_equal(expect, savematches)
 
index eedf110975368f201db7550ab97e6c982b4fa687..95042e8c1f7973f69e920df50bbeda9d0e8ed1d8 100644 (file)
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    622,
 /**/
     621,
 /**/
index d4580e474d6497a3f041a8101f5a1bcbe4186b37..f4e975012d82d85f90aa6d76240ba4fa1a63ce2f 100644 (file)
@@ -5143,8 +5143,7 @@ win_alloc(win_T *after UNUSED, int hidden UNUSED)
 #endif
     unblock_autocmds();
 #ifdef FEAT_SEARCH_EXTRA
-    new_wp->w_match_head = NULL;
-    new_wp->w_next_match_id = 4;
+    new_wp->w_next_match_id = 1000;  // up to 1000 can be picked by the user
 #endif
     return new_wp;
 }