mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	decorations: allow virt_text overlay at any column
This commit is contained in:
		| @@ -1425,6 +1425,11 @@ 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: | ||||
| ///                 - "eol": right after eol character (default) | ||||
| ///                 - "overlay": display over the specified column, without | ||||
| ///                              shifting the underlying text. | ||||
| ///               - 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 | ||||
| @@ -1474,8 +1479,9 @@ 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; | ||||
|   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; | ||||
| @@ -1544,6 +1550,22 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, | ||||
|       if (ERROR_SET(err)) { | ||||
|         goto error; | ||||
|       } | ||||
|     } else if (strequal("virt_text_pos", k.data)) { | ||||
|       if (v->type != kObjectTypeString) { | ||||
|         api_set_error(err, kErrorTypeValidation, | ||||
|                       "virt_text_pos is not a String"); | ||||
|         goto error; | ||||
|       } | ||||
|       String str = v->data.string; | ||||
|       if (strequal("eol", str.data)) { | ||||
|         virt_text_pos = kVTEndOfLine; | ||||
|       } else if (strequal("overlay", str.data)) { | ||||
|         virt_text_pos = kVTOverlay; | ||||
|       } else { | ||||
|         api_set_error(err, kErrorTypeValidation, | ||||
|                       "virt_text_pos: invalid value"); | ||||
|         goto error; | ||||
|       } | ||||
|     } else if (strequal("ephemeral", k.data)) { | ||||
|       ephemeral = api_object_to_bool(*v, "ephemeral", false, err); | ||||
|       if (ERROR_SET(err)) { | ||||
| @@ -1585,7 +1607,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, | ||||
|  | ||||
|   // Only error out if they try to set end_right_gravity without | ||||
|   // setting end_col or end_line | ||||
|   if (line2 == -1 && col2 == 0 && end_gravity_set) { | ||||
|   if (line2 == -1 && col2 == -1 && end_gravity_set) { | ||||
|     api_set_error(err, kErrorTypeValidation, | ||||
|                   "cannot set end_right_gravity " | ||||
|                   "without setting end_line or end_col"); | ||||
| @@ -1609,30 +1631,28 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, | ||||
|     col2 = 0; | ||||
|   } | ||||
|  | ||||
|   Decoration *decor = NULL, tmp = { 0 }; | ||||
|  | ||||
|   if (kv_size(virt_text) || 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); | ||||
|   } | ||||
|  | ||||
|   // TODO(bfredl): synergize these two branches even more | ||||
|   if (ephemeral && decor_state.buf == buf) { | ||||
|     int attr_id = hl_id > 0 ? syn_id2attr(hl_id) : 0; | ||||
|     VirtText *vt_allocated = NULL; | ||||
|     if (kv_size(virt_text)) { | ||||
|       vt_allocated = xmalloc(sizeof *vt_allocated); | ||||
|       *vt_allocated = virt_text; | ||||
|     } | ||||
|     decor_add_ephemeral(attr_id, (int)line, (colnr_T)col, | ||||
|                         (int)line2, (colnr_T)col2, priority, vt_allocated); | ||||
|     decor_add_ephemeral((int)line, (int)col, line2, col2, decor, 0); | ||||
|   } else { | ||||
|     if (ephemeral) { | ||||
|       api_set_error(err, kErrorTypeException, "not yet implemented"); | ||||
|       goto error; | ||||
|     } | ||||
|     Decoration *decor = NULL; | ||||
|     if (kv_size(virt_text)) { | ||||
|       decor = xcalloc(1, sizeof(*decor)); | ||||
|       decor->hl_id = hl_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, | ||||
|                      line2, col2, decor, right_gravity, | ||||
|   | ||||
| @@ -188,20 +188,21 @@ bool decor_redraw_start(buf_T *buf, int top_row, DecorState *state) | ||||
|       goto next_mark; | ||||
|     } | ||||
|  | ||||
|     int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0; | ||||
|     VirtText *vt = kv_size(decor->virt_text) ? &decor->virt_text : NULL; | ||||
|     HlRange range; | ||||
|     if (mark.id&MARKTREE_END_FLAG) { | ||||
|       range = (HlRange){ altpos.row, altpos.col, mark.row, mark.col, | ||||
|                          attr_id, decor->priority, vt, false }; | ||||
|       decor_add(state, altpos.row, altpos.col, mark.row, mark.col, | ||||
|                 decor, false, 0); | ||||
|     } else { | ||||
|       range = (HlRange){ mark.row, mark.col, altpos.row, | ||||
|                          altpos.col, attr_id, decor->priority, vt, false }; | ||||
|       if (altpos.row == -1) { | ||||
|         altpos.row = mark.row; | ||||
|         altpos.col = mark.col; | ||||
|       } | ||||
|       decor_add(state, mark.row, mark.col, altpos.row, altpos.col, | ||||
|                 decor, false, 0); | ||||
|     } | ||||
|     hlrange_activate(range, state); | ||||
|  | ||||
| next_mark: | ||||
|     if (marktree_itr_node_done(state->itr)) { | ||||
|       marktree_itr_next(buf->b_marktree, state->itr); | ||||
|       break; | ||||
|     } | ||||
|     marktree_itr_next(buf->b_marktree, state->itr); | ||||
| @@ -220,41 +221,39 @@ 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) | ||||
| static void decor_add(DecorState *state, int start_row, int start_col, | ||||
|                       int end_row, int end_col, Decoration *decor, bool owned, | ||||
|                       DecorPriority priority) | ||||
| { | ||||
|   // Get size before preparing the push, to have the number of elements | ||||
|   size_t s = kv_size(state->active); | ||||
|   int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0; | ||||
|  | ||||
|   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, | ||||
|                     kv_size(decor->virt_text) && owned, -1 }; | ||||
|  | ||||
|   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) { | ||||
|   size_t index; | ||||
|   for (index = kv_size(state->active)-1; index > 0; index--) { | ||||
|     HlRange item = kv_A(state->active, index-1); | ||||
|     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; | ||||
|   kv_A(state->active, index) = range; | ||||
| } | ||||
|  | ||||
| int decor_redraw_col(buf_T *buf, int col, DecorState *state) | ||||
| int decor_redraw_col(buf_T *buf, int col, int virt_col, DecorState *state) | ||||
| { | ||||
|   if (col <= state->col_until) { | ||||
|     return state->current; | ||||
|   } | ||||
|   state->col_until = MAXCOL; | ||||
|   while (true) { | ||||
|     // TODO(bfredl): check duplicate entry in "intersection" | ||||
|     // branch | ||||
|     mtmark_t mark = marktree_itr_current(state->itr); | ||||
|     if (mark.row < 0 || mark.row > state->row) { | ||||
|       break; | ||||
| @@ -278,6 +277,11 @@ int decor_redraw_col(buf_T *buf, int col, DecorState *state) | ||||
|     } | ||||
|     Decoration *decor = item->decor; | ||||
|  | ||||
|     if (endpos.row == -1) { | ||||
|       endpos.row = mark.row; | ||||
|       endpos.col = mark.col; | ||||
|     } | ||||
|  | ||||
|     if (endpos.row < mark.row | ||||
|         || (endpos.row == mark.row && endpos.col <= mark.col)) { | ||||
|       if (!kv_size(decor->virt_text)) { | ||||
| @@ -285,12 +289,8 @@ 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; | ||||
|     hlrange_activate((HlRange){ mark.row, mark.col, | ||||
|                                 endpos.row, endpos.col, | ||||
|                                 attr_id, decor->priority, | ||||
|                                 vt, false }, state); | ||||
|     decor_add(state, mark.row, mark.col, endpos.row, endpos.col, | ||||
|               decor, false, 0); | ||||
|  | ||||
| next_mark: | ||||
|     marktree_itr_next(buf->b_marktree, state->itr); | ||||
| @@ -310,7 +310,7 @@ next_mark: | ||||
|       if (item.start_row < state->row | ||||
|           || (item.start_row == state->row && item.start_col <= col)) { | ||||
|         active = true; | ||||
|         if (item.end_row == state->row) { | ||||
|         if (item.end_row == state->row && item.end_col > col) { | ||||
|           state->col_until = MIN(state->col_until, item.end_col-1); | ||||
|         } | ||||
|       } else { | ||||
| @@ -322,8 +322,12 @@ next_mark: | ||||
|     if (active && item.attr_id > 0) { | ||||
|       attr = hl_combine_attr(attr, item.attr_id); | ||||
|     } | ||||
|     if ((item.start_row == state->row && item.start_col <= col) | ||||
|         && item.virt_text && item.virt_col == -1) { | ||||
|       item.virt_col = virt_col; | ||||
|     } | ||||
|     if (keep) { | ||||
|       kv_A(state->active, j++) = kv_A(state->active, i); | ||||
|       kv_A(state->active, j++) = item; | ||||
|     } else if (item.virt_text_owned) { | ||||
|       clear_virttext(item.virt_text); | ||||
|       xfree(item.virt_text); | ||||
| @@ -341,21 +345,20 @@ void decor_redraw_end(DecorState *state) | ||||
|  | ||||
| VirtText *decor_redraw_virt_text(buf_T *buf, DecorState *state) | ||||
| { | ||||
|   decor_redraw_col(buf, MAXCOL, state); | ||||
|   decor_redraw_col(buf, MAXCOL, MAXCOL, 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) { | ||||
|     if (item.start_row == state->row && item.virt_text | ||||
|         && item.virt_text_pos == kVTEndOfLine) { | ||||
|       return item.virt_text; | ||||
|     } | ||||
|   } | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
| void decor_add_ephemeral(int attr_id, int start_row, int start_col, | ||||
|                          int end_row, int end_col, DecorPriority priority, | ||||
|                          VirtText *virt_text) | ||||
| void decor_add_ephemeral(int start_row, int start_col, int end_row, int end_col, | ||||
|                          Decoration *decor, DecorPriority priority) | ||||
| { | ||||
| hlrange_activate(((HlRange){ start_row, start_col, end_row, end_col, attr_id, | ||||
|                              priority, virt_text, virt_text != NULL }), | ||||
|                  &decor_state); | ||||
|   decor_add(&decor_state, start_row, start_col, end_row, end_col, decor, true, | ||||
|             priority); | ||||
| } | ||||
|   | ||||
| @@ -18,10 +18,16 @@ typedef kvec_t(VirtTextChunk) VirtText; | ||||
| typedef uint16_t DecorPriority; | ||||
| #define DECOR_PRIORITY_BASE 0x1000 | ||||
|  | ||||
| typedef enum { | ||||
|   kVTEndOfLine, | ||||
|   kVTOverlay, | ||||
| } VirtTextPos; | ||||
|  | ||||
| struct Decoration | ||||
| { | ||||
|   int hl_id;  // highlight group | ||||
|   VirtText virt_text; | ||||
|   VirtTextPos virt_text_pos; | ||||
|   // TODO(bfredl): style, signs, etc | ||||
|   DecorPriority priority; | ||||
|   bool shared;  // shared decoration, don't free | ||||
| @@ -35,7 +41,9 @@ typedef struct { | ||||
|   int attr_id; | ||||
|   DecorPriority priority; | ||||
|   VirtText *virt_text; | ||||
|   VirtTextPos virt_text_pos; | ||||
|   bool virt_text_owned; | ||||
|   int virt_col; | ||||
| } HlRange; | ||||
|  | ||||
| typedef struct { | ||||
|   | ||||
| @@ -143,7 +143,7 @@ long tab_page_click_defs_size = 0; | ||||
| // for line_putchar. Contains the state that needs to be remembered from | ||||
| // putting one character to the next. | ||||
| typedef struct { | ||||
|   const char_u *p; | ||||
|   const char *p; | ||||
|   int prev_c;  // previous Arabic character | ||||
|   int prev_c1;  // first composing char for prev_c | ||||
| } LineState; | ||||
| @@ -1857,7 +1857,7 @@ static int compute_foldcolumn(win_T *wp, int col) | ||||
| /// Handles composing chars and arabic shaping state. | ||||
| static int line_putchar(LineState *s, schar_T *dest, int maxcells, bool rl) | ||||
| { | ||||
|   const char_u *p = s->p; | ||||
|   const char_u *p = (char_u *)s->p; | ||||
|   int cells = utf_ptr2cells(p); | ||||
|   int c_len = utfc_ptr2len(p); | ||||
|   int u8c, u8cc[MAX_MCO]; | ||||
| @@ -2870,6 +2870,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, | ||||
|           && vcol >= (long)wp->w_virtcol) | ||||
|          || (number_only && draw_state > WL_NR)) | ||||
|         && filler_todo <= 0) { | ||||
|       draw_virt_text(buf, &col, grid->Columns); | ||||
|       grid_put_linebuf(grid, row, 0, col, -grid->Columns, wp->w_p_rl, wp, | ||||
|                        wp->w_hl_attr_normal, false); | ||||
|       // Pretend we have finished updating the window.  Except when | ||||
| @@ -3397,7 +3398,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, | ||||
|         } | ||||
|  | ||||
|         if (has_decor && v > 0) { | ||||
|           int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v-1, | ||||
|           int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v-1, off, | ||||
|                                               &decor_state); | ||||
|           if (extmark_attr != 0) { | ||||
|             if (!attr_pri) { | ||||
| @@ -3919,7 +3920,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, | ||||
|         int i; | ||||
|  | ||||
|         size_t virt_pos = 0; | ||||
|         LineState s = LINE_STATE((char_u *)""); | ||||
|         LineState s = LINE_STATE(""); | ||||
|         int virt_attr = 0; | ||||
|  | ||||
|         // Make sure alignment is the same regardless | ||||
| @@ -3963,7 +3964,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, | ||||
|           if (do_virttext && !delay_virttext) { | ||||
|             if (*s.p == NUL) { | ||||
|               if (virt_pos < virt_text.size) { | ||||
|                 s.p = (char_u *)kv_A(virt_text, virt_pos).text; | ||||
|                 s.p = kv_A(virt_text, virt_pos).text; | ||||
|                 int hl_id = kv_A(virt_text, virt_pos).hl_id; | ||||
|                 virt_attr = hl_id > 0 ? syn_id2attr(hl_id) : 0; | ||||
|                 virt_pos++; | ||||
| @@ -4029,6 +4030,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, | ||||
|           col += n; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       draw_virt_text(buf, &col, grid->Columns); | ||||
|       grid_put_linebuf(grid, row, 0, col, grid->Columns, wp->w_p_rl, wp, | ||||
|                        wp->w_hl_attr_normal, false); | ||||
|       row++; | ||||
| @@ -4247,7 +4250,10 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, | ||||
|         && (grid->Columns == Columns  // Window spans the width of the screen, | ||||
|             || ui_has(kUIMultigrid))  // or has dedicated grid. | ||||
|         && !wp->w_p_rl;              // Not right-to-left. | ||||
|       grid_put_linebuf(grid, row, 0, col - boguscols, grid->Columns, wp->w_p_rl, | ||||
|  | ||||
|       int draw_col = col - boguscols; | ||||
|       draw_virt_text(buf, &draw_col, grid->Columns); | ||||
|       grid_put_linebuf(grid, row, 0, draw_col, grid->Columns, wp->w_p_rl, | ||||
|                        wp, wp->w_hl_attr_normal, wrap); | ||||
|       if (wrap) { | ||||
|         ScreenGrid *current_grid = grid; | ||||
| @@ -4323,6 +4329,43 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, | ||||
|   return row; | ||||
| } | ||||
|  | ||||
| void draw_virt_text(buf_T *buf, int *end_col, int max_col) | ||||
| { | ||||
|   DecorState *state = &decor_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 | ||||
|         && item->virt_text_pos == kVTOverlay | ||||
|         && item->virt_col >= 0) { | ||||
|         VirtText vt = *item->virt_text; | ||||
|         LineState s = LINE_STATE(""); | ||||
|         int virt_attr = 0; | ||||
|         int col = item->virt_col; | ||||
|         size_t virt_pos = 0; | ||||
|         item->virt_col = -2;  // deactivate | ||||
|  | ||||
|         while (col < max_col) { | ||||
|           if (!*s.p) { | ||||
|             if (virt_pos == kv_size(vt)) { | ||||
|               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 cells = line_putchar(&s, &linebuf_char[col], 2, false); | ||||
|           linebuf_attr[col++] = virt_attr; | ||||
|           if (cells > 1) { | ||||
|             linebuf_attr[col++] = virt_attr; | ||||
|           } | ||||
|         } | ||||
|         *end_col = MAX(*end_col, col); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| /// Determine if dedicated window grid should be used or the default_grid | ||||
| /// | ||||
| /// If UI did not request multigrid support, draw all windows on the | ||||
|   | ||||
| @@ -302,3 +302,98 @@ describe('decorations providers', function() | ||||
|     ]]} | ||||
|   end) | ||||
| end) | ||||
|  | ||||
| describe('extmark decorations', function() | ||||
|   local screen | ||||
|   before_each( function() | ||||
|     clear() | ||||
|     screen = Screen.new(50, 15) | ||||
|     screen:attach() | ||||
|     screen:set_default_attr_ids { | ||||
|       [1] = {bold=true, foreground=Screen.colors.Blue}; | ||||
|       [2] = {foreground = Screen.colors.Brown}; | ||||
|       [3] = {bold = true, foreground = Screen.colors.SeaGreen}; | ||||
|       [4] = {background = Screen.colors.Red1, foreground = Screen.colors.Gray100}; | ||||
|     } | ||||
|   end) | ||||
|  | ||||
|   it('can have virtual text of overlay style', function() | ||||
|     insert [[ | ||||
| for _,item in ipairs(items) do | ||||
|     local text, hl_id_cell, count = unpack(item) | ||||
|     if hl_id_cell ~= nil then | ||||
|         hl_id = hl_id_cell | ||||
|     end | ||||
|     for _ = 1, (count or 1) do | ||||
|         local cell = line[colpos] | ||||
|         cell.text = text | ||||
|         cell.hl_id = hl_id | ||||
|         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'}) | ||||
|     end | ||||
|   end | ||||
|   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'}) | ||||
|  | ||||
|   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:~                     }| | ||||
|                           | | ||||
|   ]]} | ||||
|   end) | ||||
| end) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Björn Linse
					Björn Linse