diff options
author | Thomas Vigouroux <tomvig38@gmail.com> | 2020-11-23 12:25:36 +0100 |
---|---|---|
committer | Thomas Vigouroux <tomvig38@gmail.com> | 2020-11-25 10:10:05 +0100 |
commit | c0a6989d93d35811411155e43f37b2fc4658719e (patch) | |
tree | 973e033815651f0630099bada4ebb16278d6c0ae | |
parent | 43ec616414c7f17585e8b4a7e34acaaedfff5121 (diff) | |
download | rneovim-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.lua | 3 | ||||
-rw-r--r-- | src/nvim/api/buffer.c | 19 | ||||
-rw-r--r-- | src/nvim/decoration.c | 53 | ||||
-rw-r--r-- | src/nvim/decoration.h | 5 | ||||
-rw-r--r-- | test/functional/ui/bufhl_spec.lua | 60 |
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) |