mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	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)
This commit is contained in:
		| @@ -219,7 +219,8 @@ local function on_line_impl(self, buf, line) | |||||||
|         a.nvim_buf_set_extmark(buf, ns, start_row, start_col, |         a.nvim_buf_set_extmark(buf, ns, start_row, start_col, | ||||||
|                                { end_line = end_row, end_col = end_col, |                                { end_line = end_row, end_col = end_col, | ||||||
|                                  hl_group = hl, |                                  hl_group = hl, | ||||||
|                                  ephemeral = true |                                  ephemeral = true, | ||||||
|  |                                  priority = 100 -- Low but leaves room below | ||||||
|                                 }) |                                 }) | ||||||
|       end |       end | ||||||
|       if start_row > line then |       if start_row > line then | ||||||
|   | |||||||
| @@ -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, "virt_text", ARRAY_OBJ(chunks)); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |       PUT(dict, "priority", INTEGER_OBJ(decor->priority)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (dict.size) { |     if (dict.size) { | ||||||
| @@ -1375,6 +1377,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, | |||||||
|  |  | ||||||
|   uint64_t id = 0; |   uint64_t id = 0; | ||||||
|   int line2 = -1, hl_id = 0; |   int line2 = -1, hl_id = 0; | ||||||
|  |   DecorPriority priority = DECOR_PRIORITY_BASE; | ||||||
|   colnr_T col2 = 0; |   colnr_T col2 = 0; | ||||||
|   VirtText virt_text = KV_INITIAL_VALUE; |   VirtText virt_text = KV_INITIAL_VALUE; | ||||||
|   for (size_t i = 0; i < opts.size; i++) { |   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)) { |       if (ERROR_SET(err)) { | ||||||
|         goto error; |         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 { |     } else { | ||||||
|       api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); |       api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); | ||||||
|       goto error; |       goto error; | ||||||
| @@ -1479,7 +1495,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, | |||||||
|       *vt_allocated = virt_text; |       *vt_allocated = virt_text; | ||||||
|     } |     } | ||||||
|     decor_add_ephemeral(attr_id, (int)line, (colnr_T)col, |     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 { |   } else { | ||||||
|     if (ephemeral) { |     if (ephemeral) { | ||||||
|       api_set_error(err, kErrorTypeException, "not yet implemented"); |       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; |       decor->virt_text = virt_text; | ||||||
|     } else if (hl_id) { |     } else if (hl_id) { | ||||||
|       decor = decor_hl(hl_id); |       decor = decor_hl(hl_id); | ||||||
|  |       decor->priority = priority; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col, |     id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col, | ||||||
|   | |||||||
| @@ -43,6 +43,7 @@ void bufhl_add_hl_pos_offset(buf_T *buf, | |||||||
|   colnr_T hl_end = 0; |   colnr_T hl_end = 0; | ||||||
|   Decoration *decor = decor_hl(hl_id); |   Decoration *decor = decor_hl(hl_id); | ||||||
|  |  | ||||||
|  |   decor->priority = DECOR_PRIORITY_BASE; | ||||||
|   // TODO(bfredl): if decoration had blocky mode, we could avoid this loop |   // TODO(bfredl): if decoration had blocky mode, we could avoid this loop | ||||||
|   for (linenr_T lnum = pos_start.lnum; lnum <= pos_end.lnum; lnum ++) { |   for (linenr_T lnum = pos_start.lnum; lnum <= pos_end.lnum; lnum ++) { | ||||||
|     int end_off = 0; |     int end_off = 0; | ||||||
| @@ -84,6 +85,7 @@ Decoration *decor_hl(int hl_id) | |||||||
|   Decoration *decor = xcalloc(1, sizeof(*decor)); |   Decoration *decor = xcalloc(1, sizeof(*decor)); | ||||||
|   decor->hl_id = hl_id; |   decor->hl_id = hl_id; | ||||||
|   decor->shared = true; |   decor->shared = true; | ||||||
|  |   decor->priority = DECOR_PRIORITY_BASE; | ||||||
|   *dp = decor; |   *dp = decor; | ||||||
|   return decor; |   return decor; | ||||||
| } | } | ||||||
| @@ -191,12 +193,12 @@ bool decor_redraw_start(buf_T *buf, int top_row, DecorState *state) | |||||||
|     HlRange range; |     HlRange range; | ||||||
|     if (mark.id&MARKTREE_END_FLAG) { |     if (mark.id&MARKTREE_END_FLAG) { | ||||||
|       range = (HlRange){ altpos.row, altpos.col, mark.row, mark.col, |       range = (HlRange){ altpos.row, altpos.col, mark.row, mark.col, | ||||||
|                          attr_id, vt, false }; |                          attr_id, decor->priority, vt, false }; | ||||||
|     } else { |     } else { | ||||||
|       range = (HlRange){ mark.row, mark.col, altpos.row, |       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: | next_mark: | ||||||
|     if (marktree_itr_node_done(state->itr)) { |     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 |   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) | int decor_redraw_col(buf_T *buf, int col, DecorState *state) | ||||||
| { | { | ||||||
|   if (col <= state->col_until) { |   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; |     int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0; | ||||||
|     VirtText *vt = kv_size(decor->virt_text) ? &decor->virt_text : NULL; |     VirtText *vt = kv_size(decor->virt_text) ? &decor->virt_text : NULL; | ||||||
|     kv_push(state->active, ((HlRange){ mark.row, mark.col, |     hlrange_activate((HlRange){ mark.row, mark.col, | ||||||
|                                        endpos.row, endpos.col, |                                 endpos.row, endpos.col, | ||||||
|                                        attr_id, vt, false })); |                                 attr_id, decor->priority, | ||||||
|  |                                 vt, false }, state); | ||||||
|  |  | ||||||
| next_mark: | next_mark: | ||||||
|     marktree_itr_next(buf->b_marktree, state->itr); |     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, | 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_activate(((HlRange){ start_row, start_col, end_row, end_col, attr_id, | ||||||
|           ((HlRange){ start_row, start_col, |                              priority, virt_text, virt_text != NULL }), | ||||||
|                       end_row, end_col, |                  &decor_state); | ||||||
|                       attr_id, virt_text, virt_text != NULL })); |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -15,11 +15,15 @@ typedef struct { | |||||||
| typedef kvec_t(VirtTextChunk) VirtText; | typedef kvec_t(VirtTextChunk) VirtText; | ||||||
| #define VIRTTEXT_EMPTY ((VirtText)KV_INITIAL_VALUE) | #define VIRTTEXT_EMPTY ((VirtText)KV_INITIAL_VALUE) | ||||||
|  |  | ||||||
|  | typedef uint16_t DecorPriority; | ||||||
|  | #define DECOR_PRIORITY_BASE 0x1000 | ||||||
|  |  | ||||||
| struct Decoration | struct Decoration | ||||||
| { | { | ||||||
|   int hl_id;  // highlight group |   int hl_id;  // highlight group | ||||||
|   VirtText virt_text; |   VirtText virt_text; | ||||||
|   // TODO(bfredl): style, signs, etc |   // TODO(bfredl): style, signs, etc | ||||||
|  |   DecorPriority priority; | ||||||
|   bool shared;  // shared decoration, don't free |   bool shared;  // shared decoration, don't free | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -29,6 +33,7 @@ typedef struct { | |||||||
|   int end_row; |   int end_row; | ||||||
|   int end_col; |   int end_col; | ||||||
|   int attr_id; |   int attr_id; | ||||||
|  |   DecorPriority priority; | ||||||
|   VirtText *virt_text; |   VirtText *virt_text; | ||||||
|   bool virt_text_owned; |   bool virt_text_owned; | ||||||
| } HlRange; | } HlRange; | ||||||
|   | |||||||
| @@ -534,6 +534,62 @@ describe('Buffer highlighting', function() | |||||||
|     ]]} |     ]]} | ||||||
|   end) |   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() |   it('works with multibyte text', function() | ||||||
|     insert([[ |     insert([[ | ||||||
|       Ta båten över sjön!]]) |       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 |       -- TODO: only a virtual text from the same ns curretly overrides | ||||||
|       -- an existing virtual text. We might add a prioritation system. |       -- an existing virtual text. We might add a prioritation system. | ||||||
|       set_virtual_text(id1, 0, s1, {}) |       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? |       -- TODO: is this really valid? shouldn't the max be line_count()-1? | ||||||
|       local lastline = line_count() |       local lastline = line_count() | ||||||
|       set_virtual_text(id1, line_count(), s2, {}) |       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}, {})) |       eq({}, get_extmarks(id1, {lastline+9000,0}, {lastline+9000, -1}, {})) | ||||||
|     end) |     end) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Thomas Vigouroux
					Thomas Vigouroux