mirror of
https://github.com/neovim/neovim.git
synced 2025-09-10 05:18:16 +00:00
decor: sketch new decorations API
return decorations back lol no nvim_buf_get_virtual_text share decorations that are hl only to avoid alloc avalanche
This commit is contained in:

committed by
Thomas Vigouroux

parent
d3302573ba
commit
49f5b57587
@@ -1108,15 +1108,65 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static Array extmark_to_array(ExtmarkInfo extmark, bool id, bool add_dict)
|
||||
{
|
||||
Array rv = ARRAY_DICT_INIT;
|
||||
if (id) {
|
||||
ADD(rv, INTEGER_OBJ((Integer)extmark.mark_id));
|
||||
}
|
||||
ADD(rv, INTEGER_OBJ(extmark.row));
|
||||
ADD(rv, INTEGER_OBJ(extmark.col));
|
||||
|
||||
if (add_dict) {
|
||||
Dictionary dict = ARRAY_DICT_INIT;
|
||||
|
||||
if (extmark.end_row >= 0) {
|
||||
PUT(dict, "end_row", INTEGER_OBJ(extmark.end_row));
|
||||
PUT(dict, "end_col", INTEGER_OBJ(extmark.end_col));
|
||||
}
|
||||
|
||||
if (extmark.decor) {
|
||||
Decoration *decor = extmark.decor;
|
||||
if (decor->hl_id) {
|
||||
String name = cstr_to_string((const char *)syn_id2name(decor->hl_id));
|
||||
PUT(dict, "hl_group", STRING_OBJ(name));
|
||||
}
|
||||
if (kv_size(decor->virt_text)) {
|
||||
Array chunks = ARRAY_DICT_INIT;
|
||||
for (size_t i = 0; i < decor->virt_text.size; i++) {
|
||||
Array chunk = ARRAY_DICT_INIT;
|
||||
VirtTextChunk *vtc = &decor->virt_text.items[i];
|
||||
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))));
|
||||
}
|
||||
ADD(chunks, ARRAY_OBJ(chunk));
|
||||
}
|
||||
PUT(dict, "virt_text", ARRAY_OBJ(chunks));
|
||||
}
|
||||
}
|
||||
|
||||
if (dict.size) {
|
||||
ADD(rv, DICTIONARY_OBJ(dict));
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/// Returns position for a given extmark id
|
||||
///
|
||||
/// @param buffer Buffer handle, or 0 for current buffer
|
||||
/// @param ns_id Namespace id from |nvim_create_namespace()|
|
||||
/// @param id Extmark id
|
||||
/// @param details Wether to include the details dict
|
||||
/// @param[out] err Error details, if any
|
||||
/// @return (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, Error *err)
|
||||
Integer id, Boolean details,
|
||||
Error *err)
|
||||
FUNC_API_SINCE(7)
|
||||
{
|
||||
Array rv = ARRAY_DICT_INIT;
|
||||
@@ -1136,9 +1186,7 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
|
||||
if (extmark.row < 0) {
|
||||
return rv;
|
||||
}
|
||||
ADD(rv, INTEGER_OBJ((Integer)extmark.row));
|
||||
ADD(rv, INTEGER_OBJ((Integer)extmark.col));
|
||||
return rv;
|
||||
return extmark_to_array(extmark, false, (bool)details);
|
||||
}
|
||||
|
||||
/// Gets extmarks in "traversal order" from a |charwise| region defined by
|
||||
@@ -1181,10 +1229,13 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
|
||||
/// (whose position defines the bound)
|
||||
/// @param opts Optional parameters. Keys:
|
||||
/// - limit: Maximum number of marks to return
|
||||
/// @param details Wether 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, Boolean details,
|
||||
Error *err)
|
||||
FUNC_API_SINCE(7)
|
||||
{
|
||||
Array rv = ARRAY_DICT_INIT;
|
||||
@@ -1241,16 +1292,11 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start,
|
||||
}
|
||||
|
||||
|
||||
ExtmarkArray marks = extmark_get(buf, (uint64_t)ns_id, l_row, l_col, u_row,
|
||||
u_col, (int64_t)limit, reverse);
|
||||
ExtmarkInfoArray marks = extmark_get(buf, (uint64_t)ns_id, l_row, l_col,
|
||||
u_row, u_col, (int64_t)limit, reverse);
|
||||
|
||||
for (size_t i = 0; i < kv_size(marks); i++) {
|
||||
Array mark = ARRAY_DICT_INIT;
|
||||
ExtmarkInfo extmark = kv_A(marks, i);
|
||||
ADD(mark, INTEGER_OBJ((Integer)extmark.mark_id));
|
||||
ADD(mark, INTEGER_OBJ(extmark.row));
|
||||
ADD(mark, INTEGER_OBJ(extmark.col));
|
||||
ADD(rv, ARRAY_OBJ(mark));
|
||||
ADD(rv, ARRAY_OBJ(extmark_to_array(kv_A(marks, i), true, (bool)details)));
|
||||
}
|
||||
|
||||
kv_destroy(marks);
|
||||
@@ -1260,18 +1306,26 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start,
|
||||
/// Creates or updates an extmark.
|
||||
///
|
||||
/// To create a new extmark, pass id=0. The extmark id will be returned.
|
||||
// To move an existing mark, pass its id.
|
||||
/// To move an existing mark, pass its id.
|
||||
///
|
||||
/// It is also allowed to create a new mark by passing in a previously unused
|
||||
/// id, but the caller must then keep track of existing and unused ids itself.
|
||||
/// (Useful over RPC, to avoid waiting for the return value.)
|
||||
///
|
||||
/// Using the optional arguments, it is possible to use this to highlight
|
||||
/// a range of text, and also to associate virtual text to the mark.
|
||||
///
|
||||
/// @param buffer Buffer handle, or 0 for current buffer
|
||||
/// @param ns_id Namespace id from |nvim_create_namespace()|
|
||||
/// @param id Extmark id, or 0 to create new
|
||||
/// @param line Line number where to place the mark
|
||||
/// @param col Column where to place the mark
|
||||
/// @param opts Optional parameters. Currently not used.
|
||||
/// @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 inclusive.
|
||||
/// - hl_group : name of the highlight group used to highlight
|
||||
/// this mark.
|
||||
/// - virt_text : virtual text to link to this mark.
|
||||
/// @param[out] err Error details, if any
|
||||
/// @return Id of the created/updated extmark
|
||||
Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
|
||||
@@ -1281,6 +1335,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
|
||||
{
|
||||
buf_T *buf = find_buffer_by_handle(buffer, err);
|
||||
if (!buf) {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid buffer id");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1305,6 +1360,9 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
|
||||
}
|
||||
|
||||
uint64_t 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;
|
||||
@@ -1316,19 +1374,97 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
|
||||
}
|
||||
|
||||
id = (uint64_t)v->data.integer;
|
||||
} else 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 || v->data.integer > buf->b_ml.ml_line_count) {
|
||||
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 >= 0) {
|
||||
if (line2 >= 0) {
|
||||
len = STRLEN(ml_get_buf(buf, (linenr_T)line2+1, false));
|
||||
} else {
|
||||
// reuse len from before
|
||||
line2 = (int)line;
|
||||
}
|
||||
if (col2 > (Integer)len) {
|
||||
api_set_error(err, kErrorTypeValidation,
|
||||
"end_col value outside range");
|
||||
goto error;
|
||||
}
|
||||
} else if (line2 >= 0) {
|
||||
col2 = 0;
|
||||
}
|
||||
|
||||
Decoration *decor = NULL;
|
||||
if (kv_size(virt_text)) {
|
||||
decor = xcalloc(1, sizeof(*decor));
|
||||
decor->hl_id = hl_id;
|
||||
decor->virt_text = virt_text;
|
||||
} else if (hl_id) {
|
||||
decor = decoration_hl(hl_id);
|
||||
}
|
||||
|
||||
id = extmark_set(buf, (uint64_t)ns_id, id,
|
||||
(int)line, (colnr_T)col, -1, -1, NULL, kExtmarkUndo);
|
||||
(int)line, (colnr_T)col, line2, col2, decor, kExtmarkUndo);
|
||||
|
||||
return (Integer)id;
|
||||
|
||||
error:
|
||||
clear_virttext(&virt_text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1421,9 +1557,9 @@ Integer nvim_buf_add_highlight(Buffer buffer,
|
||||
return src_id;
|
||||
}
|
||||
|
||||
int hlg_id = 0;
|
||||
int hl_id = 0;
|
||||
if (hl_group.size > 0) {
|
||||
hlg_id = syn_check_group((char_u *)hl_group.data, (int)hl_group.size);
|
||||
hl_id = syn_check_group((char_u *)hl_group.data, (int)hl_group.size);
|
||||
} else {
|
||||
return src_id;
|
||||
}
|
||||
@@ -1434,13 +1570,10 @@ Integer nvim_buf_add_highlight(Buffer buffer,
|
||||
end_line++;
|
||||
}
|
||||
|
||||
Decoration *decor = xcalloc(1, sizeof(*decor));
|
||||
decor->hl_id = hlg_id;
|
||||
|
||||
ns_id = extmark_set(buf, ns_id, 0,
|
||||
(int)line, (colnr_T)col_start,
|
||||
end_line, (colnr_T)col_end,
|
||||
decor, kExtmarkUndo);
|
||||
decoration_hl(hl_id), kExtmarkUndo);
|
||||
return src_id;
|
||||
}
|
||||
|
||||
@@ -1611,114 +1744,6 @@ Integer nvim_buf_set_virtual_text(Buffer buffer,
|
||||
return src_id;
|
||||
}
|
||||
|
||||
/// Get the virtual text (annotation) for a buffer line.
|
||||
///
|
||||
/// The virtual text is returned as list of lists, whereas the inner lists have
|
||||
/// either one or two elements. The first element is the actual text, the
|
||||
/// optional second element is the highlight group.
|
||||
///
|
||||
/// The format is exactly the same as given to nvim_buf_set_virtual_text().
|
||||
///
|
||||
/// If there is no virtual text associated with the given line, an empty list
|
||||
/// is returned.
|
||||
///
|
||||
/// @param buffer Buffer handle, or 0 for current buffer
|
||||
/// @param line Line to get the virtual text from (zero-indexed)
|
||||
/// @param[out] err Error details, if any
|
||||
/// @return List of virtual text chunks
|
||||
Array nvim_buf_get_virtual_text(Buffer buffer, Integer line, Error *err)
|
||||
FUNC_API_SINCE(7)
|
||||
{
|
||||
Array chunks = ARRAY_DICT_INIT;
|
||||
|
||||
buf_T *buf = find_buffer_by_handle(buffer, err);
|
||||
if (!buf) {
|
||||
return chunks;
|
||||
}
|
||||
|
||||
if (line < 0 || line >= MAXLNUM) {
|
||||
api_set_error(err, kErrorTypeValidation, "Line number outside range");
|
||||
return chunks;
|
||||
}
|
||||
|
||||
VirtText *virt_text = extmark_find_virttext(buf, (int)line, 0);
|
||||
|
||||
if (!virt_text) {
|
||||
return chunks;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < virt_text->size; i++) {
|
||||
Array chunk = ARRAY_DICT_INIT;
|
||||
VirtTextChunk *vtc = &virt_text->items[i];
|
||||
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))));
|
||||
}
|
||||
ADD(chunks, ARRAY_OBJ(chunk));
|
||||
}
|
||||
|
||||
return chunks;
|
||||
}
|
||||
|
||||
Integer nvim__buf_add_decoration(Buffer buffer, Integer ns_id, String hl_group,
|
||||
Integer start_row, Integer start_col,
|
||||
Integer end_row, Integer end_col,
|
||||
Array virt_text,
|
||||
Error *err)
|
||||
{
|
||||
buf_T *buf = find_buffer_by_handle(buffer, err);
|
||||
if (!buf) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ns_initialized((uint64_t)ns_id)) {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid ns_id");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (start_row < 0 || start_row >= MAXLNUM || end_row > MAXCOL) {
|
||||
api_set_error(err, kErrorTypeValidation, "Line number outside range");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (start_col < 0 || start_col > MAXCOL || end_col > MAXCOL) {
|
||||
api_set_error(err, kErrorTypeValidation, "Column value outside range");
|
||||
return 0;
|
||||
}
|
||||
if (end_row < 0 || end_col < 0) {
|
||||
end_row = -1;
|
||||
end_col = -1;
|
||||
}
|
||||
|
||||
if (start_row >= buf->b_ml.ml_line_count
|
||||
|| end_row >= buf->b_ml.ml_line_count) {
|
||||
// safety check, we can't add marks outside the range
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hlg_id = 0;
|
||||
if (hl_group.size > 0) {
|
||||
hlg_id = syn_check_group((char_u *)hl_group.data, (int)hl_group.size);
|
||||
}
|
||||
|
||||
VirtText vt = parse_virt_text(virt_text, err);
|
||||
if (ERROR_SET(err)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Decoration *decor = xcalloc(1, sizeof(*decor));
|
||||
decor->hl_id = hlg_id;
|
||||
decor->virt_text = vt;
|
||||
|
||||
uint64_t mark_id = extmark_set(buf, (uint64_t)ns_id, 0,
|
||||
(int)start_row, (colnr_T)start_col,
|
||||
(int)end_row, (colnr_T)end_col, decor,
|
||||
kExtmarkUndo);
|
||||
return (Integer)mark_id;
|
||||
}
|
||||
|
||||
Dictionary nvim__buf_stats(Buffer buffer, Error *err)
|
||||
{
|
||||
Dictionary rv = ARRAY_DICT_INIT;
|
||||
|
Reference in New Issue
Block a user