aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/sign.c76
-rw-r--r--src/nvim/testdir/test_signs.vim295
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})