mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	decorations: add additional styling of virt_text overlays
This commit is contained in:
		| @@ -1430,6 +1430,18 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, | ||||
| ///                 - "eol": right after eol character (default) | ||||
| ///                 - "overlay": display over the specified column, without | ||||
| ///                              shifting the underlying text. | ||||
| ///               - virt_text_hide : hide the virtual text when the background | ||||
| ///                                  text is selected or hidden due to | ||||
| ///                                  horizontal scroll 'nowrap' | ||||
| ///               - hl_mode : control how highlights are combined with the | ||||
| ///                           highlights of the text. Currently only affects | ||||
| ///                           virt_text highlights, but might affect `hl_group` | ||||
| ///                           in later versions. | ||||
| ///                 - "replace": only show the virt_text color. This is the | ||||
| ///                              default | ||||
| ///                 - "combine": combine with background text color | ||||
| ///                 - "blend": blend with background text color. | ||||
| /// | ||||
| ///               - ephemeral : for use with |nvim_set_decoration_provider| | ||||
| ///                   callbacks. The mark will only be used for the current | ||||
| ///                   redraw cycle, and not be permantently stored in the | ||||
| @@ -1477,11 +1489,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, | ||||
|   bool ephemeral = false; | ||||
|  | ||||
|   uint64_t id = 0; | ||||
|   int line2 = -1, hl_id = 0; | ||||
|   DecorPriority priority = DECOR_PRIORITY_BASE; | ||||
|   int line2 = -1; | ||||
|   Decoration decor = DECORATION_INIT; | ||||
|   colnr_T col2 = -1; | ||||
|   VirtText virt_text = KV_INITIAL_VALUE; | ||||
|   VirtTextPos virt_text_pos = kVTEndOfLine; | ||||
|  | ||||
|   bool right_gravity = true; | ||||
|   bool end_right_gravity = false; | ||||
|   bool end_gravity_set = false; | ||||
| @@ -1528,12 +1539,12 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, | ||||
|       switch (v->type) { | ||||
|         case kObjectTypeString: | ||||
|           hl_group = v->data.string; | ||||
|           hl_id = syn_check_group( | ||||
|           decor.hl_id = syn_check_group( | ||||
|               (char_u *)(hl_group.data), | ||||
|               (int)hl_group.size); | ||||
|           break; | ||||
|         case kObjectTypeInteger: | ||||
|           hl_id = (int)v->data.integer; | ||||
|           decor.hl_id = (int)v->data.integer; | ||||
|           break; | ||||
|         default: | ||||
|           api_set_error(err, kErrorTypeValidation, | ||||
| @@ -1546,7 +1557,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, | ||||
|                       "virt_text is not an Array"); | ||||
|         goto error; | ||||
|       } | ||||
|       virt_text = parse_virt_text(v->data.array, err); | ||||
|       decor.virt_text = parse_virt_text(v->data.array, err); | ||||
|       if (ERROR_SET(err)) { | ||||
|         goto error; | ||||
|       } | ||||
| @@ -1558,9 +1569,33 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, | ||||
|       } | ||||
|       String str = v->data.string; | ||||
|       if (strequal("eol", str.data)) { | ||||
|         virt_text_pos = kVTEndOfLine; | ||||
|         decor.virt_text_pos = kVTEndOfLine; | ||||
|       } else if (strequal("overlay", str.data)) { | ||||
|         virt_text_pos = kVTOverlay; | ||||
|         decor.virt_text_pos = kVTOverlay; | ||||
|       } else { | ||||
|         api_set_error(err, kErrorTypeValidation, | ||||
|                       "virt_text_pos: invalid value"); | ||||
|         goto error; | ||||
|       } | ||||
|     } else if (strequal("virt_text_hide", k.data)) { | ||||
|       decor.virt_text_hide = api_object_to_bool(*v, | ||||
|                                                 "virt_text_hide", false, err); | ||||
|       if (ERROR_SET(err)) { | ||||
|         goto error; | ||||
|       } | ||||
|     } else if (strequal("hl_mode", k.data)) { | ||||
|       if (v->type != kObjectTypeString) { | ||||
|         api_set_error(err, kErrorTypeValidation, | ||||
|                       "hl_mode is not a String"); | ||||
|         goto error; | ||||
|       } | ||||
|       String str = v->data.string; | ||||
|       if (strequal("replace", str.data)) { | ||||
|         decor.hl_mode = kHlModeReplace; | ||||
|       } else if (strequal("combine", str.data)) { | ||||
|         decor.hl_mode = kHlModeCombine; | ||||
|       } else if (strequal("blend", str.data)) { | ||||
|         decor.hl_mode = kHlModeBlend; | ||||
|       } else { | ||||
|         api_set_error(err, kErrorTypeValidation, | ||||
|                       "virt_text_pos: invalid value"); | ||||
| @@ -1583,7 +1618,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, | ||||
|                       "priority is not a valid value"); | ||||
|         goto error; | ||||
|       } | ||||
|       priority = (DecorPriority)v->data.integer; | ||||
|       decor.priority = (DecorPriority)v->data.integer; | ||||
|     } else if (strequal("right_gravity", k.data)) { | ||||
|       if (v->type != kObjectTypeBoolean) { | ||||
|         api_set_error(err, kErrorTypeValidation, | ||||
| @@ -1631,23 +1666,23 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, | ||||
|     col2 = 0; | ||||
|   } | ||||
|  | ||||
|   Decoration *decor = NULL, tmp = { 0 }; | ||||
|   Decoration *d = NULL; | ||||
|  | ||||
|   if (kv_size(virt_text) || priority != DECOR_PRIORITY_BASE) { | ||||
|   if (ephemeral) { | ||||
|     d = &decor; | ||||
|   } else if (kv_size(decor.virt_text) | ||||
|              || decor.priority != DECOR_PRIORITY_BASE) { | ||||
|     // TODO(bfredl): this is a bit sketchy. eventually we should | ||||
|     // have predefined decorations for both marks/ephemerals | ||||
|     decor = ephemeral ? &tmp : xcalloc(1, sizeof(*decor)); | ||||
|     decor->hl_id = hl_id; | ||||
|     decor->virt_text = virt_text; | ||||
|     decor->priority = priority; | ||||
|     decor->virt_text_pos = virt_text_pos; | ||||
|   } else if (hl_id) { | ||||
|     decor = decor_hl(hl_id); | ||||
|     d = xcalloc(1, sizeof(*d)); | ||||
|     *d = decor; | ||||
|   } else if (decor.hl_id) { | ||||
|     d = decor_hl(decor.hl_id); | ||||
|   } | ||||
|  | ||||
|   // TODO(bfredl): synergize these two branches even more | ||||
|   if (ephemeral && decor_state.buf == buf) { | ||||
|     decor_add_ephemeral((int)line, (int)col, line2, col2, decor, 0); | ||||
|     decor_add_ephemeral((int)line, (int)col, line2, col2, &decor, 0); | ||||
|   } else { | ||||
|     if (ephemeral) { | ||||
|       api_set_error(err, kErrorTypeException, "not yet implemented"); | ||||
| @@ -1655,14 +1690,14 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, | ||||
|     } | ||||
|  | ||||
|     id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col, | ||||
|                      line2, col2, decor, right_gravity, | ||||
|                      line2, col2, d, right_gravity, | ||||
|                      end_right_gravity, kExtmarkNoUndo); | ||||
|   } | ||||
|  | ||||
|   return (Integer)id; | ||||
|  | ||||
| error: | ||||
|   clear_virttext(&virt_text); | ||||
|   clear_virttext(&decor.virt_text); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -230,7 +230,7 @@ static void decor_add(DecorState *state, int start_row, int start_col, | ||||
|   HlRange range = { start_row, start_col, end_row, end_col, | ||||
|                     attr_id, MAX(priority, decor->priority), | ||||
|                     kv_size(decor->virt_text) ? &decor->virt_text : NULL, | ||||
|                     decor->virt_text_pos, | ||||
|                     decor->virt_text_pos, decor->virt_text_hide, decor->hl_mode, | ||||
|                     kv_size(decor->virt_text) && owned, -1 }; | ||||
|  | ||||
|   kv_pushp(state->active); | ||||
| @@ -245,7 +245,8 @@ static void decor_add(DecorState *state, int start_row, int start_col, | ||||
|   kv_A(state->active, index) = range; | ||||
| } | ||||
|  | ||||
| int decor_redraw_col(buf_T *buf, int col, int virt_col, DecorState *state) | ||||
| int decor_redraw_col(buf_T *buf, int col, int virt_col, bool hidden, | ||||
|                      DecorState *state) | ||||
| { | ||||
|   if (col <= state->col_until) { | ||||
|     return state->current; | ||||
| @@ -324,7 +325,7 @@ next_mark: | ||||
|     } | ||||
|     if ((item.start_row == state->row && item.start_col <= col) | ||||
|         && item.virt_text && item.virt_col == -1) { | ||||
|       item.virt_col = virt_col; | ||||
|       item.virt_col = (item.virt_text_hide && hidden) ? -2 : virt_col; | ||||
|     } | ||||
|     if (keep) { | ||||
|       kv_A(state->active, j++) = item; | ||||
| @@ -345,7 +346,7 @@ void decor_redraw_end(DecorState *state) | ||||
|  | ||||
| VirtText *decor_redraw_virt_text(buf_T *buf, DecorState *state) | ||||
| { | ||||
|   decor_redraw_col(buf, MAXCOL, MAXCOL, state); | ||||
|   decor_redraw_col(buf, MAXCOL, MAXCOL, false, state); | ||||
|   for (size_t i = 0; i < kv_size(state->active); i++) { | ||||
|     HlRange item = kv_A(state->active, i); | ||||
|     if (item.start_row == state->row && item.virt_text | ||||
|   | ||||
| @@ -23,15 +23,26 @@ typedef enum { | ||||
|   kVTOverlay, | ||||
| } VirtTextPos; | ||||
|  | ||||
| typedef enum { | ||||
|   kHlModeUnknown, | ||||
|   kHlModeReplace, | ||||
|   kHlModeCombine, | ||||
|   kHlModeBlend, | ||||
| } HlMode; | ||||
|  | ||||
| struct Decoration | ||||
| { | ||||
|   int hl_id;  // highlight group | ||||
|   VirtText virt_text; | ||||
|   VirtTextPos virt_text_pos; | ||||
|   bool virt_text_hide; | ||||
|   HlMode hl_mode; | ||||
|   // TODO(bfredl): style, signs, etc | ||||
|   DecorPriority priority; | ||||
|   bool shared;  // shared decoration, don't free | ||||
| }; | ||||
| #define DECORATION_INIT { 0, KV_INITIAL_VALUE, kVTEndOfLine, false, \ | ||||
|                           kHlModeUnknown, DECOR_PRIORITY_BASE, false } | ||||
|  | ||||
| typedef struct { | ||||
|   int start_row; | ||||
| @@ -39,9 +50,13 @@ typedef struct { | ||||
|   int end_row; | ||||
|   int end_col; | ||||
|   int attr_id; | ||||
|   // TODO(bfredl): embed decoration instead, perhaps using an arena | ||||
|   // for ephemerals? | ||||
|   DecorPriority priority; | ||||
|   VirtText *virt_text; | ||||
|   VirtTextPos virt_text_pos; | ||||
|   bool virt_text_hide; | ||||
|   HlMode hl_mode; | ||||
|   bool virt_text_owned; | ||||
|   int virt_col; | ||||
| } HlRange; | ||||
|   | ||||
| @@ -2096,6 +2096,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, | ||||
|  | ||||
|   char_u buf_fold[FOLD_TEXT_LEN + 1];   // Hold value returned by get_foldtext | ||||
|  | ||||
|   bool area_active = false; | ||||
|  | ||||
|   /* draw_state: items that are drawn in sequence: */ | ||||
| #define WL_START        0               /* nothing done yet */ | ||||
| # define WL_CMDLINE     WL_START + 1    /* cmdline window column */ | ||||
| @@ -2850,6 +2852,12 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, | ||||
|       if (draw_state == WL_LINE - 1 && n_extra == 0) { | ||||
|         sign_idx = 0; | ||||
|         draw_state = WL_LINE; | ||||
|  | ||||
|         if (has_decor && row == startrow + filler_lines) { | ||||
|           // hide virt_text on text hidden by 'nowrap' | ||||
|           decor_redraw_col(wp->w_buffer, vcol, off, true, &decor_state); | ||||
|         } | ||||
|  | ||||
|         if (saved_n_extra) { | ||||
|           /* Continue item from end of wrapped line. */ | ||||
|           n_extra = saved_n_extra; | ||||
| @@ -2934,10 +2942,14 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, | ||||
|               && vcol_prev < vcol               // not at margin | ||||
|               && vcol < tocol)) { | ||||
|         area_attr = attr;                       // start highlighting | ||||
|         if (area_highlighting) { | ||||
|           area_active = true; | ||||
|         } | ||||
|       } else if (area_attr != 0 && (vcol == tocol | ||||
|                                     || (noinvcur | ||||
|                                         && (colnr_T)vcol == wp->w_virtcol))) { | ||||
|         area_attr = 0;                          // stop highlighting | ||||
|         area_active = false; | ||||
|      } | ||||
|  | ||||
|       if (!n_extra) { | ||||
| @@ -3397,9 +3409,15 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, | ||||
|             char_attr = hl_combine_attr(spell_attr, char_attr); | ||||
|         } | ||||
|  | ||||
|         if (wp->w_buffer->terminal) { | ||||
|           char_attr = hl_combine_attr(term_attrs[vcol], char_attr); | ||||
|         } | ||||
|  | ||||
|         if (has_decor && v > 0) { | ||||
|           bool selected = (area_active || (area_highlighting && noinvcur | ||||
|                                            && (colnr_T)vcol == wp->w_virtcol)); | ||||
|           int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v-1, off, | ||||
|                                               &decor_state); | ||||
|                                               selected, &decor_state); | ||||
|           if (extmark_attr != 0) { | ||||
|             if (!attr_pri) { | ||||
|               char_attr = hl_combine_attr(char_attr, extmark_attr); | ||||
| @@ -3409,10 +3427,6 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         if (wp->w_buffer->terminal) { | ||||
|           char_attr = hl_combine_attr(term_attrs[vcol], char_attr); | ||||
|         } | ||||
|  | ||||
|         // Found last space before word: check for line break. | ||||
|         if (wp->w_p_lbr && c0 == c && vim_isbreak(c) | ||||
|             && !vim_isbreak((int)(*ptr))) { | ||||
| @@ -4355,10 +4369,22 @@ void draw_virt_text(buf_T *buf, int *end_col, int max_col) | ||||
|             virt_pos++; | ||||
|             continue; | ||||
|           } | ||||
|           int cells = line_putchar(&s, &linebuf_char[col], 2, false); | ||||
|           linebuf_attr[col++] = virt_attr; | ||||
|           int attr; | ||||
|           bool through = false; | ||||
|           if (item->hl_mode == kHlModeCombine) { | ||||
|             attr = hl_combine_attr(linebuf_attr[col], virt_attr); | ||||
|           } else if (item->hl_mode == kHlModeBlend) { | ||||
|             through = (*s.p == ' '); | ||||
|             attr = hl_blend_attrs(linebuf_attr[col], virt_attr, &through); | ||||
|           } else { | ||||
|             attr = virt_attr; | ||||
|           } | ||||
|           schar_T dummy[2]; | ||||
|           int cells = line_putchar(&s, through ? dummy : &linebuf_char[col], | ||||
|                                    max_col-col, false); | ||||
|           linebuf_attr[col++] = attr; | ||||
|           if (cells > 1) { | ||||
|             linebuf_attr[col++] = virt_attr; | ||||
|             linebuf_attr[col++] = attr; | ||||
|           } | ||||
|         } | ||||
|         *end_col = MAX(*end_col, col); | ||||
|   | ||||
| @@ -8,6 +8,7 @@ local exec_lua = helpers.exec_lua | ||||
| local exec = helpers.exec | ||||
| local expect_events = helpers.expect_events | ||||
| local meths = helpers.meths | ||||
| local command = helpers.command | ||||
|  | ||||
| describe('decorations providers', function() | ||||
|   local screen | ||||
| @@ -314,11 +315,30 @@ describe('extmark decorations', function() | ||||
|       [2] = {foreground = Screen.colors.Brown}; | ||||
|       [3] = {bold = true, foreground = Screen.colors.SeaGreen}; | ||||
|       [4] = {background = Screen.colors.Red1, foreground = Screen.colors.Gray100}; | ||||
|       [5] = {foreground = Screen.colors.Brown, bold = true}; | ||||
|       [6] = {foreground = Screen.colors.DarkCyan}; | ||||
|       [7] = {foreground = Screen.colors.Grey0, background = tonumber('0xff4c4c')}; | ||||
|       [8] = {foreground = tonumber('0x180606'), background = tonumber('0xff4c4c')}; | ||||
|       [9] = {foreground = tonumber('0xe40c0c'), background = tonumber('0xff4c4c'), bold = true}; | ||||
|       [10] = {foreground = tonumber('0xb20000'), background = tonumber('0xff4c4c')}; | ||||
|       [11] = {blend = 30, background = Screen.colors.Red1}; | ||||
|       [12] = {foreground = Screen.colors.Brown, blend = 30, background = Screen.colors.Red1, bold = true}; | ||||
|       [13] = {foreground = Screen.colors.Fuchsia}; | ||||
|       [14] = {background = Screen.colors.Red1, foreground = Screen.colors.Black}; | ||||
|       [15] = {background = Screen.colors.Red1, foreground = tonumber('0xb20000')}; | ||||
|       [16] = {blend = 30, background = Screen.colors.Red1, foreground = Screen.colors.Magenta1}; | ||||
|       [17] = {bold = true, foreground = Screen.colors.Brown, background = Screen.colors.LightGrey}; | ||||
|       [18] = {background = Screen.colors.LightGrey}; | ||||
|       [19] = {foreground = Screen.colors.Cyan4, background = Screen.colors.LightGrey}; | ||||
|       [20] = {foreground = tonumber('0x180606'), background = tonumber('0xf13f3f')}; | ||||
|       [21] = {foreground = Screen.colors.Gray0, background = tonumber('0xf13f3f')}; | ||||
|       [22] = {foreground = tonumber('0xb20000'), background = tonumber('0xf13f3f')}; | ||||
|       [23] = {foreground = Screen.colors.Magenta1, background = Screen.colors.LightGrey}; | ||||
|       [24] = {bold = true}; | ||||
|     } | ||||
|   end) | ||||
|  | ||||
|   it('can have virtual text of overlay style', function() | ||||
|     insert [[ | ||||
|   local example_text = [[ | ||||
| for _,item in ipairs(items) do | ||||
|     local text, hl_id_cell, count = unpack(item) | ||||
|     if hl_id_cell ~= nil then | ||||
| @@ -331,69 +351,164 @@ for _,item in ipairs(items) do | ||||
|         colpos = colpos+1 | ||||
|     end | ||||
| end]] | ||||
|   feed 'gg' | ||||
|  | ||||
|   local ns = meths.create_namespace 'test' | ||||
|   for i = 1,9 do | ||||
|     meths.buf_set_extmark(0, ns, i, 0, { virt_text={{'|', 'LineNr'}}, virt_text_pos='overlay'}) | ||||
|     if i == 3 or (i >= 6 and i <= 9) then | ||||
|       meths.buf_set_extmark(0, ns, i, 4, { virt_text={{'|', 'NonText'}}, virt_text_pos='overlay'}) | ||||
|   it('can have virtual text of overlay position', function() | ||||
|     insert(example_text) | ||||
|     feed 'gg' | ||||
|  | ||||
|     local ns = meths.create_namespace 'test' | ||||
|     for i = 1,9 do | ||||
|       meths.buf_set_extmark(0, ns, i, 0, { virt_text={{'|', 'LineNr'}}, virt_text_pos='overlay'}) | ||||
|       if i == 3 or (i >= 6 and i <= 9) then | ||||
|         meths.buf_set_extmark(0, ns, i, 4, { virt_text={{'|', 'NonText'}}, virt_text_pos='overlay'}) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|   meths.buf_set_extmark(0, ns, 9, 10, { virt_text={{'foo'}, {'bar', 'MoreMsg'}, {'!!', 'ErrorMsg'}}, virt_text_pos='overlay'}) | ||||
|     meths.buf_set_extmark(0, ns, 9, 10, { virt_text={{'foo'}, {'bar', 'MoreMsg'}, {'!!', 'ErrorMsg'}}, virt_text_pos='overlay'}) | ||||
|  | ||||
|   -- can "float" beyond end of line | ||||
|   meths.buf_set_extmark(0, ns, 5, 28, { virt_text={{'loopy', 'ErrorMsg'}}, virt_text_pos='overlay'}) | ||||
|   -- bound check: right edge of window | ||||
|   meths.buf_set_extmark(0, ns, 2, 26, { virt_text={{'bork bork bork ' }, {'bork bork bork', 'ErrorMsg'}}, virt_text_pos='overlay'}) | ||||
|     -- can "float" beyond end of line | ||||
|     meths.buf_set_extmark(0, ns, 5, 28, { virt_text={{'loopy', 'ErrorMsg'}}, virt_text_pos='overlay'}) | ||||
|     -- bound check: right edge of window | ||||
|     meths.buf_set_extmark(0, ns, 2, 26, { virt_text={{'bork bork bork ' }, {'bork bork bork', 'ErrorMsg'}}, virt_text_pos='overlay'}) | ||||
|  | ||||
|   screen:expect{grid=[[ | ||||
|     ^for _,item in ipairs(items) do                    | | ||||
|     {2:|}   local text, hl_id_cell, count = unpack(item)  | | ||||
|     {2:|}   if hl_id_cell ~= nil tbork bork bork {4:bork bork}| | ||||
|     {2:|}   {1:|}   hl_id = hl_id_cell                        | | ||||
|     {2:|}   end                                           | | ||||
|     {2:|}   for _ = 1, (count or 1) {4:loopy}                 | | ||||
|     {2:|}   {1:|}   local cell = line[colpos]                 | | ||||
|     {2:|}   {1:|}   cell.text = text                          | | ||||
|     {2:|}   {1:|}   cell.hl_id = hl_id                        | | ||||
|     {2:|}   {1:|}   cofoo{3:bar}{4:!!}olpos+1                         | | ||||
|         end                                           | | ||||
|     end                                               | | ||||
|     {1:~                                                 }| | ||||
|     {1:~                                                 }| | ||||
|                                                       | | ||||
|   ]]} | ||||
|     screen:expect{grid=[[ | ||||
|       ^for _,item in ipairs(items) do                    | | ||||
|       {2:|}   local text, hl_id_cell, count = unpack(item)  | | ||||
|       {2:|}   if hl_id_cell ~= nil tbork bork bork {4:bork bork}| | ||||
|       {2:|}   {1:|}   hl_id = hl_id_cell                        | | ||||
|       {2:|}   end                                           | | ||||
|       {2:|}   for _ = 1, (count or 1) {4:loopy}                 | | ||||
|       {2:|}   {1:|}   local cell = line[colpos]                 | | ||||
|       {2:|}   {1:|}   cell.text = text                          | | ||||
|       {2:|}   {1:|}   cell.hl_id = hl_id                        | | ||||
|       {2:|}   {1:|}   cofoo{3:bar}{4:!!}olpos+1                         | | ||||
|           end                                           | | ||||
|       end                                               | | ||||
|       {1:~                                                 }| | ||||
|       {1:~                                                 }| | ||||
|                                                         | | ||||
|     ]]} | ||||
|  | ||||
|  | ||||
|   -- handles broken lines | ||||
|   screen:try_resize(22, 25) | ||||
|   screen:expect{grid=[[ | ||||
|     ^for _,item in ipairs(i| | ||||
|     tems) do              | | ||||
|     {2:|}   local text, hl_id_| | ||||
|     cell, count = unpack(i| | ||||
|     tem)                  | | ||||
|     {2:|}   if hl_id_cell ~= n| | ||||
|     il tbork bork bork {4:bor}| | ||||
|     {2:|}   {1:|}   hl_id = hl_id_| | ||||
|     cell                  | | ||||
|     {2:|}   end               | | ||||
|     {2:|}   for _ = 1, (count | | ||||
|     or 1) {4:loopy}           | | ||||
|     {2:|}   {1:|}   local cell = l| | ||||
|     ine[colpos]           | | ||||
|     {2:|}   {1:|}   cell.text = te| | ||||
|     xt                    | | ||||
|     {2:|}   {1:|}   cell.hl_id = h| | ||||
|     l_id                  | | ||||
|     {2:|}   {1:|}   cofoo{3:bar}{4:!!}olpo| | ||||
|     s+1                   | | ||||
|         end               | | ||||
|     end                   | | ||||
|     {1:~                     }| | ||||
|     {1:~                     }| | ||||
|                           | | ||||
|   ]]} | ||||
|     -- handles broken lines | ||||
|     screen:try_resize(22, 25) | ||||
|     screen:expect{grid=[[ | ||||
|       ^for _,item in ipairs(i| | ||||
|       tems) do              | | ||||
|       {2:|}   local text, hl_id_| | ||||
|       cell, count = unpack(i| | ||||
|       tem)                  | | ||||
|       {2:|}   if hl_id_cell ~= n| | ||||
|       il tbork bork bork {4:bor}| | ||||
|       {2:|}   {1:|}   hl_id = hl_id_| | ||||
|       cell                  | | ||||
|       {2:|}   end               | | ||||
|       {2:|}   for _ = 1, (count | | ||||
|       or 1) {4:loopy}           | | ||||
|       {2:|}   {1:|}   local cell = l| | ||||
|       ine[colpos]           | | ||||
|       {2:|}   {1:|}   cell.text = te| | ||||
|       xt                    | | ||||
|       {2:|}   {1:|}   cell.hl_id = h| | ||||
|       l_id                  | | ||||
|       {2:|}   {1:|}   cofoo{3:bar}{4:!!}olpo| | ||||
|       s+1                   | | ||||
|           end               | | ||||
|       end                   | | ||||
|       {1:~                     }| | ||||
|       {1:~                     }| | ||||
|                             | | ||||
|     ]]} | ||||
|   end) | ||||
|  | ||||
|   it('can have virtual text of overlay position and styling', function() | ||||
|     insert(example_text) | ||||
|     feed 'gg' | ||||
|     local ns = meths.create_namespace 'test' | ||||
|  | ||||
|     command 'set ft=lua' | ||||
|     command 'syntax on' | ||||
|  | ||||
|     screen:expect{grid=[[ | ||||
|       {5:^for} _,item {5:in} {6:ipairs}(items) {5:do}                    | | ||||
|           {5:local} text, hl_id_cell, count = unpack(item)  | | ||||
|           {5:if} hl_id_cell ~= {13:nil} {5:then}                     | | ||||
|               hl_id = hl_id_cell                        | | ||||
|           {5:end}                                           | | ||||
|           {5:for} _ = {13:1}, (count {5:or} {13:1}) {5:do}                    | | ||||
|               {5:local} cell = line[colpos]                 | | ||||
|               cell.text = text                          | | ||||
|               cell.hl_id = hl_id                        | | ||||
|               colpos = colpos+{13:1}                         | | ||||
|           {5:end}                                           | | ||||
|       {5:end}                                               | | ||||
|       {1:~                                                 }| | ||||
|       {1:~                                                 }| | ||||
|                                                         | | ||||
|     ]]} | ||||
|  | ||||
|     command 'hi Blendy guibg=Red blend=30' | ||||
|     meths.buf_set_extmark(0, ns, 1, 5, { virt_text={{'blendy text - here', 'Blendy'}}, virt_text_pos='overlay', hl_mode='blend'}) | ||||
|     meths.buf_set_extmark(0, ns, 2, 5, { virt_text={{'combining color', 'Blendy'}}, virt_text_pos='overlay', hl_mode='combine'}) | ||||
|     meths.buf_set_extmark(0, ns, 3, 5, { virt_text={{'replacing color', 'Blendy'}}, virt_text_pos='overlay', hl_mode='replace'}) | ||||
|  | ||||
|     meths.buf_set_extmark(0, ns, 4, 5, { virt_text={{'blendy text - here', 'Blendy'}}, virt_text_pos='overlay', hl_mode='blend', virt_text_hide=true}) | ||||
|     meths.buf_set_extmark(0, ns, 5, 5, { virt_text={{'combining color', 'Blendy'}}, virt_text_pos='overlay', hl_mode='combine', virt_text_hide=true}) | ||||
|     meths.buf_set_extmark(0, ns, 6, 5, { virt_text={{'replacing color', 'Blendy'}}, virt_text_pos='overlay', hl_mode='replace', virt_text_hide=true}) | ||||
|  | ||||
|     screen:expect{grid=[[ | ||||
|       {5:^for} _,item {5:in} {6:ipairs}(items) {5:do}                    | | ||||
|           {5:l}{8:blen}{7:dy}{10:e}{7:text}{10:h}{7:-}{10:_}{7:here}ell, count = unpack(item)  | | ||||
|           {5:i}{12:c}{11:ombining color} {13:nil} {5:then}                     | | ||||
|            {11:replacing color}d_cell                        | | ||||
|           {5:e}{8:bl}{14:endy}{15:i}{14:text}{15:o}{14:-}{15:o}{14:h}{7:ere}                           | | ||||
|           {5:f}{12:co}{11:mbini}{16:n}{11:g color}t {5:or} {13:1}) {5:do}                    | | ||||
|            {11:replacing color} line[colpos]                 | | ||||
|               cell.text = text                          | | ||||
|               cell.hl_id = hl_id                        | | ||||
|               colpos = colpos+{13:1}                         | | ||||
|           {5:end}                                           | | ||||
|       {5:end}                                               | | ||||
|       {1:~                                                 }| | ||||
|       {1:~                                                 }| | ||||
|                                                         | | ||||
|     ]]} | ||||
|  | ||||
|     feed 'V5G' | ||||
|     screen:expect{grid=[[ | ||||
|       {17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do}                    | | ||||
|       {18:    }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count = unpack(item)}  | | ||||
|       {18:    }{17:i}{12:c}{11:ombining color}{18: }{23:nil}{18: }{17:then}                     | | ||||
|       {18:     }{11:replacing color}{18:d_cell}                        | | ||||
|       {18:    }{5:^e}{17:nd}                                           | | ||||
|           {5:f}{12:co}{11:mbini}{16:n}{11:g color}t {5:or} {13:1}) {5:do}                    | | ||||
|            {11:replacing color} line[colpos]                 | | ||||
|               cell.text = text                          | | ||||
|               cell.hl_id = hl_id                        | | ||||
|               colpos = colpos+{13:1}                         | | ||||
|           {5:end}                                           | | ||||
|       {5:end}                                               | | ||||
|       {1:~                                                 }| | ||||
|       {1:~                                                 }| | ||||
|       {24:-- VISUAL LINE --}                                 | | ||||
|     ]]} | ||||
|  | ||||
|     feed 'jj' | ||||
|     screen:expect{grid=[[ | ||||
|       {17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do}                    | | ||||
|       {18:    }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count = unpack(item)}  | | ||||
|       {18:    }{17:i}{12:c}{11:ombining color}{18: }{23:nil}{18: }{17:then}                     | | ||||
|       {18:     }{11:replacing color}{18:d_cell}                        | | ||||
|       {18:    }{17:end}                                           | | ||||
|       {18:    }{17:for}{18: _ = }{23:1}{18:, (count }{17:or}{18: }{23:1}{18:) }{17:do}                    | | ||||
|       {18:    }^ {18:   }{17:local}{18: cell = line[colpos]}                 | | ||||
|               cell.text = text                          | | ||||
|               cell.hl_id = hl_id                        | | ||||
|               colpos = colpos+{13:1}                         | | ||||
|           {5:end}                                           | | ||||
|       {5:end}                                               | | ||||
|       {1:~                                                 }| | ||||
|       {1:~                                                 }| | ||||
|       {24:-- VISUAL LINE --}                                 | | ||||
|     ]]} | ||||
|   end) | ||||
| end) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Björn Linse
					Björn Linse