mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +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,
 | 
			
		||||
                               { 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
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
    hlrange_activate((HlRange){ mark.row, mark.col,
 | 
			
		||||
                                endpos.row, endpos.col,
 | 
			
		||||
                                       attr_id, vt, false }));
 | 
			
		||||
                                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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user