refactor(api): use typed keysets

Initially this is just for geting rid of boilerplate,
but eventually the types could get exposed as metadata
This commit is contained in:
bfredl
2023-08-01 14:01:19 +02:00
parent c01e624b07
commit 7bc93e0e2f
23 changed files with 771 additions and 866 deletions

View File

@@ -10,6 +10,7 @@
#include "lauxlib.h"
#include "nvim/api/extmark.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/validate.h"
#include "nvim/buffer_defs.h"
@@ -581,40 +582,32 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
});
uint32_t id = 0;
if (HAS_KEY(opts->id)) {
VALIDATE_EXP((opts->id.type == kObjectTypeInteger && opts->id.data.integer > 0),
"id", "positive Integer", NULL, {
if (HAS_KEY(opts, set_extmark, id)) {
VALIDATE_EXP((opts->id > 0), "id", "positive Integer", NULL, {
goto error;
});
id = (uint32_t)opts->id.data.integer;
id = (uint32_t)opts->id;
}
int line2 = -1;
bool did_end_line = false;
// For backward compatibility we support "end_line" as an alias for "end_row"
if (HAS_KEY(opts->end_line)) {
VALIDATE(!HAS_KEY(opts->end_row), "%s", "cannot use both 'end_row' and 'end_line'", {
if (HAS_KEY(opts, set_extmark, end_line)) {
VALIDATE(!HAS_KEY(opts, set_extmark, end_row),
"%s", "cannot use both 'end_row' and 'end_line'", {
goto error;
});
opts->end_row = opts->end_line;
did_end_line = true;
}
#define OPTION_TO_BOOL(target, name, val) \
target = api_object_to_bool(opts->name, #name, val, err); \
if (ERROR_SET(err)) { \
goto error; \
}
bool strict = GET_BOOL_OR_TRUE(opts, set_extmark, strict);
bool strict = true;
OPTION_TO_BOOL(strict, strict, true);
if (HAS_KEY(opts->end_row)) {
VALIDATE_T("end_row", kObjectTypeInteger, opts->end_row.type, {
goto error;
});
Integer val = opts->end_row.data.integer;
if (HAS_KEY(opts, set_extmark, end_row) || did_end_line) {
Integer val = opts->end_row;
VALIDATE_RANGE((val >= 0 && !(val > buf->b_ml.ml_line_count && strict)), "end_row", {
goto error;
});
@@ -622,12 +615,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
colnr_T col2 = -1;
if (HAS_KEY(opts->end_col)) {
VALIDATE_T("end_col", kObjectTypeInteger, opts->end_col.type, {
goto error;
});
Integer val = opts->end_col.data.integer;
if (HAS_KEY(opts, set_extmark, end_col)) {
Integer val = opts->end_col;
VALIDATE_RANGE((val >= 0 && val <= MAXCOL), "end_col", {
goto error;
});
@@ -636,6 +625,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
// uncrustify:off
// TODO(bfredl): keyset type alias for hl_group? (nil|int|string)
struct {
const char *name;
Object *opt;
@@ -652,7 +642,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
// uncrustify:on
for (int j = 0; hls[j].name && hls[j].dest; j++) {
if (HAS_KEY(*hls[j].opt)) {
if (hls[j].opt->type != kObjectTypeNil) {
*hls[j].dest = object_to_hl_id(*hls[j].opt, hls[j].name, err);
if (ERROR_SET(err)) {
goto error;
@@ -661,12 +651,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
}
if (HAS_KEY(opts->conceal)) {
VALIDATE_T("conceal", kObjectTypeString, opts->conceal.type, {
goto error;
});
String c = opts->conceal.data.string;
if (HAS_KEY(opts, set_extmark, conceal)) {
String c = opts->conceal;
decor.conceal = true;
if (c.size) {
decor.conceal_char = utf_ptr2char(c.data);
@@ -674,25 +660,16 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
has_decor = true;
}
if (HAS_KEY(opts->virt_text)) {
VALIDATE_T("virt_text", kObjectTypeArray, opts->virt_text.type, {
goto error;
});
decor.virt_text = parse_virt_text(opts->virt_text.data.array, err,
&decor.virt_text_width);
if (HAS_KEY(opts, set_extmark, virt_text)) {
decor.virt_text = parse_virt_text(opts->virt_text, err, &decor.virt_text_width);
has_decor = true;
if (ERROR_SET(err)) {
goto error;
}
}
if (HAS_KEY(opts->virt_text_pos)) {
VALIDATE_T("virt_text_pos", kObjectTypeString, opts->virt_text_pos.type, {
goto error;
});
String str = opts->virt_text_pos.data.string;
if (HAS_KEY(opts, set_extmark, virt_text_pos)) {
String str = opts->virt_text_pos;
if (strequal("eol", str.data)) {
decor.virt_text_pos = kVTEndOfLine;
} else if (strequal("overlay", str.data)) {
@@ -708,24 +685,16 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
}
if (HAS_KEY(opts->virt_text_win_col)) {
VALIDATE_T("virt_text_win_col", kObjectTypeInteger, opts->virt_text_win_col.type, {
goto error;
});
decor.col = (int)opts->virt_text_win_col.data.integer;
if (HAS_KEY(opts, set_extmark, virt_text_win_col)) {
decor.col = (int)opts->virt_text_win_col;
decor.virt_text_pos = kVTWinCol;
}
OPTION_TO_BOOL(decor.virt_text_hide, virt_text_hide, false);
OPTION_TO_BOOL(decor.hl_eol, hl_eol, false);
decor.hl_eol = opts->hl_eol;
decor.virt_text_hide = opts->virt_text_hide;
if (HAS_KEY(opts->hl_mode)) {
VALIDATE_T("hl_mode", kObjectTypeString, opts->hl_mode.type, {
goto error;
});
String str = opts->hl_mode.data.string;
if (HAS_KEY(opts, set_extmark, hl_mode)) {
String str = opts->hl_mode;
if (strequal("replace", str.data)) {
decor.hl_mode = kHlModeReplace;
} else if (strequal("combine", str.data)) {
@@ -744,15 +713,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
}
bool virt_lines_leftcol = false;
OPTION_TO_BOOL(virt_lines_leftcol, virt_lines_leftcol, false);
bool virt_lines_leftcol = opts->virt_lines_leftcol;
if (HAS_KEY(opts->virt_lines)) {
VALIDATE_T("virt_lines", kObjectTypeArray, opts->virt_lines.type, {
goto error;
});
Array a = opts->virt_lines.data.array;
if (HAS_KEY(opts, set_extmark, virt_lines)) {
Array a = opts->virt_lines;
for (size_t j = 0; j < a.size; j++) {
VALIDATE_T("virt_text_line", kObjectTypeArray, a.items[j].type, {
goto error;
@@ -767,61 +731,44 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
}
OPTION_TO_BOOL(decor.virt_lines_above, virt_lines_above, false);
decor.virt_lines_above = opts->virt_lines_above;
if (HAS_KEY(opts->priority)) {
VALIDATE_T("priority", kObjectTypeInteger, opts->priority.type, {
if (HAS_KEY(opts, set_extmark, priority)) {
VALIDATE_RANGE((opts->priority >= 0 && opts->priority <= UINT16_MAX), "priority", {
goto error;
});
Integer val = opts->priority.data.integer;
VALIDATE_RANGE((val >= 0 && val <= UINT16_MAX), "priority", {
goto error;
});
decor.priority = (DecorPriority)val;
decor.priority = (DecorPriority)opts->priority;
}
if (HAS_KEY(opts->sign_text)) {
VALIDATE_T("sign_text", kObjectTypeString, opts->sign_text.type, {
goto error;
});
VALIDATE_S(init_sign_text(&decor.sign_text, opts->sign_text.data.string.data),
if (HAS_KEY(opts, set_extmark, sign_text)) {
VALIDATE_S(init_sign_text(&decor.sign_text, opts->sign_text.data),
"sign_text", "", {
goto error;
});
has_decor = true;
}
bool right_gravity = true;
OPTION_TO_BOOL(right_gravity, right_gravity, true);
bool right_gravity = GET_BOOL_OR_TRUE(opts, set_extmark, right_gravity);
// Only error out if they try to set end_right_gravity without
// setting end_col or end_row
VALIDATE(!(line2 == -1 && col2 == -1 && HAS_KEY(opts->end_right_gravity)),
VALIDATE(!(line2 == -1 && col2 == -1 && HAS_KEY(opts, set_extmark, end_right_gravity)),
"%s", "cannot set end_right_gravity without end_row or end_col", {
goto error;
});
bool end_right_gravity = false;
OPTION_TO_BOOL(end_right_gravity, end_right_gravity, false);
bool end_right_gravity = opts->end_right_gravity;
size_t len = 0;
bool ephemeral = false;
OPTION_TO_BOOL(ephemeral, ephemeral, false);
if (!HAS_KEY(opts->spell)) {
if (!HAS_KEY(opts, set_extmark, spell)) {
decor.spell = kNone;
} else {
bool spell = false;
OPTION_TO_BOOL(spell, spell, false);
decor.spell = spell ? kTrue : kFalse;
decor.spell = opts->spell ? kTrue : kFalse;
has_decor = true;
}
OPTION_TO_BOOL(decor.ui_watched, ui_watched, false);
decor.ui_watched = opts->ui_watched;
if (decor.ui_watched) {
has_decor = true;
}
@@ -836,7 +783,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
});
line = buf->b_ml.ml_line_count;
} else if (line < buf->b_ml.ml_line_count) {
len = ephemeral ? MAXCOL : strlen(ml_get_buf(buf, (linenr_T)line + 1, false));
len = opts->ephemeral ? MAXCOL : strlen(ml_get_buf(buf, (linenr_T)line + 1, false));
}
if (col == -1) {
@@ -854,7 +801,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
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 = opts->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;
@@ -873,10 +820,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
// TODO(bfredl): synergize these two branches even more
if (ephemeral && decor_state.win && decor_state.win->w_buffer == buf) {
if (opts->ephemeral && decor_state.win && decor_state.win->w_buffer == buf) {
decor_add_ephemeral((int)line, (int)col, line2, col2, &decor, (uint64_t)ns_id, id);
} else {
if (ephemeral) {
if (opts->ephemeral) {
api_set_error(err, kErrorTypeException, "not yet implemented");
goto error;
}
@@ -1107,7 +1054,7 @@ void nvim_set_decoration_provider(Integer ns_id, Dict(set_decoration_provider) *
struct {
const char *name;
Object *source;
LuaRef *source;
LuaRef *dest;
} cbs[] = {
{ "on_start", &opts->on_start, &p->redraw_start },
@@ -1121,25 +1068,18 @@ void nvim_set_decoration_provider(Integer ns_id, Dict(set_decoration_provider) *
};
for (size_t i = 0; cbs[i].source && cbs[i].dest && cbs[i].name; i++) {
Object *v = cbs[i].source;
if (v->type == kObjectTypeNil) {
LuaRef *v = cbs[i].source;
if (*v <= 0) {
continue;
}
VALIDATE_T(cbs[i].name, kObjectTypeLuaRef, v->type, {
goto error;
});
*(cbs[i].dest) = v->data.luaref;
v->data.luaref = LUA_NOREF;
*(cbs[i].dest) = *v;
*v = LUA_NOREF;
}
p->active = true;
p->hl_valid++;
p->hl_cached = false;
return;
error:
decor_provider_clear(p);
}
/// Gets the line and column of an |extmark|.