This commit is contained in:
Björn Linse 2020-09-04 21:33:25 +02:00
parent 4d3ef578e9
commit 18a3a89822
4 changed files with 122 additions and 55 deletions

View File

@ -1664,43 +1664,6 @@ void nvim_buf_clear_highlight(Buffer buffer,
nvim_buf_clear_namespace(buffer, ns_id, line_start, line_end, err);
}
static VirtText parse_virt_text(Array chunks, Error *err)
{
VirtText virt_text = KV_INITIAL_VALUE;
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");
goto free_exit;
}
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)) {
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);
}
}
kv_push(virt_text, ((VirtTextChunk){ .text = text, .hl_id = hl_id }));
}
return virt_text;
free_exit:
clear_virttext(&virt_text);
return virt_text;
}
/// Set the virtual text (annotation) for a buffer line.
///

View File

@ -15,6 +15,8 @@
#include "nvim/lua/executor.h"
#include "nvim/ascii.h"
#include "nvim/assert.h"
#include "nvim/charset.h"
#include "nvim/syntax.h"
#include "nvim/vim.h"
#include "nvim/buffer.h"
#include "nvim/window.h"
@ -1579,3 +1581,40 @@ bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, int
return false;
}
}
VirtText parse_virt_text(Array chunks, Error *err)
{
VirtText virt_text = KV_INITIAL_VALUE;
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");
goto free_exit;
}
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)) {
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);
}
}
kv_push(virt_text, ((VirtTextChunk){ .text = text, .hl_id = hl_id }));
}
return virt_text;
free_exit:
clear_virttext(&virt_text);
return virt_text;
}

View File

@ -2610,22 +2610,91 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Error *err)
/// interface should probably be derived from a reformed
/// bufhl/virttext interface with full support for multi-line
/// ranges etc
void nvim__put_attr(Integer id, Integer start_row, Integer start_col,
Integer end_row, Integer end_col)
void nvim__put_attr(Integer line, Integer col, Dictionary opts, Error *err)
FUNC_API_LUA_ONLY
{
if (!lua_attr_active) {
return;
}
if (id == 0 || syn_get_final_id((int)id) == 0) {
int line2 = -1, hl_id = 0;
colnr_T col2 = 0;
VirtText virt_text = KV_INITIAL_VALUE;
for (size_t i = 0; i < opts.size; i++) {
String k = opts.items[i].key;
Object *v = &opts.items[i].value;
if (strequal("end_line", k.data)) {
if (v->type != kObjectTypeInteger) {
api_set_error(err, kErrorTypeValidation,
"end_line is not an integer");
goto error;
}
if (v->data.integer < 0) {
api_set_error(err, kErrorTypeValidation,
"end_line value outside range");
goto error;
}
line2 = (int)v->data.integer;
} else if (strequal("end_col", k.data)) {
if (v->type != kObjectTypeInteger) {
api_set_error(err, kErrorTypeValidation,
"end_col is not an integer");
goto error;
}
if (v->data.integer < 0 || v->data.integer > MAXCOL) {
api_set_error(err, kErrorTypeValidation,
"end_col value outside range");
goto error;
}
col2 = (colnr_T)v->data.integer;
} else if (strequal("hl_group", k.data)) {
String hl_group;
switch (v->type) {
case kObjectTypeString:
hl_group = v->data.string;
hl_id = syn_check_group(
(char_u *)(hl_group.data),
(int)hl_group.size);
break;
case kObjectTypeInteger:
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) {
api_set_error(err, kErrorTypeValidation,
"virt_text is not an Array");
goto error;
}
virt_text = parse_virt_text(v->data.array, err);
if (ERROR_SET(err)) {
goto error;
}
} else {
api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
goto error;
}
}
if (col2 && line2 < 0) {
line2 = (int)line;
}
int attr = hl_id ? syn_id2attr((int)hl_id) : 0;
if (attr == 0 && !kv_size(virt_text)) {
return;
}
int attr = syn_id2attr((int)id);
if (attr == 0) {
return;
}
decorations_add_luahl_attr(attr, (int)start_row, (colnr_T)start_col,
(int)end_row, (colnr_T)end_col);
VirtText *v = xmalloc(sizeof(*v));
*v = virt_text; // LeakSanitizer be sad
decorations_add_luahl_attr(attr, (int)line, (colnr_T)col,
(int)line2, (colnr_T)col2, v);
error:
return;
}
void nvim__screenshot(String path)

View File

@ -639,10 +639,11 @@ bool decorations_active = false;
void decorations_add_luahl_attr(int attr_id,
int start_row, int start_col,
int end_row, int end_col)
int end_row, int end_col, VirtText *virt_text)
{
kv_push(decorations.active,
((HlRange){ start_row, start_col, end_row, end_col, attr_id, NULL }));
((HlRange){ start_row, start_col,
end_row, end_col, attr_id, virt_text }));
}
/*
@ -2356,14 +2357,9 @@ win_line (
args.items[2] = INTEGER_OBJ(lnum-1);
lua_attr_active = true;
extra_check = true;
Object o = nlua_call_ref(buf->b_luahl_line, "line", args, true, &err);
nlua_call_ref(buf->b_luahl_line, "line", args, false, &err);
lua_attr_active = false;
if (o.type == kObjectTypeString) {
// TODO(bfredl): this is a bit of a hack. A final API should use an
// "unified" interface where luahl can add both bufhl and virttext
luatext = o.data.string.data;
do_virttext = true;
} else if (ERROR_SET(&err)) {
if (ERROR_SET(&err)) {
ELOG("error in luahl line: %s", err.msg);
luatext = err.msg;
do_virttext = true;