summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-09-29 13:50:08 +0100
committerBram Moolenaar <Bram@vim.org>2022-09-29 13:50:08 +0100
commit9f573a8df02d9f699a43d2afbd1d2841d700b9ad (patch)
tree8b68307515d0dce34622ef379b11c166a6f2f7d3
parentfc06cda8379031890ee8852cdca61eb8af8e1ba2 (diff)
downloadvim-git-9.0.0622.tar.gz
patch 9.0.0622: matchaddpos() can get slow when adding many matchesv9.0.0622
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)
-rw-r--r--runtime/doc/builtin.txt2
-rw-r--r--src/match.c32
-rw-r--r--src/testdir/test_match.vim14
-rw-r--r--src/version.c2
-rw-r--r--src/window.c3
5 files changed, 26 insertions, 27 deletions
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 81758aff4..e5740a587 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -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
diff --git a/src/match.c b/src/match.c
index ecab28cef..ceb317c38 100644
--- a/src/match.c
+++ b/src/match.c
@@ -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)
diff --git a/src/testdir/test_match.vim b/src/testdir/test_match.vim
index 91e78a768..8be5bc080 100644
--- a/src/testdir/test_match.vim
+++ b/src/testdir/test_match.vim
@@ -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)
diff --git a/src/version.c b/src/version.c
index eedf11097..95042e8c1 100644
--- a/src/version.c
+++ b/src/version.c
@@ -700,6 +700,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 622,
+/**/
621,
/**/
620,
diff --git a/src/window.c b/src/window.c
index d4580e474..f4e975012 100644
--- a/src/window.c
+++ b/src/window.c
@@ -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;
}