aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Vigouroux <tomvig38@gmail.com>2020-11-23 12:25:36 +0100
committerThomas Vigouroux <tomvig38@gmail.com>2020-11-25 10:10:05 +0100
commitc0a6989d93d35811411155e43f37b2fc4658719e (patch)
tree973e033815651f0630099bada4ebb16278d6c0ae
parent43ec616414c7f17585e8b4a7e34acaaedfff5121 (diff)
downloadrneovim-c0a6989d93d35811411155e43f37b2fc4658719e.tar.gz
rneovim-c0a6989d93d35811411155e43f37b2fc4658719e.tar.bz2
rneovim-c0a6989d93d35811411155e43f37b2fc4658719e.zip
feat(luahl): add priority mechanism
Base priority is 0x1000, in order to stay kinda backward compatible. Also set tree-sitter default highlight to 100 (middle-ish value)
-rw-r--r--runtime/lua/vim/treesitter/highlighter.lua3
-rw-r--r--src/nvim/api/buffer.c19
-rw-r--r--src/nvim/decoration.c53
-rw-r--r--src/nvim/decoration.h5
-rw-r--r--test/functional/ui/bufhl_spec.lua60
5 files changed, 125 insertions, 15 deletions
diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
index 60db7f24cf..275e960e28 100644
--- a/runtime/lua/vim/treesitter/highlighter.lua
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -219,7 +219,8 @@ local function on_line_impl(self, buf, line)
a.nvim_buf_set_extmark(buf, ns, start_row, start_col,
{ end_line = end_row, end_col = end_col,
hl_group = hl,
- ephemeral = true
+ ephemeral = true,
+ priority = 100 -- Low but leaves room below
})
end
if start_row > line then
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 4fc0ee4fdf..1011f050fd 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -1122,6 +1122,8 @@ static Array extmark_to_array(ExtmarkInfo extmark, bool id, bool add_dict)
}
PUT(dict, "virt_text", ARRAY_OBJ(chunks));
}
+
+ PUT(dict, "priority", INTEGER_OBJ(decor->priority));
}
if (dict.size) {
@@ -1375,6 +1377,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
uint64_t id = 0;
int line2 = -1, hl_id = 0;
+ DecorPriority priority = DECOR_PRIORITY_BASE;
colnr_T col2 = 0;
VirtText virt_text = KV_INITIAL_VALUE;
for (size_t i = 0; i < opts.size; i++) {
@@ -1446,6 +1449,19 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
if (ERROR_SET(err)) {
goto error;
}
+ } else if (strequal("priority", k.data)) {
+ if (v->type != kObjectTypeInteger) {
+ api_set_error(err, kErrorTypeValidation,
+ "priority is not a Number of the correct size");
+ goto error;
+ }
+
+ if (v->data.integer < 0 || v->data.integer > UINT16_MAX) {
+ api_set_error(err, kErrorTypeValidation,
+ "priority is not a valid value");
+ goto error;
+ }
+ priority = (DecorPriority)v->data.integer;
} else {
api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
goto error;
@@ -1479,7 +1495,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
*vt_allocated = virt_text;
}
decor_add_ephemeral(attr_id, (int)line, (colnr_T)col,
- (int)line2, (colnr_T)col2, vt_allocated);
+ (int)line2, (colnr_T)col2, priority, vt_allocated);
} else {
if (ephemeral) {
api_set_error(err, kErrorTypeException, "not yet implemented");
@@ -1492,6 +1508,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
decor->virt_text = virt_text;
} else if (hl_id) {
decor = decor_hl(hl_id);
+ decor->priority = priority;
}
id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col,
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index 03ce2a37b5..e6a616c927 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -43,6 +43,7 @@ void bufhl_add_hl_pos_offset(buf_T *buf,
colnr_T hl_end = 0;
Decoration *decor = decor_hl(hl_id);
+ decor->priority = DECOR_PRIORITY_BASE;
// TODO(bfredl): if decoration had blocky mode, we could avoid this loop
for (linenr_T lnum = pos_start.lnum; lnum <= pos_end.lnum; lnum ++) {
int end_off = 0;
@@ -84,6 +85,7 @@ Decoration *decor_hl(int hl_id)
Decoration *decor = xcalloc(1, sizeof(*decor));
decor->hl_id = hl_id;
decor->shared = true;
+ decor->priority = DECOR_PRIORITY_BASE;
*dp = decor;
return decor;
}
@@ -191,12 +193,12 @@ bool decor_redraw_start(buf_T *buf, int top_row, DecorState *state)
HlRange range;
if (mark.id&MARKTREE_END_FLAG) {
range = (HlRange){ altpos.row, altpos.col, mark.row, mark.col,
- attr_id, vt, false };
+ attr_id, decor->priority, vt, false };
} else {
range = (HlRange){ mark.row, mark.col, altpos.row,
- altpos.col, attr_id, vt, false };
+ altpos.col, attr_id, decor->priority, vt, false };
}
- kv_push(state->active, range);
+ hlrange_activate(range, state);
next_mark:
if (marktree_itr_node_done(state->itr)) {
@@ -218,6 +220,34 @@ bool decor_redraw_line(buf_T *buf, int row, DecorState *state)
return true; // TODO(bfredl): be more precise
}
+static void hlrange_activate(HlRange range, DecorState *state)
+{
+ // Get size before preparing the push, to have the number of elements
+ size_t s = kv_size(state->active);
+
+ kv_pushp(state->active);
+
+ size_t dest_index = 0;
+
+ // Determine insertion dest_index
+ while (dest_index < s) {
+ HlRange item = kv_A(state->active, dest_index);
+ if (item.priority > range.priority) {
+ break;
+ }
+
+ dest_index++;
+ }
+
+ // Splice
+ for (size_t index = s; index > dest_index; index--) {
+ kv_A(state->active, index) = kv_A(state->active, index-1);
+ }
+
+ // Insert
+ kv_A(state->active, dest_index) = range;
+}
+
int decor_redraw_col(buf_T *buf, int col, DecorState *state)
{
if (col <= state->col_until) {
@@ -257,9 +287,10 @@ int decor_redraw_col(buf_T *buf, int col, DecorState *state)
int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0;
VirtText *vt = kv_size(decor->virt_text) ? &decor->virt_text : NULL;
- kv_push(state->active, ((HlRange){ mark.row, mark.col,
- endpos.row, endpos.col,
- attr_id, vt, false }));
+ hlrange_activate((HlRange){ mark.row, mark.col,
+ endpos.row, endpos.col,
+ attr_id, decor->priority,
+ vt, false }, state);
next_mark:
marktree_itr_next(buf->b_marktree, state->itr);
@@ -321,10 +352,10 @@ VirtText *decor_redraw_virt_text(buf_T *buf, DecorState *state)
}
void decor_add_ephemeral(int attr_id, int start_row, int start_col,
- int end_row, int end_col, VirtText *virt_text)
+ int end_row, int end_col, DecorPriority priority,
+ VirtText *virt_text)
{
- kv_push(decor_state.active,
- ((HlRange){ start_row, start_col,
- end_row, end_col,
- attr_id, virt_text, virt_text != NULL }));
+hlrange_activate(((HlRange){ start_row, start_col, end_row, end_col, attr_id,
+ priority, virt_text, virt_text != NULL }),
+ &decor_state);
}
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index c5941ae2fe..2533a641dd 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -15,11 +15,15 @@ typedef struct {
typedef kvec_t(VirtTextChunk) VirtText;
#define VIRTTEXT_EMPTY ((VirtText)KV_INITIAL_VALUE)
+typedef uint16_t DecorPriority;
+#define DECOR_PRIORITY_BASE 0x1000
+
struct Decoration
{
int hl_id; // highlight group
VirtText virt_text;
// TODO(bfredl): style, signs, etc
+ DecorPriority priority;
bool shared; // shared decoration, don't free
};
@@ -29,6 +33,7 @@ typedef struct {
int end_row;
int end_col;
int attr_id;
+ DecorPriority priority;
VirtText *virt_text;
bool virt_text_owned;
} HlRange;
diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua
index d7269d2c29..af709cd521 100644
--- a/test/functional/ui/bufhl_spec.lua
+++ b/test/functional/ui/bufhl_spec.lua
@@ -534,6 +534,62 @@ describe('Buffer highlighting', function()
]]}
end)
+ it('respects priority', function()
+ local set_extmark = curbufmeths.set_extmark
+ local id = meths.create_namespace('')
+ insert [[foobar]]
+
+ set_extmark(id, 0, 0, {
+ end_line = 0,
+ end_col = 5,
+ hl_group = "Statement",
+ priority = 100
+ })
+ set_extmark(id, 0, 0, {
+ end_line = 0,
+ end_col = 6,
+ hl_group = "String",
+ priority = 1
+ })
+
+ screen:expect [[
+ {3:fooba}{2:^r} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]
+
+ clear_namespace(id, 0, -1)
+
+ set_extmark(id, 0, 0, {
+ end_line = 0,
+ end_col = 6,
+ hl_group = "String",
+ priority = 1
+ })
+ set_extmark(id, 0, 0, {
+ end_line = 0,
+ end_col = 5,
+ hl_group = "Statement",
+ priority = 100
+ })
+
+ screen:expect [[
+ {3:fooba}{2:^r} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]
+ end)
+
it('works with multibyte text', function()
insert([[
Ta båten över sjön!]])
@@ -699,12 +755,12 @@ describe('Buffer highlighting', function()
-- TODO: only a virtual text from the same ns curretly overrides
-- an existing virtual text. We might add a prioritation system.
set_virtual_text(id1, 0, s1, {})
- eq({{1, 0, 0, {virt_text = s1}}}, get_extmarks(id1, {0,0}, {0, -1}, {details=true}))
+ eq({{1, 0, 0, { priority = 0, virt_text = s1}}}, get_extmarks(id1, {0,0}, {0, -1}, {details=true}))
-- TODO: is this really valid? shouldn't the max be line_count()-1?
local lastline = line_count()
set_virtual_text(id1, line_count(), s2, {})
- eq({{3, lastline, 0, {virt_text = s2}}}, get_extmarks(id1, {lastline,0}, {lastline, -1}, {details=true}))
+ eq({{3, lastline, 0, { priority = 0, virt_text = s2}}}, get_extmarks(id1, {lastline,0}, {lastline, -1}, {details=true}))
eq({}, get_extmarks(id1, {lastline+9000,0}, {lastline+9000, -1}, {}))
end)