From 18a3a8982288fc41fd902e412d624071e79fc627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Linse?= Date: Fri, 4 Sep 2020 21:33:25 +0200 Subject: [PATCH] luahl --- src/nvim/api/buffer.c | 37 --------------- src/nvim/api/private/helpers.c | 39 +++++++++++++++ src/nvim/api/vim.c | 87 ++++++++++++++++++++++++++++++---- src/nvim/screen.c | 14 ++---- 4 files changed, 122 insertions(+), 55 deletions(-) diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 15065760b3..e58035b6c7 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -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. /// diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 13f77d2d85..f1ecd732ee 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -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; +} diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 9155ffcfb8..cb5d1e1f77 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -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) diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 3c2e1ccaf5..ca1c4589f8 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -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;