mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 09:44:31 +00:00 
			
		
		
		
	feat(decorations): allow more than one stacked highlight in a virt_text
This commit is contained in:
		@@ -1433,8 +1433,14 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
 | 
			
		||||
///               - hl_group : name of the highlight group used to highlight
 | 
			
		||||
///                   this mark.
 | 
			
		||||
///               - virt_text : virtual text to link to this mark.
 | 
			
		||||
///               - virt_text_pos : positioning of virtual text. Possible
 | 
			
		||||
///                                 values:
 | 
			
		||||
///                   A list of [text, highlight] tuples, each representing a
 | 
			
		||||
///                   text chunk with specified highlight. `highlight` element
 | 
			
		||||
///                   can either be a a single highlight group, or an array of
 | 
			
		||||
///                   multiple highlight groups that will be stacked
 | 
			
		||||
///                   (highest priority last). A highlight group can be supplied
 | 
			
		||||
///                   either as a string or as an integer, the latter which
 | 
			
		||||
///                   can be obtained using |nvim_get_hl_id_by_name|.
 | 
			
		||||
///               - virt_text_pos : position of virtual text. Possible values:
 | 
			
		||||
///                 - "eol": right after eol character (default)
 | 
			
		||||
///                 - "overlay": display over the specified column, without
 | 
			
		||||
///                              shifting the underlying text.
 | 
			
		||||
 
 | 
			
		||||
@@ -1603,22 +1603,38 @@ VirtText parse_virt_text(Array chunks, Error *err)
 | 
			
		||||
    Array chunk = chunks.items[i].data.array;
 | 
			
		||||
    if (chunk.size == 0 || chunk.size > 2
 | 
			
		||||
        || chunk.items[0].type != kObjectTypeString
 | 
			
		||||
        || (chunk.size == 2 && chunk.items[1].type != kObjectTypeString)) {
 | 
			
		||||
        || chunk.size > 2) {
 | 
			
		||||
      api_set_error(err, kErrorTypeValidation,
 | 
			
		||||
                    "Chunk is not an array with one or two strings");
 | 
			
		||||
      goto free_exit;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    String str = chunk.items[0].data.string;
 | 
			
		||||
    char *text = transstr(str.size > 0 ? str.data : "");  // allocates
 | 
			
		||||
 | 
			
		||||
    int hl_id = 0;
 | 
			
		||||
    if (chunk.size == 2) {
 | 
			
		||||
      String hl = chunk.items[1].data.string;
 | 
			
		||||
      if (hl.size > 0) {
 | 
			
		||||
        hl_id = syn_check_group((char_u *)hl.data, (int)hl.size);
 | 
			
		||||
      Object hl = chunk.items[1];
 | 
			
		||||
      if (hl.type == kObjectTypeArray) {
 | 
			
		||||
        Array arr = hl.data.array;
 | 
			
		||||
        for (size_t j = 0; j < arr.size; j++) {
 | 
			
		||||
          hl_id = object_to_hl_id(arr.items[j], "virt_text highlight", err);
 | 
			
		||||
          if (ERROR_SET(err)) {
 | 
			
		||||
            goto free_exit;
 | 
			
		||||
          }
 | 
			
		||||
          if (j < arr.size-1) {
 | 
			
		||||
            kv_push(virt_text, ((VirtTextChunk){ .text = NULL,
 | 
			
		||||
                                                 .hl_id = hl_id }));
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        hl_id = object_to_hl_id(hl, "virt_text highlight", err);
 | 
			
		||||
        if (ERROR_SET(err)) {
 | 
			
		||||
          goto free_exit;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    char *text = transstr(str.size > 0 ? str.data : "");  // allocates
 | 
			
		||||
    kv_push(virt_text, ((VirtTextChunk){ .text = text, .hl_id = hl_id }));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -1656,7 +1672,7 @@ int object_to_hl_id(Object obj, const char *what, Error *err)
 | 
			
		||||
    String str = obj.data.string;
 | 
			
		||||
    return str.size ? syn_check_group((char_u *)str.data, (int)str.size) : 0;
 | 
			
		||||
  } else if (obj.type == kObjectTypeInteger) {
 | 
			
		||||
    return (int)obj.data.integer;
 | 
			
		||||
    return MAX((int)obj.data.integer, 0);
 | 
			
		||||
  } else {
 | 
			
		||||
    api_set_error(err, kErrorTypeValidation,
 | 
			
		||||
                  "%s is not a valid highlight", what);
 | 
			
		||||
 
 | 
			
		||||
@@ -4021,6 +4021,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
 | 
			
		||||
 | 
			
		||||
        while (wp->w_p_rl ? col >= 0 : col < grid->Columns) {
 | 
			
		||||
          int cells = -1;
 | 
			
		||||
          // TODO: integrate this whith the other virt_text impl already
 | 
			
		||||
          if (do_virttext && !delay_virttext) {
 | 
			
		||||
            if (*s.p == NUL) {
 | 
			
		||||
              if (virt_pos < virt_text.size) {
 | 
			
		||||
@@ -4424,14 +4425,21 @@ void draw_virt_text(buf_T *buf, int col_off, int *end_col, int max_col)
 | 
			
		||||
 | 
			
		||||
      while (col < max_col) {
 | 
			
		||||
        if (!*s.p) {
 | 
			
		||||
          if (virt_pos == kv_size(vt)) {
 | 
			
		||||
          if (virt_pos >= kv_size(vt)) {
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
          virt_attr = 0;
 | 
			
		||||
          do {
 | 
			
		||||
            s.p = kv_A(vt, virt_pos).text;
 | 
			
		||||
            int hl_id = kv_A(vt, virt_pos).hl_id;
 | 
			
		||||
            virt_attr = hl_combine_attr(virt_attr,
 | 
			
		||||
                                        hl_id > 0 ? syn_id2attr(hl_id) : 0);
 | 
			
		||||
            virt_pos++;
 | 
			
		||||
          } while (!s.p && virt_pos < kv_size(vt));
 | 
			
		||||
          // TODO: y w0t m8
 | 
			
		||||
          if (!s.p) {
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
          s.p = kv_A(vt, virt_pos).text;
 | 
			
		||||
          int hl_id = kv_A(vt, virt_pos).hl_id;
 | 
			
		||||
          virt_attr = hl_id > 0 ? syn_id2attr(hl_id) : 0;
 | 
			
		||||
          virt_pos++;
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
        int attr;
 | 
			
		||||
        bool through = false;
 | 
			
		||||
 
 | 
			
		||||
@@ -697,6 +697,52 @@ end]]
 | 
			
		||||
                                                        |
 | 
			
		||||
    ]]}
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('can have virtual text which combines foreground and backround groups', function()
 | 
			
		||||
    screen:set_default_attr_ids {
 | 
			
		||||
      [1] = {bold=true, foreground=Screen.colors.Blue};
 | 
			
		||||
      [2] = {background = tonumber('0x123456'), foreground = tonumber('0xbbbbbb')};
 | 
			
		||||
      [3] = {background = tonumber('0x123456'), foreground = tonumber('0xcccccc')};
 | 
			
		||||
      [4] = {background = tonumber('0x234567'), foreground = tonumber('0xbbbbbb')};
 | 
			
		||||
      [5] = {background = tonumber('0x234567'), foreground = tonumber('0xcccccc')};
 | 
			
		||||
      [6] = {bold = true, foreground = tonumber('0xcccccc'), background = tonumber('0x234567')};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    exec [[
 | 
			
		||||
      hi BgOne guibg=#123456
 | 
			
		||||
      hi BgTwo guibg=#234567
 | 
			
		||||
      hi FgEin guifg=#bbbbbb
 | 
			
		||||
      hi FgZwei guifg=#cccccc
 | 
			
		||||
      hi VeryBold gui=bold
 | 
			
		||||
    ]]
 | 
			
		||||
 | 
			
		||||
    meths.buf_set_extmark(0, ns, 0, 0, { virt_text={
 | 
			
		||||
      {'a', {'BgOne', 'FgEin'}};
 | 
			
		||||
      {'b', {'BgOne', 'FgZwei'}};
 | 
			
		||||
      {'c', {'BgTwo', 'FgEin'}};
 | 
			
		||||
      {'d', {'BgTwo', 'FgZwei'}};
 | 
			
		||||
      {'X', {'BgTwo', 'FgZwei', 'VeryBold'}};
 | 
			
		||||
    }})
 | 
			
		||||
 | 
			
		||||
    screen:expect{grid=[[
 | 
			
		||||
      ^ {2:a}{3:b}{4:c}{5:d}{6:X}                                            |
 | 
			
		||||
      {1:~                                                 }|
 | 
			
		||||
      {1:~                                                 }|
 | 
			
		||||
      {1:~                                                 }|
 | 
			
		||||
      {1:~                                                 }|
 | 
			
		||||
      {1:~                                                 }|
 | 
			
		||||
      {1:~                                                 }|
 | 
			
		||||
      {1:~                                                 }|
 | 
			
		||||
      {1:~                                                 }|
 | 
			
		||||
      {1:~                                                 }|
 | 
			
		||||
      {1:~                                                 }|
 | 
			
		||||
      {1:~                                                 }|
 | 
			
		||||
      {1:~                                                 }|
 | 
			
		||||
      {1:~                                                 }|
 | 
			
		||||
                                                        |
 | 
			
		||||
    ]]}
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('does not crash when deleting a cleared buffer #15212', function()
 | 
			
		||||
    exec_lua [[
 | 
			
		||||
      ns = vim.api.nvim_create_namespace("myplugin")
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user