aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api
diff options
context:
space:
mode:
authorBjörn Linse <bjorn.linse@gmail.com>2021-07-29 22:25:43 +0200
committerGitHub <noreply@github.com>2021-07-29 22:25:43 +0200
commitb73e733d529266ef350f71fa896d16e44cc83f78 (patch)
tree2ecd8cba6958a7576f2ea37e6736f2d2440d7c4d /src/nvim/api
parent3521bf7672d2a33e60e2656043374a1584a0285b (diff)
parent25a879dfa2f0795d610833c9552ca48f0cab95fa (diff)
downloadrneovim-b73e733d529266ef350f71fa896d16e44cc83f78.tar.gz
rneovim-b73e733d529266ef350f71fa896d16e44cc83f78.tar.bz2
rneovim-b73e733d529266ef350f71fa896d16e44cc83f78.zip
Merge pull request #15184 from bfredl/sunjonhl
feat(decorations): allow more than one stacked highlight in a virt_text
Diffstat (limited to 'src/nvim/api')
-rw-r--r--src/nvim/api/buffer.c87
-rw-r--r--src/nvim/api/deprecated.c82
-rw-r--r--src/nvim/api/private/helpers.c35
3 files changed, 120 insertions, 84 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 78e36e5ef0..77cff0cb4f 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -1433,8 +1433,14 @@ 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:
+/// 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.
@@ -1560,7 +1566,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;
}
@@ -1892,80 +1899,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".
diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c
index 3989386bb9..554966e266 100644
--- a/src/nvim/api/deprecated.c
+++ b/src/nvim/api/deprecated.c
@@ -12,6 +12,7 @@
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/defs.h"
#include "nvim/lua/executor.h"
+#include "nvim/extmark.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/deprecated.c.generated.h"
@@ -80,6 +81,87 @@ void nvim_buf_clear_highlight(Buffer buffer,
}
+/// Set the virtual text (annotation) for a buffer line.
+///
+/// @deprecated use nvim_buf_set_extmark to use full virtual text
+/// functionality.
+///
+/// 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)
+ FUNC_API_DEPRECATED_SINCE(8)
+{
+ 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);
+ int width;
+
+ VirtText virt_text = parse_virt_text(chunks, err, &width);
+ if (ERROR_SET(err)) {
+ return 0;
+ }
+
+
+ Decoration *existing = decor_find_virttext(buf, (int)line, ns_id);
+
+ if (existing) {
+ clear_virttext(&existing->virt_text);
+ existing->virt_text = virt_text;
+ existing->virt_text_width = width;
+ return src_id;
+ }
+
+ Decoration *decor = xcalloc(1, sizeof(*decor));
+ decor->virt_text = virt_text;
+ decor->virt_text_width = width;
+
+ extmark_set(buf, ns_id, 0, (int)line, 0, -1, -1, decor, true,
+ false, kExtmarkNoUndo);
+ return src_id;
+}
+
/// Inserts a sequence of lines to a buffer at a certain index
///
/// @deprecated use nvim_buf_set_lines(buffer, lnum, lnum, true, lines)
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 9f2e94f31e..5a8c5de35c 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -1592,9 +1592,10 @@ bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, int
}
}
-VirtText parse_virt_text(Array chunks, Error *err)
+VirtText parse_virt_text(Array chunks, Error *err, int *width)
{
VirtText virt_text = KV_INITIAL_VALUE;
+ int w = 0;
for (size_t i = 0; i < chunks.size; i++) {
if (chunks.items[i].type != kObjectTypeArray) {
api_set_error(err, kErrorTypeValidation, "Chunk is not an array");
@@ -1603,25 +1604,44 @@ VirtText parse_virt_text(Array chunks, Error *err)
Array chunk = chunks.items[i].data.array;
if (chunk.size == 0 || chunk.size > 2
|| chunk.items[0].type != kObjectTypeString
- || (chunk.size == 2 && chunk.items[1].type != kObjectTypeString)) {
+ || chunk.size > 2) {
api_set_error(err, kErrorTypeValidation,
"Chunk is not an array with one or two strings");
goto free_exit;
}
String str = chunk.items[0].data.string;
- char *text = transstr(str.size > 0 ? str.data : ""); // allocates
int hl_id = 0;
if (chunk.size == 2) {
- String hl = chunk.items[1].data.string;
- if (hl.size > 0) {
- hl_id = syn_check_group((char_u *)hl.data, (int)hl.size);
+ Object hl = chunk.items[1];
+ if (hl.type == kObjectTypeArray) {
+ Array arr = hl.data.array;
+ for (size_t j = 0; j < arr.size; j++) {
+ hl_id = object_to_hl_id(arr.items[j], "virt_text highlight", err);
+ if (ERROR_SET(err)) {
+ goto free_exit;
+ }
+ if (j < arr.size-1) {
+ kv_push(virt_text, ((VirtTextChunk){ .text = NULL,
+ .hl_id = hl_id }));
+ }
+ }
+ } else {
+ hl_id = object_to_hl_id(hl, "virt_text highlight", err);
+ if (ERROR_SET(err)) {
+ goto free_exit;
+ }
}
}
+
+ char *text = transstr(str.size > 0 ? str.data : ""); // allocates
+ w += (int)mb_string2cells((char_u *)text);
+
kv_push(virt_text, ((VirtTextChunk){ .text = text, .hl_id = hl_id }));
}
+ *width = w;
return virt_text;
free_exit:
@@ -1656,7 +1676,7 @@ int object_to_hl_id(Object obj, const char *what, Error *err)
String str = obj.data.string;
return str.size ? syn_check_group((char_u *)str.data, (int)str.size) : 0;
} else if (obj.type == kObjectTypeInteger) {
- return (int)obj.data.integer;
+ return MAX((int)obj.data.integer, 0);
} else {
api_set_error(err, kErrorTypeValidation,
"%s is not a valid highlight", what);
@@ -1687,6 +1707,7 @@ HlMessage parse_hl_msg(Array chunks, Error *err)
if (chunk.size == 2) {
String hl = chunk.items[1].data.string;
if (hl.size > 0) {
+ // TODO(bfredl): use object_to_hl_id and allow integer
int hl_id = syn_check_group((char_u *)hl.data, (int)hl.size);
attr = hl_id > 0 ? syn_id2attr(hl_id) : 0;
}