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)
64416127fc
This commit is contained in:
Jan Edmund Lazo 2020-02-25 00:35:19 -05:00
parent 1caa85b677
commit c6481f70c2
No known key found for this signature in database
GPG Key ID: 64915E6E9F735B15
2 changed files with 371 additions and 0 deletions

View File

@ -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);

View File

@ -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})