diff options
author | Jan Edmund Lazo <jan.lazo@mail.utoronto.ca> | 2020-02-25 00:35:19 -0500 |
---|---|---|
committer | Jan Edmund Lazo <jan.lazo@mail.utoronto.ca> | 2020-03-01 20:02:09 -0500 |
commit | c6481f70c22899604b7707299bb96d0f0768334f (patch) | |
tree | 8a4a771d85ba0412d0520fda224def3e759faae4 | |
parent | 1caa85b677bc287883895558281d23e1fd55817e (diff) | |
download | rneovim-c6481f70c22899604b7707299bb96d0f0768334f.tar.gz rneovim-c6481f70c22899604b7707299bb96d0f0768334f.tar.bz2 rneovim-c6481f70c22899604b7707299bb96d0f0768334f.zip |
vim-patch:8.1.1489: sign order wrong when priority was changed
Problem: Sign order wrong when priority was changed.
Solution: Reorder signs when priority is changed. (Yegappan Lakshmanan,
closes vim/vim#4502)
https://github.com/vim/vim/commit/64416127fc184b5544530afe818722679158f059
-rw-r--r-- | src/nvim/sign.c | 76 | ||||
-rw-r--r-- | src/nvim/testdir/test_signs.vim | 295 |
2 files changed, 371 insertions, 0 deletions
diff --git a/src/nvim/sign.c b/src/nvim/sign.c index e81d09aa4b..baa9c6538f 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -265,6 +265,81 @@ dict_T * sign_get_info(signlist_T *sign) return d; } +// Sort the signs placed on the same line as "sign" by priority. Invoked after +// changing the priority of an already placed sign. Assumes the signs in the +// buffer are sorted by line number and priority. +static void sign_sort_by_prio_on_line(buf_T *buf, signlist_T *sign) + FUNC_ATTR_NONNULL_ALL +{ + // If there is only one sign in the buffer or only one sign on the line or + // the sign is already sorted by priority, then return. + if ((sign->prev == NULL + || sign->prev->lnum != sign->lnum + || sign->prev->priority > sign->priority) + && (sign->next == NULL + || sign->next->lnum != sign->lnum + || sign->next->priority < sign->priority)) { + return; + } + + // One or more signs on the same line as 'sign' + // Find a sign after which 'sign' should be inserted + + // First search backward for a sign with higher priority on the same line + signlist_T *p = sign; + while (p->prev != NULL + && p->prev->lnum == sign->lnum + && p->prev->priority <= sign->priority) { + p = p->prev; + } + if (p == sign) { + // Sign not found. Search forward for a sign with priority just before + // 'sign'. + p = sign->next; + while (p->next != NULL + && p->next->lnum == sign->lnum + && p->next->priority > sign->priority) { + p = p->next; + } + } + + // Remove 'sign' from the list + if (buf->b_signlist == sign) { + buf->b_signlist = sign->next; + } + if (sign->prev != NULL) { + sign->prev->next = sign->next; + } + if (sign->next != NULL) { + sign->next->prev = sign->prev; + } + sign->prev = NULL; + sign->next = NULL; + + // Re-insert 'sign' at the right place + if (p->priority <= sign->priority) { + // 'sign' has a higher priority and should be inserted before 'p' + sign->prev = p->prev; + sign->next = p; + p->prev = sign; + if (sign->prev != NULL) { + sign->prev->next = sign; + } + if (buf->b_signlist == p) { + buf->b_signlist = sign; + } + } else { + // 'sign' has a lower priority and should be inserted after 'p' + sign->prev = p; + sign->next = p->next; + p->next = sign; + if (sign->next != NULL) { + sign->next->prev = sign; + } + } +} + + /// Add the sign into the signlist. Find the right spot to do it though. void buf_addsign( buf_T *buf, // buffer to store sign in @@ -285,6 +360,7 @@ void buf_addsign( // Update an existing sign sign->typenr = typenr; sign->priority = prio; + sign_sort_by_prio_on_line(buf, sign); return; } else if (lnum < sign->lnum) { insert_sign_by_lnum_prio(buf, prev, id, groupname, prio, lnum, typenr); diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim index 806bd4b68b..6af81e15c5 100644 --- a/src/nvim/testdir/test_signs.vim +++ b/src/nvim/testdir/test_signs.vim @@ -1127,6 +1127,301 @@ func Test_sign_priority() \ 'priority' : 10}], \ s[0].signs) + call sign_unplace('*') + + " Three signs on different lines with changing priorities + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 11, 'priority' : 50}) + call sign_place(2, '', 'sign2', 'Xsign', + \ {'lnum' : 12, 'priority' : 60}) + call sign_place(3, '', 'sign3', 'Xsign', + \ {'lnum' : 13, 'priority' : 70}) + call sign_place(2, '', 'sign2', 'Xsign', + \ {'lnum' : 12, 'priority' : 40}) + call sign_place(3, '', 'sign3', 'Xsign', + \ {'lnum' : 13, 'priority' : 30}) + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 11, 'priority' : 50}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 11, 'group' : '', + \ 'priority' : 50}, + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 12, 'group' : '', + \ 'priority' : 40}, + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 13, 'group' : '', + \ 'priority' : 30}], + \ s[0].signs) + + call sign_unplace('*') + + " Two signs on the same line with changing priorities + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + call sign_place(2, '', 'sign2', 'Xsign', + \ {'lnum' : 4, 'priority' : 30}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 30}, + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}], + \ s[0].signs) + " Change the priority of the last sign to highest + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 40}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 40}, + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 30}], + \ s[0].signs) + " Change the priority of the first sign to lowest + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 25}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 30}, + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 25}], + \ s[0].signs) + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 45}) + call sign_place(2, '', 'sign2', 'Xsign', + \ {'lnum' : 4, 'priority' : 55}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 55}, + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 45}], + \ s[0].signs) + + call sign_unplace('*') + + " Three signs on the same line with changing priorities + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 40}) + call sign_place(2, '', 'sign2', 'Xsign', + \ {'lnum' : 4, 'priority' : 30}) + call sign_place(3, '', 'sign3', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 40}, + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 30}, + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}], + \ s[0].signs) + + " Change the priority of the middle sign to the highest + call sign_place(2, '', 'sign2', 'Xsign', + \ {'lnum' : 4, 'priority' : 50}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 50}, + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 40}, + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}], + \ s[0].signs) + + " Change the priority of the middle sign to the lowest + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 15}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 50}, + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 15}], + \ s[0].signs) + + " Change the priority of the last sign to the highest + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 55}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 55}, + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 50}, + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}], + \ s[0].signs) + + " Change the priority of the first sign to the lowest + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 15}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 50}, + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 15}], + \ s[0].signs) + + call sign_unplace('*') + + " Three signs on the same line with changing priorities along with other + " signs + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 2, 'priority' : 10}) + call sign_place(2, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 30}) + call sign_place(3, '', 'sign2', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + call sign_place(4, '', 'sign3', 'Xsign', + \ {'lnum' : 4, 'priority' : 25}) + call sign_place(5, '', 'sign2', 'Xsign', + \ {'lnum' : 6, 'priority' : 80}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 2, 'group' : '', + \ 'priority' : 10}, + \ {'id' : 2, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 30}, + \ {'id' : 4, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 25}, + \ {'id' : 3, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 5, 'name' : 'sign2', 'lnum' : 6, 'group' : '', + \ 'priority' : 80}], + \ s[0].signs) + + " Change the priority of the first sign to lowest + call sign_place(2, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 15}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 2, 'group' : '', + \ 'priority' : 10}, + \ {'id' : 4, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 25}, + \ {'id' : 3, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 2, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 15}, + \ {'id' : 5, 'name' : 'sign2', 'lnum' : 6, 'group' : '', + \ 'priority' : 80}], + \ s[0].signs) + + " Change the priority of the last sign to highest + call sign_place(2, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 30}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 2, 'group' : '', + \ 'priority' : 10}, + \ {'id' : 2, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 30}, + \ {'id' : 4, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 25}, + \ {'id' : 3, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 5, 'name' : 'sign2', 'lnum' : 6, 'group' : '', + \ 'priority' : 80}], + \ s[0].signs) + + " Change the priority of the middle sign to lowest + call sign_place(4, '', 'sign3', 'Xsign', + \ {'lnum' : 4, 'priority' : 15}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 2, 'group' : '', + \ 'priority' : 10}, + \ {'id' : 2, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 30}, + \ {'id' : 3, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 4, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 15}, + \ {'id' : 5, 'name' : 'sign2', 'lnum' : 6, 'group' : '', + \ 'priority' : 80}], + \ s[0].signs) + + " Change the priority of the middle sign to highest + call sign_place(3, '', 'sign2', 'Xsign', + \ {'lnum' : 4, 'priority' : 35}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 2, 'group' : '', + \ 'priority' : 10}, + \ {'id' : 3, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 35}, + \ {'id' : 2, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 30}, + \ {'id' : 4, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 15}, + \ {'id' : 5, 'name' : 'sign2', 'lnum' : 6, 'group' : '', + \ 'priority' : 80}], + \ s[0].signs) + + call sign_unplace('*') + + " Multiple signs with the same priority on the same line + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + call sign_place(2, '', 'sign2', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + call sign_place(3, '', 'sign3', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}], + \ s[0].signs) + " Place the last sign again with the same priority + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}], + \ s[0].signs) + " Place the first sign again with the same priority + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}], + \ s[0].signs) + " Place the middle sign again with the same priority + call sign_place(3, '', 'sign3', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}], + \ s[0].signs) + + call sign_unplace('*') + " Place multiple signs with same id on a line with different priority call sign_place(1, '', 'sign1', 'Xsign', \ {'lnum' : 5, 'priority' : 20}) |