From 392c658d4d0f9457f143748adf98ecd4cdc8dc85 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 8 Aug 2021 17:36:54 +0200 Subject: feat(decorations): support virtual lines (for now: only one block at a time) --- src/nvim/api/buffer.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 8 deletions(-) (limited to 'src/nvim/api/buffer.c') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 8973f8fef6..0ef2776263 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1415,6 +1415,10 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// - end_col : ending col of the mark, 0-based exclusive. /// - hl_group : name of the highlight group used to highlight /// this mark. +/// - hl_eol : when true, for a multiline highlight covering the +/// EOL of a line, continue the highlight for the rest +/// of the screen line (just like for diff and +/// cursorline highlight). /// - virt_text : virtual text to link to this mark. /// A list of [text, highlight] tuples, each representing a /// text chunk with specified highlight. `highlight` element @@ -1442,10 +1446,28 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// default /// - "combine": combine with background text color /// - "blend": blend with background text color. -/// - hl_eol : when true, for a multiline highlight covering the -/// EOL of a line, continue the highlight for the rest -/// of the screen line (just like for diff and -/// cursorline highlight). +/// +/// - virt_lines : virtual lines to add next to this mark +/// This should be an array over lines, where each line in +/// turn is an array over [text, highlight] tuples. In +/// general, buffer and window options do not affect the +/// display of the text. In particular 'wrap' +/// and 'linebreak' options do not take effect, so +/// the number of extra screen lines will always match +/// the size of the array. However the 'tabstop' buffer +/// option is still used for hard tabs. By default lines are +/// placed below the buffer line containing the mark. +/// +/// Note: currently virtual lines are limited to one block +/// per buffer. Thus setting a new mark disables any previous +/// `virt_lines` decoration. However plugins should not rely +/// on this behaviour, as this limitation is planned to be +/// removed. +/// +/// - virt_lines_above: place virtual lines above instead. +/// - virt_lines_leftcol: Place extmarks in the leftmost +/// column of the window, bypassing +/// sign and number columns. /// /// - ephemeral : for use with |nvim_set_decoration_provider| /// callbacks. The mark will only be used for the current @@ -1487,6 +1509,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer bool end_right_gravity = false; bool end_gravity_set = false; + VirtLines virt_lines = KV_INITIAL_VALUE; + bool virt_lines_above = false; + bool virt_lines_leftcol = false; + for (size_t i = 0; i < opts.size; i++) { String k = opts.items[i].key; Object *v = &opts.items[i].value; @@ -1584,6 +1610,36 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer if (ERROR_SET(err)) { goto error; } + } else if (strequal("virt_lines", k.data)) { + if (v->type != kObjectTypeArray) { + api_set_error(err, kErrorTypeValidation, + "virt_lines is not an Array"); + goto error; + } + Array a = v->data.array; + for (size_t j = 0; j < a.size; j++) { + if (a.items[j].type != kObjectTypeArray) { + api_set_error(err, kErrorTypeValidation, + "virt_text_line item is not an Array"); + goto error; + } + int dummig; + VirtText jtem = parse_virt_text(a.items[j].data.array, err, &dummig); + kv_push(virt_lines, jtem); + if (ERROR_SET(err)) { + goto error; + } + } + } else if (strequal("virt_lines_above", k.data)) { + virt_lines_above = api_object_to_bool(*v, "virt_lines_above", false, err); + if (ERROR_SET(err)) { + goto error; + } + } else if (strequal("virt_lines_leftcol", k.data)) { + virt_lines_leftcol = api_object_to_bool(*v, "virt_lines_leftcol", false, err); + if (ERROR_SET(err)) { + goto error; + } } else if (strequal("hl_eol", k.data)) { decor.hl_eol = api_object_to_bool(*v, "hl_eol", false, err); if (ERROR_SET(err)) { @@ -1721,9 +1777,23 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer goto error; } - id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col, - line2, col2, d, right_gravity, - end_right_gravity, kExtmarkNoUndo); + if (kv_size(virt_lines) && buf->b_virt_line_mark) { + mtpos_t pos = marktree_lookup(buf->b_marktree, buf->b_virt_line_mark, NULL); + clear_virt_lines(buf, pos.row); // handles pos.row == -1 + } + + uint64_t mark = extmark_set(buf, (uint64_t)ns_id, &id, (int)line, (colnr_T)col, + line2, col2, d, right_gravity, + end_right_gravity, kExtmarkNoUndo); + + if (kv_size(virt_lines)) { + buf->b_virt_lines = virt_lines; + buf->b_virt_line_mark = mark; + buf->b_virt_line_pos = -1; + buf->b_virt_line_above = virt_lines_above; + buf->b_virt_line_leftcol = virt_lines_leftcol; + redraw_buf_line_later(buf, MIN(buf->b_ml.ml_line_count, line+1+(virt_lines_above?0:1))); + } } return (Integer)id; @@ -1827,7 +1897,7 @@ Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, In end_line++; } - extmark_set(buf, ns, 0, + extmark_set(buf, ns, NULL, (int)line, (colnr_T)col_start, end_line, (colnr_T)col_end, decor_hl(hl_id), true, false, kExtmarkNoUndo); -- cgit