aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/api/buffer.c')
-rw-r--r--src/nvim/api/buffer.c357
1 files changed, 164 insertions, 193 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index b371c08d2a..0ef2776263 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -3,40 +3,39 @@
// Some of this code was adapted from 'if_py_both.h' from the original
// vim source
+#include <lauxlib.h>
+#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
-#include <limits.h>
-
-#include <lauxlib.h>
#include "nvim/api/buffer.h"
-#include "nvim/api/private/helpers.h"
#include "nvim/api/private/defs.h"
-#include "nvim/lua/executor.h"
-#include "nvim/vim.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/buffer.h"
+#include "nvim/buffer_updates.h"
#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
+#include "nvim/decoration.h"
+#include "nvim/ex_cmds.h"
+#include "nvim/ex_docmd.h"
+#include "nvim/extmark.h"
+#include "nvim/fileio.h"
#include "nvim/getchar.h"
+#include "nvim/lua/executor.h"
+#include "nvim/map.h"
+#include "nvim/map_defs.h"
+#include "nvim/mark.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/misc1.h"
-#include "nvim/ex_cmds.h"
-#include "nvim/map_defs.h"
-#include "nvim/map.h"
-#include "nvim/mark.h"
-#include "nvim/ops.h"
-#include "nvim/extmark.h"
-#include "nvim/decoration.h"
-#include "nvim/fileio.h"
#include "nvim/move.h"
+#include "nvim/ops.h"
#include "nvim/syntax.h"
-#include "nvim/window.h"
#include "nvim/undo.h"
-#include "nvim/ex_docmd.h"
-#include "nvim/buffer_updates.h"
+#include "nvim/vim.h"
+#include "nvim/window.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/buffer.c.generated.h"
@@ -149,11 +148,8 @@ Integer nvim_buf_line_count(Buffer buffer, Error *err)
/// @param[out] err Error details, if any
/// @return False if attach failed (invalid parameter, or buffer isn't loaded);
/// otherwise True. TODO: LUA_API_NO_EVAL
-Boolean nvim_buf_attach(uint64_t channel_id,
- Buffer buffer,
- Boolean send_buffer,
- DictionaryOf(LuaRef) opts,
- Error *err)
+Boolean nvim_buf_attach(uint64_t channel_id, Buffer buffer, Boolean send_buffer,
+ DictionaryOf(LuaRef) opts, Error *err)
FUNC_API_SINCE(4)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -237,9 +233,7 @@ error:
/// @param[out] err Error details, if any
/// @return False if detach failed (because the buffer isn't loaded);
/// otherwise True.
-Boolean nvim_buf_detach(uint64_t channel_id,
- Buffer buffer,
- Error *err)
+Boolean nvim_buf_detach(uint64_t channel_id, Buffer buffer, Error *err)
FUNC_API_SINCE(4) FUNC_API_REMOTE_ONLY
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -252,8 +246,7 @@ Boolean nvim_buf_detach(uint64_t channel_id,
return true;
}
-void nvim__buf_redraw_range(Buffer buffer, Integer first, Integer last,
- Error *err)
+void nvim__buf_redraw_range(Buffer buffer, Integer first, Integer last, Error *err)
FUNC_API_LUA_ONLY
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -315,7 +308,7 @@ ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id,
}
rv.size = (size_t)(end - start);
- rv.items = xcalloc(sizeof(Object), rv.size);
+ rv.items = xcalloc(rv.size, sizeof(Object));
if (!buf_collect_lines(buf, rv.size, start,
(channel_id != VIML_INTERNAL_CALL), &rv, err)) {
@@ -376,13 +369,8 @@ static bool check_string_array(Array arr, bool disallow_nl, Error *err)
/// @param strict_indexing Whether out-of-bounds should be an error.
/// @param replacement Array of lines to use as replacement
/// @param[out] err Error details, if any
-void nvim_buf_set_lines(uint64_t channel_id,
- Buffer buffer,
- Integer start,
- Integer end,
- Boolean strict_indexing,
- ArrayOf(String) replacement,
- Error *err)
+void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integer end,
+ Boolean strict_indexing, ArrayOf(String) replacement, Error *err)
FUNC_API_SINCE(1)
FUNC_API_CHECK_TEXTLOCK
{
@@ -554,10 +542,8 @@ end:
/// @param end_column Last column
/// @param replacement Array of lines to use as replacement
/// @param[out] err Error details, if any
-void nvim_buf_set_text(uint64_t channel_id, Buffer buffer,
- Integer start_row, Integer start_col,
- Integer end_row, Integer end_col,
- ArrayOf(String) replacement, Error *err)
+void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, Integer start_col,
+ Integer end_row, Integer end_col, ArrayOf(String) replacement, Error *err)
FUNC_API_SINCE(7)
{
FIXED_TEMP_ARRAY(scratch, 1);
@@ -617,17 +603,17 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer,
// calculate byte size of old region before it gets modified/deleted
if (start_row == end_row) {
- old_byte = (bcount_t)end_col - start_col;
+ old_byte = (bcount_t)end_col - start_col;
} else {
- const char *bufline;
- old_byte += (bcount_t)strlen(str_at_start) - start_col;
- for (int64_t i = 1; i < end_row - start_row; i++) {
- int64_t lnum = start_row + i;
+ const char *bufline;
+ old_byte += (bcount_t)strlen(str_at_start) - start_col;
+ for (int64_t i = 1; i < end_row - start_row; i++) {
+ int64_t lnum = start_row + i;
- bufline = (char *)ml_get_buf(buf, lnum, false);
- old_byte += (bcount_t)(strlen(bufline))+1;
- }
- old_byte += (bcount_t)end_col+1;
+ bufline = (char *)ml_get_buf(buf, lnum, false);
+ old_byte += (bcount_t)(strlen(bufline))+1;
+ }
+ old_byte += (bcount_t)end_col+1;
}
String first_item = replacement.items[0].data.string;
@@ -824,7 +810,7 @@ Object nvim_buf_get_var(Buffer buffer, String name, Error *err)
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
- return (Object) OBJECT_INIT;
+ return (Object)OBJECT_INIT;
}
return dict_get_value(buf->b_vars, name, err);
@@ -872,8 +858,8 @@ ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err)
/// @see |nvim_set_keymap()|
///
/// @param buffer Buffer handle, or 0 for current buffer
-void nvim_buf_set_keymap(Buffer buffer, String mode, String lhs, String rhs,
- Dictionary opts, Error *err)
+void nvim_buf_set_keymap(Buffer buffer, String mode, String lhs, String rhs, Dictionary opts,
+ Error *err)
FUNC_API_SINCE(6)
{
modify_keymap(buffer, false, mode, lhs, rhs, opts, err);
@@ -980,7 +966,7 @@ Object nvim_buf_get_option(Buffer buffer, String name, Error *err)
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
- return (Object) OBJECT_INIT;
+ return (Object)OBJECT_INIT;
}
return get_option_from(buf, SREQ_BUF, name, err);
@@ -994,8 +980,7 @@ Object nvim_buf_get_option(Buffer buffer, String name, Error *err)
/// @param name Option name
/// @param value Option value
/// @param[out] err Error details, if any
-void nvim_buf_set_option(uint64_t channel_id, Buffer buffer,
- String name, Object value, Error *err)
+void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, String name, Object value, Error *err)
FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -1044,7 +1029,7 @@ void nvim_buf_set_name(Buffer buffer, String name, Error *err)
// Using aucmd_*: autocommands will be executed by rename_buffer
aco_save_T aco;
aucmd_prepbuf(&aco, buf);
- int ren_ret = rename_buffer((char_u *) name.data);
+ int ren_ret = rename_buffer((char_u *)name.data);
aucmd_restbuf(&aco);
if (try_end(err)) {
@@ -1105,12 +1090,11 @@ void nvim_buf_delete(Buffer buffer, Dictionary opts, Error *err)
return;
}
- int result = do_buffer(
- unload ? DOBUF_UNLOAD : DOBUF_WIPE,
- DOBUF_FIRST,
- FORWARD,
- buf->handle,
- force);
+ int result = do_buffer(unload ? DOBUF_UNLOAD : DOBUF_WIPE,
+ DOBUF_FIRST,
+ FORWARD,
+ buf->handle,
+ force);
if (result == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to unload buffer.");
@@ -1213,8 +1197,7 @@ static Array extmark_to_array(ExtmarkInfo extmark, bool id, bool add_dict)
ADD(chunk, STRING_OBJ(cstr_to_string(vtc->text)));
if (vtc->hl_id > 0) {
ADD(chunk,
- STRING_OBJ(cstr_to_string(
- (const char *)syn_id2name(vtc->hl_id))));
+ STRING_OBJ(cstr_to_string((const char *)syn_id2name(vtc->hl_id))));
}
ADD(chunks, ARRAY_OBJ(chunk));
}
@@ -1232,7 +1215,7 @@ static Array extmark_to_array(ExtmarkInfo extmark, bool id, bool add_dict)
return rv;
}
-/// Returns position for a given extmark id
+/// Gets the position (0-indexed) of an extmark.
///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param ns_id Namespace id from |nvim_create_namespace()|
@@ -1240,7 +1223,8 @@ static Array extmark_to_array(ExtmarkInfo extmark, bool id, bool add_dict)
/// @param opts Optional parameters. Keys:
/// - details: Whether to include the details dict
/// @param[out] err Error details, if any
-/// @return (row, col) tuple or empty list () if extmark id was absent
+/// @return 0-indexed (row, col) tuple or empty list () if extmark id was
+/// absent
ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
Integer id, Dictionary opts,
Error *err)
@@ -1320,18 +1304,17 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param ns_id Namespace id from |nvim_create_namespace()|
-/// @param start Start of range, given as (row, col) or valid extmark id
-/// (whose position defines the bound)
-/// @param end End of range, given as (row, col) or valid extmark id
-/// (whose position defines the bound)
+/// @param start Start of range: a 0-indexed (row, col) or valid extmark id
+/// (whose position defines the bound). |api-indexing|
+/// @param end End of range (inclusive): a 0-indexed (row, col) or valid
+/// extmark id (whose position defines the bound). |api-indexing|
/// @param opts Optional parameters. Keys:
/// - limit: Maximum number of marks to return
/// - details Whether to include the details dict
/// @param[out] err Error details, if any
/// @return List of [extmark_id, row, col] tuples in "traversal order".
-Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
- Object start, Object end,
- Dictionary opts, Error *err)
+Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object end, Dictionary opts,
+ Error *err)
FUNC_API_SINCE(7)
{
Array rv = ARRAY_DICT_INIT;
@@ -1424,17 +1407,27 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param ns_id Namespace id from |nvim_create_namespace()|
-/// @param line Line where to place the mark, 0-based
-/// @param col Column where to place the mark, 0-based
+/// @param line Line where to place the mark, 0-based. |api-indexing|
+/// @param col Column where to place the mark, 0-based. |api-indexing|
/// @param opts Optional parameters.
/// - id : id of the extmark to edit.
/// - end_line : ending line of the mark, 0-based inclusive.
/// - 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.
-/// - 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.
@@ -1453,10 +1446,28 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
/// 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
@@ -1473,14 +1484,12 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
/// example treesitter highlighting uses a value of 100.
/// @param[out] err Error details, if any
/// @return Id of the created/updated extmark
-Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
- Integer line, Integer col,
+Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer col,
Dictionary opts, Error *err)
FUNC_API_SINCE(7)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
- api_set_error(err, kErrorTypeValidation, "Invalid buffer id");
return 0;
}
@@ -1500,6 +1509,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
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;
@@ -1540,19 +1553,18 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
} else if (strequal("hl_group", k.data)) {
String hl_group;
switch (v->type) {
- case kObjectTypeString:
- hl_group = v->data.string;
- decor.hl_id = syn_check_group(
- (char_u *)(hl_group.data),
- (int)hl_group.size);
- break;
- case kObjectTypeInteger:
- decor.hl_id = (int)v->data.integer;
- break;
- default:
- api_set_error(err, kErrorTypeValidation,
- "hl_group is not valid.");
- goto error;
+ case kObjectTypeString:
+ hl_group = v->data.string;
+ decor.hl_id = syn_check_group((char_u *)(hl_group.data),
+ (int)hl_group.size);
+ break;
+ case kObjectTypeInteger:
+ decor.hl_id = (int)v->data.integer;
+ break;
+ default:
+ api_set_error(err, kErrorTypeValidation,
+ "hl_group is not valid.");
+ goto error;
}
} else if (strequal("virt_text", k.data)) {
if (v->type != kObjectTypeArray) {
@@ -1560,7 +1572,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
"virt_text is not an Array");
goto error;
}
- decor.virt_text = parse_virt_text(v->data.array, err);
+ decor.virt_text = parse_virt_text(v->data.array, err,
+ &decor.virt_text_width);
if (ERROR_SET(err)) {
goto error;
}
@@ -1597,6 +1610,36 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
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)) {
@@ -1685,8 +1728,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
if (col2 >= 0) {
if (line2 >= 0 && line2 < buf->b_ml.ml_line_count) {
- len = ephemeral ? MAXCOL : STRLEN(
- ml_get_buf(buf, (linenr_T)line2 + 1, false));
+ len = ephemeral ? MAXCOL : STRLEN(ml_get_buf(buf, (linenr_T)line2 + 1, false));
} else if (line2 == buf->b_ml.ml_line_count) {
// We are trying to add an extmark past final newline
len = 0;
@@ -1706,7 +1748,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
decor.col = 0;
for (size_t i = 0; i < kv_size(decor.virt_text); i++) {
decor.col
- += (int)mb_string2cells((char_u *)kv_A(decor.virt_text, i).text);
+ += (int)mb_string2cells((char_u *)kv_A(decor.virt_text, i).text);
}
}
@@ -1735,9 +1777,23 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
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;
@@ -1754,10 +1810,7 @@ error:
/// @param id Extmark id
/// @param[out] err Error details, if any
/// @return true if the extmark was found, else false
-Boolean nvim_buf_del_extmark(Buffer buffer,
- Integer ns_id,
- Integer id,
- Error *err)
+Boolean nvim_buf_del_extmark(Buffer buffer, Integer ns_id, Integer id, Error *err)
FUNC_API_SINCE(7)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -1803,13 +1856,8 @@ Boolean nvim_buf_del_extmark(Buffer buffer,
/// or -1 to highlight to end of line
/// @param[out] err Error details, if any
/// @return The ns_id that was used
-Integer nvim_buf_add_highlight(Buffer buffer,
- Integer ns_id,
- String hl_group,
- Integer line,
- Integer col_start,
- Integer col_end,
- Error *err)
+Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, Integer line,
+ Integer col_start, Integer col_end, Error *err)
FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -1849,7 +1897,7 @@ Integer nvim_buf_add_highlight(Buffer buffer,
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);
@@ -1868,10 +1916,7 @@ Integer nvim_buf_add_highlight(Buffer buffer,
/// @param line_end End of range of lines to clear (exclusive) or -1 to clear
/// to end of buffer.
/// @param[out] err Error details, if any
-void nvim_buf_clear_namespace(Buffer buffer,
- Integer ns_id,
- Integer line_start,
- Integer line_end,
+void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, Integer line_end,
Error *err)
FUNC_API_SINCE(5)
{
@@ -1892,80 +1937,6 @@ void nvim_buf_clear_namespace(Buffer buffer,
(int)line_end-1, MAXCOL);
}
-/// Set the virtual text (annotation) for a buffer line.
-///
-/// By default (and currently the only option) the text will be placed after
-/// the buffer text. Virtual text will never cause reflow, rather virtual
-/// text will be truncated at the end of the screen line. The virtual text will
-/// begin one cell (|lcs-eol| or space) after the ordinary text.
-///
-/// Namespaces are used to support batch deletion/updating of virtual text.
-/// To create a namespace, use |nvim_create_namespace()|. Virtual text is
-/// cleared using |nvim_buf_clear_namespace()|. The same `ns_id` can be used for
-/// both virtual text and highlights added by |nvim_buf_add_highlight()|, both
-/// can then be cleared with a single call to |nvim_buf_clear_namespace()|. If
-/// the virtual text never will be cleared by an API call, pass `ns_id = -1`.
-///
-/// As a shorthand, `ns_id = 0` can be used to create a new namespace for the
-/// virtual text, the allocated id is then returned.
-///
-/// @param buffer Buffer handle, or 0 for current buffer
-/// @param ns_id Namespace to use or 0 to create a namespace,
-/// or -1 for a ungrouped annotation
-/// @param line Line to annotate with virtual text (zero-indexed)
-/// @param chunks A list of [text, hl_group] arrays, each representing a
-/// text chunk with specified highlight. `hl_group` element
-/// can be omitted for no highlight.
-/// @param opts Optional parameters. Currently not used.
-/// @param[out] err Error details, if any
-/// @return The ns_id that was used
-Integer nvim_buf_set_virtual_text(Buffer buffer,
- Integer src_id,
- Integer line,
- Array chunks,
- Dictionary opts,
- Error *err)
- FUNC_API_SINCE(5)
-{
- buf_T *buf = find_buffer_by_handle(buffer, err);
- if (!buf) {
- return 0;
- }
-
- if (line < 0 || line >= MAXLNUM) {
- api_set_error(err, kErrorTypeValidation, "Line number outside range");
- return 0;
- }
-
- if (opts.size > 0) {
- api_set_error(err, kErrorTypeValidation, "opts dict isn't empty");
- return 0;
- }
-
- uint64_t ns_id = src2ns(&src_id);
-
- VirtText virt_text = parse_virt_text(chunks, err);
- if (ERROR_SET(err)) {
- return 0;
- }
-
-
- VirtText *existing = decor_find_virttext(buf, (int)line, ns_id);
-
- if (existing) {
- clear_virttext(existing);
- *existing = virt_text;
- return src_id;
- }
-
- Decoration *decor = xcalloc(1, sizeof(*decor));
- decor->virt_text = virt_text;
-
- extmark_set(buf, ns_id, 0, (int)line, 0, -1, -1, decor, true,
- false, kExtmarkNoUndo);
- return src_id;
-}
-
/// call a function with buffer as temporary current buffer
///
/// This temporarily switches current buffer to "buffer".