mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 09:44:31 +00:00 
			
		
		
		
	fix(ui): handle virtual text with multiple hl in more cases (#25304)
This commit is contained in:
		@@ -1188,8 +1188,7 @@ VirtText parse_virt_text(Array chunks, Error *err, int *width)
 | 
			
		||||
            goto free_exit;
 | 
			
		||||
          }
 | 
			
		||||
          if (j < arr.size - 1) {
 | 
			
		||||
            kv_push(virt_text, ((VirtTextChunk){ .text = NULL,
 | 
			
		||||
                                                 .hl_id = hl_id }));
 | 
			
		||||
            kv_push(virt_text, ((VirtTextChunk){ .text = NULL, .hl_id = hl_id }));
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
 
 | 
			
		||||
@@ -153,6 +153,24 @@ void clear_virttext(VirtText *text)
 | 
			
		||||
  *text = (VirtText)KV_INITIAL_VALUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get the next chunk of a virtual text item.
 | 
			
		||||
///
 | 
			
		||||
/// @param[in]     vt    The virtual text item
 | 
			
		||||
/// @param[in,out] pos   Position in the virtual text item
 | 
			
		||||
/// @param[in,out] attr  Highlight attribute
 | 
			
		||||
///
 | 
			
		||||
/// @return  The text of the chunk, or NULL if there are no more chunks
 | 
			
		||||
char *next_virt_text_chunk(VirtText vt, size_t *pos, int *attr)
 | 
			
		||||
{
 | 
			
		||||
  char *text = NULL;
 | 
			
		||||
  for (; text == NULL && *pos < kv_size(vt); (*pos)++) {
 | 
			
		||||
    text = kv_A(vt, *pos).text;
 | 
			
		||||
    int hl_id = kv_A(vt, *pos).hl_id;
 | 
			
		||||
    *attr = hl_combine_attr(*attr, hl_id > 0 ? syn_id2attr(hl_id) : 0);
 | 
			
		||||
  }
 | 
			
		||||
  return text;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Decoration *decor_find_virttext(buf_T *buf, int row, uint64_t ns_id)
 | 
			
		||||
{
 | 
			
		||||
  MarkTreeIter itr[1] = { 0 };
 | 
			
		||||
 
 | 
			
		||||
@@ -324,24 +324,6 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get the next chunk of a virtual text item.
 | 
			
		||||
///
 | 
			
		||||
/// @param[in]     vt    The virtual text item
 | 
			
		||||
/// @param[in,out] pos   Position in the virtual text item
 | 
			
		||||
/// @param[in,out] attr  Highlight attribute
 | 
			
		||||
///
 | 
			
		||||
/// @return  The text of the chunk, or NULL if there are no more chunks
 | 
			
		||||
static char *next_virt_text_chunk(VirtText vt, size_t *pos, int *attr)
 | 
			
		||||
{
 | 
			
		||||
  char *text = NULL;
 | 
			
		||||
  for (; text == NULL && *pos < kv_size(vt); (*pos)++) {
 | 
			
		||||
    text = kv_A(vt, *pos).text;
 | 
			
		||||
    int hl_id = kv_A(vt, *pos).hl_id;
 | 
			
		||||
    *attr = hl_combine_attr(*attr, hl_id > 0 ? syn_id2attr(hl_id) : 0);
 | 
			
		||||
  }
 | 
			
		||||
  return text;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode, int max_col,
 | 
			
		||||
                               int vcol, bool rl)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -709,13 +709,15 @@ void end_search_hl(void)
 | 
			
		||||
  screen_search_hl.rm.regprog = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void win_redr_bordertext(win_T *wp, ScreenGrid *grid, VirtText text_chunks, int row, int col)
 | 
			
		||||
static void win_redr_bordertext(win_T *wp, ScreenGrid *grid, VirtText vt, int row, int col)
 | 
			
		||||
{
 | 
			
		||||
  for (size_t i = 0; i < text_chunks.size; i++) {
 | 
			
		||||
    char *text = text_chunks.items[i].text;
 | 
			
		||||
  for (size_t i = 0; i < kv_size(vt);) {
 | 
			
		||||
    int attr = 0;
 | 
			
		||||
    char *text = next_virt_text_chunk(vt, &i, &attr);
 | 
			
		||||
    if (text == NULL) {
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    int cell = (int)mb_string2cells(text);
 | 
			
		||||
    int hl_id = text_chunks.items[i].hl_id;
 | 
			
		||||
    int attr = hl_id ? syn_id2attr(hl_id) : 0;
 | 
			
		||||
    grid_puts(grid, text, row, col, attr);
 | 
			
		||||
    col += cell;
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -3344,8 +3344,13 @@ void f_foldtextresult(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
 | 
			
		||||
    }
 | 
			
		||||
    if (kv_size(vt) > 0) {
 | 
			
		||||
      assert(*text == NUL);
 | 
			
		||||
      for (size_t i = 0; i < kv_size(vt); i++) {
 | 
			
		||||
        char *new_text = concat_str(text, kv_A(vt, i).text);
 | 
			
		||||
      for (size_t i = 0; i < kv_size(vt);) {
 | 
			
		||||
        int attr = 0;
 | 
			
		||||
        char *new_text = next_virt_text_chunk(vt, &i, &attr);
 | 
			
		||||
        if (new_text == NULL) {
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        new_text = concat_str(text, new_text);
 | 
			
		||||
        xfree(text);
 | 
			
		||||
        text = new_text;
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -821,7 +821,7 @@ describe('float window', function()
 | 
			
		||||
        [4] = {bold = true, reverse = true},
 | 
			
		||||
        [5] = {reverse = true},
 | 
			
		||||
        [6] = {background = Screen.colors.LightMagenta, bold = true, reverse = true},
 | 
			
		||||
        [7] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
 | 
			
		||||
        [7] = {foreground = Screen.colors.White, background = Screen.colors.Red},
 | 
			
		||||
        [8] = {bold = true, foreground = Screen.colors.SeaGreen4},
 | 
			
		||||
        [9] = {background = Screen.colors.LightGrey, underline = true},
 | 
			
		||||
        [10] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Magenta},
 | 
			
		||||
@@ -2512,7 +2512,12 @@ describe('float window', function()
 | 
			
		||||
        ]]}
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      meths.win_set_config(win, {title= { {"🦄"},{"BB"}},title_pos="right",footer= { {"🦄"},{"BB"}},footer_pos="right"})
 | 
			
		||||
      command('hi B0 guibg=Red guifg=Black')
 | 
			
		||||
      command('hi B1 guifg=White')
 | 
			
		||||
      meths.win_set_config(win, {
 | 
			
		||||
        title = {{"🦄"}, {"BB", {"B0", "B1"}}}, title_pos = "right",
 | 
			
		||||
        footer= {{"🦄"}, {"BB", {"B0", "B1"}}}, footer_pos = "right",
 | 
			
		||||
      })
 | 
			
		||||
      if multigrid then
 | 
			
		||||
        screen:expect{grid=[[
 | 
			
		||||
        ## grid 1
 | 
			
		||||
@@ -2533,10 +2538,10 @@ describe('float window', function()
 | 
			
		||||
        ## grid 3
 | 
			
		||||
                                                  |
 | 
			
		||||
        ## grid 4
 | 
			
		||||
          {5:╔═════}🦄BB{5:╗}|
 | 
			
		||||
          {5:╔═════}🦄{7:BB}{5:╗}|
 | 
			
		||||
          {5:║}{1: halloj! }{5:║}|
 | 
			
		||||
          {5:║}{1: BORDAA  }{5:║}|
 | 
			
		||||
          {5:╚═════}🦄BB{5:╝}|
 | 
			
		||||
          {5:╚═════}🦄{7:BB}{5:╝}|
 | 
			
		||||
        ]], float_pos={
 | 
			
		||||
          [4] = { { id = 1001 }, "NW", 1, 2, 5, true }
 | 
			
		||||
        }, win_viewport={
 | 
			
		||||
@@ -2547,10 +2552,10 @@ describe('float window', function()
 | 
			
		||||
        screen:expect{grid=[[
 | 
			
		||||
          ^                                        |
 | 
			
		||||
          {0:~                                       }|
 | 
			
		||||
          {0:~    }{5:╔═════}🦄BB{5:╗}{0:                        }|
 | 
			
		||||
          {0:~    }{5:╔═════}🦄{7:BB}{5:╗}{0:                        }|
 | 
			
		||||
          {0:~    }{5:║}{1: halloj! }{5:║}{0:                        }|
 | 
			
		||||
          {0:~    }{5:║}{1: BORDAA  }{5:║}{0:                        }|
 | 
			
		||||
          {0:~    }{5:╚═════}🦄BB{5:╝}{0:                        }|
 | 
			
		||||
          {0:~    }{5:╚═════}🦄{7:BB}{5:╝}{0:                        }|
 | 
			
		||||
                                                  |
 | 
			
		||||
        ]]}
 | 
			
		||||
      end
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ describe("folded lines", function()
 | 
			
		||||
        [1] = {bold = true, foreground = Screen.colors.Blue1},
 | 
			
		||||
        [2] = {reverse = true},
 | 
			
		||||
        [3] = {bold = true, reverse = true},
 | 
			
		||||
        [4] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
 | 
			
		||||
        [4] = {foreground = Screen.colors.White, background = Screen.colors.Red},
 | 
			
		||||
        [5] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey},
 | 
			
		||||
        [6] = {background = Screen.colors.Yellow},
 | 
			
		||||
        [7] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
 | 
			
		||||
@@ -2938,10 +2938,15 @@ describe("folded lines", function()
 | 
			
		||||
      screen:try_resize(30, 7)
 | 
			
		||||
      insert(content1)
 | 
			
		||||
      command("hi! CursorLine guibg=NONE guifg=Red gui=NONE")
 | 
			
		||||
      command('hi F0 guibg=Red guifg=Black')
 | 
			
		||||
      command('hi F1 guifg=White')
 | 
			
		||||
      meths.set_option_value('cursorline', true, {})
 | 
			
		||||
      meths.set_option_value('foldcolumn', '4', {})
 | 
			
		||||
      meths.set_option_value('foldtext',
 | 
			
		||||
        '[[v:folddashes], ["\t", "Search"], [getline(v:foldstart), "NonText"]]', {})
 | 
			
		||||
      meths.set_option_value('foldtext', '['
 | 
			
		||||
        .. '["▶", ["F0", "F1"]], '
 | 
			
		||||
        .. '[v:folddashes], '
 | 
			
		||||
        .. '["\t", "Search"], '
 | 
			
		||||
        .. '[getline(v:foldstart), "NonText"]]', {})
 | 
			
		||||
 | 
			
		||||
      command('3,4fold')
 | 
			
		||||
      command('5,6fold')
 | 
			
		||||
@@ -2958,7 +2963,7 @@ describe("folded lines", function()
 | 
			
		||||
          [3:------------------------------]|
 | 
			
		||||
        ## grid 2
 | 
			
		||||
          {7:    }This is a                 |
 | 
			
		||||
          {7:+   }{13:^-}{17:       }{18:valid English}{13:·····}|
 | 
			
		||||
          {7:+   }{4:^▶}{13:-}{17:      }{18:valid English}{13:·····}|
 | 
			
		||||
          {1:~                             }|
 | 
			
		||||
          {1:~                             }|
 | 
			
		||||
          {1:~                             }|
 | 
			
		||||
@@ -2969,7 +2974,7 @@ describe("folded lines", function()
 | 
			
		||||
      else
 | 
			
		||||
        screen:expect([[
 | 
			
		||||
          {7:    }This is a                 |
 | 
			
		||||
          {7:+   }{13:^-}{17:       }{18:valid English}{13:·····}|
 | 
			
		||||
          {7:+   }{4:^▶}{13:-}{17:      }{18:valid English}{13:·····}|
 | 
			
		||||
          {1:~                             }|
 | 
			
		||||
          {1:~                             }|
 | 
			
		||||
          {1:~                             }|
 | 
			
		||||
@@ -2977,7 +2982,7 @@ describe("folded lines", function()
 | 
			
		||||
                                        |
 | 
			
		||||
        ]])
 | 
			
		||||
      end
 | 
			
		||||
      eq('-\tvalid English', funcs.foldtextresult(2))
 | 
			
		||||
      eq('▶-\tvalid English', funcs.foldtextresult(2))
 | 
			
		||||
 | 
			
		||||
      feed('zo')
 | 
			
		||||
      if multigrid then
 | 
			
		||||
@@ -2993,8 +2998,8 @@ describe("folded lines", function()
 | 
			
		||||
        ## grid 2
 | 
			
		||||
          {7:    }This is a                 |
 | 
			
		||||
          {7:-   }valid English             |
 | 
			
		||||
          {7:│+  }{5:--}{19:      }{18:sentence composed }|
 | 
			
		||||
          {7:│+  }{13:^--}{17:      }{18:in his cave.}{13:······}|
 | 
			
		||||
          {7:│+  }{4:▶}{5:--}{19:     }{18:sentence composed }|
 | 
			
		||||
          {7:│+  }{4:^▶}{13:--}{17:     }{18:in his cave.}{13:······}|
 | 
			
		||||
          {1:~                             }|
 | 
			
		||||
          {1:~                             }|
 | 
			
		||||
        ## grid 3
 | 
			
		||||
@@ -3004,15 +3009,15 @@ describe("folded lines", function()
 | 
			
		||||
        screen:expect([[
 | 
			
		||||
          {7:    }This is a                 |
 | 
			
		||||
          {7:-   }valid English             |
 | 
			
		||||
          {7:│+  }{5:--}{19:      }{18:sentence composed }|
 | 
			
		||||
          {7:│+  }{13:^--}{17:      }{18:in his cave.}{13:······}|
 | 
			
		||||
          {7:│+  }{4:▶}{5:--}{19:     }{18:sentence composed }|
 | 
			
		||||
          {7:│+  }{4:^▶}{13:--}{17:     }{18:in his cave.}{13:······}|
 | 
			
		||||
          {1:~                             }|
 | 
			
		||||
          {1:~                             }|
 | 
			
		||||
                                        |
 | 
			
		||||
        ]])
 | 
			
		||||
      end
 | 
			
		||||
      eq('--\tsentence composed by', funcs.foldtextresult(3))
 | 
			
		||||
      eq('--\tin his cave.', funcs.foldtextresult(5))
 | 
			
		||||
      eq('▶--\tsentence composed by', funcs.foldtextresult(3))
 | 
			
		||||
      eq('▶--\tin his cave.', funcs.foldtextresult(5))
 | 
			
		||||
 | 
			
		||||
      command('hi! Visual guibg=Red')
 | 
			
		||||
      feed('V2k')
 | 
			
		||||
@@ -3029,8 +3034,8 @@ describe("folded lines", function()
 | 
			
		||||
        ## grid 2
 | 
			
		||||
          {7:    }This is a                 |
 | 
			
		||||
          {7:-   }^v{14:alid English}             |
 | 
			
		||||
          {7:│+  }{15:--}{19:      }{20:sentence composed }|
 | 
			
		||||
          {7:│+  }{15:--}{19:      }{20:in his cave.}{15:······}|
 | 
			
		||||
          {7:│+  }{4:▶}{15:--}{19:     }{20:sentence composed }|
 | 
			
		||||
          {7:│+  }{4:▶}{15:--}{19:     }{20:in his cave.}{15:······}|
 | 
			
		||||
          {1:~                             }|
 | 
			
		||||
          {1:~                             }|
 | 
			
		||||
        ## grid 3
 | 
			
		||||
@@ -3040,8 +3045,8 @@ describe("folded lines", function()
 | 
			
		||||
        screen:expect([[
 | 
			
		||||
          {7:    }This is a                 |
 | 
			
		||||
          {7:-   }^v{14:alid English}             |
 | 
			
		||||
          {7:│+  }{15:--}{19:      }{20:sentence composed }|
 | 
			
		||||
          {7:│+  }{15:--}{19:      }{20:in his cave.}{15:······}|
 | 
			
		||||
          {7:│+  }{4:▶}{15:--}{19:     }{20:sentence composed }|
 | 
			
		||||
          {7:│+  }{4:▶}{15:--}{19:     }{20:in his cave.}{15:······}|
 | 
			
		||||
          {1:~                             }|
 | 
			
		||||
          {1:~                             }|
 | 
			
		||||
          {11:-- VISUAL LINE --}             |
 | 
			
		||||
@@ -3062,8 +3067,8 @@ describe("folded lines", function()
 | 
			
		||||
        ## grid 2
 | 
			
		||||
                           a si sihT{7:    }|
 | 
			
		||||
                       {14:hsilgnE dila}^v{7:   -}|
 | 
			
		||||
          {20: desopmoc ecnetnes}{19:      }{15:--}{7:  +│}|
 | 
			
		||||
          {15:······}{20:.evac sih ni}{19:      }{15:--}{7:  +│}|
 | 
			
		||||
          {20: desopmoc ecnetnes}{19:     }{15:--}{4:▶}{7:  +│}|
 | 
			
		||||
          {15:······}{20:.evac sih ni}{19:     }{15:--}{4:▶}{7:  +│}|
 | 
			
		||||
          {1:                             ~}|
 | 
			
		||||
          {1:                             ~}|
 | 
			
		||||
        ## grid 3
 | 
			
		||||
@@ -3073,8 +3078,8 @@ describe("folded lines", function()
 | 
			
		||||
        screen:expect([[
 | 
			
		||||
                           a si sihT{7:    }|
 | 
			
		||||
                       {14:hsilgnE dila}^v{7:   -}|
 | 
			
		||||
          {20: desopmoc ecnetnes}{19:      }{15:--}{7:  +│}|
 | 
			
		||||
          {15:······}{20:.evac sih ni}{19:      }{15:--}{7:  +│}|
 | 
			
		||||
          {20: desopmoc ecnetnes}{19:     }{15:--}{4:▶}{7:  +│}|
 | 
			
		||||
          {15:······}{20:.evac sih ni}{19:     }{15:--}{4:▶}{7:  +│}|
 | 
			
		||||
          {1:                             ~}|
 | 
			
		||||
          {1:                             ~}|
 | 
			
		||||
          {11:-- VISUAL LINE --}             |
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user