From aec4b476c5689f032103ab3e0ca068fc2af8bbba Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 27 Jan 2023 11:24:20 +0000 Subject: docs(api): tweak data arg for nvim_create_autocmd (#22008) Fixes #21964 --- src/nvim/api/autocmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 931363e199..a2cb297b15 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -404,7 +404,7 @@ cleanup: /// - match: (string) expanded value of || /// - buf: (number) expanded value of || /// - file: (string) expanded value of || -/// - data: (any) arbitrary data passed to |nvim_exec_autocmds()| +/// - data: (any) arbitrary data passed from |nvim_exec_autocmds()| /// - command (string) optional: Vim command to execute on event. Cannot be used with /// {callback} /// - once (boolean) optional: defaults to false. Run the autocommand -- cgit From 28e26e05bc4cd2bd8e1abc2dd4d720fd9199456d Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 8 Feb 2023 16:24:33 +0100 Subject: perf(ui): mitigate redraw latency regression from TUI refactor While the new RPC encoder/decoder implementation in general should have less overhead than the deleted UIBridge serializer previously used for the TUI, it regresses on redraw latency in one important aspect. The old bridge implementation allowed the TUI to process a previous screen line internally in parallel with the main thread rendering the next one in win_line etc. As printing the escape sequences in highlighted cells has a considerable hit in profiles, this has a substantial effect on redraw latency. The RPC implementation, however, waits with sending any data until either a flush, or the buffer is full. This change lowers the granularity of communication again, using an adjustable threshold counted in number of cell events (discounting long repeats and clearing as maximum a single extra event). The current value is guesstimated to something simple on a reasonable scale, which should be bigger than a single line, but multiple events for a big multi-window screen. --- src/nvim/api/ui.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index e67607a7e4..3ad625234c 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -202,6 +202,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona data->flushed_events = false; data->ncalls_pos = NULL; data->ncalls = 0; + data->ncells_pending = 0; data->buf_wptr = data->buf; data->temp_buf = NULL; data->wildmenu_active = false; @@ -854,18 +855,25 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int mpack_uint(buf, repeat); } } + data->ncells_pending += MIN(repeat, 2); last_hl = attrs[i]; repeat = 0; } } if (endcol < clearcol) { nelem++; + data->ncells_pending += 1; mpack_array(buf, 3); mpack_str(buf, " "); mpack_uint(buf, (uint32_t)clearattr); mpack_uint(buf, (uint32_t)(clearcol - endcol)); } mpack_w2(&lenpos, nelem); + + if (data->ncells_pending > 500) { + // pass of cells to UI to let it start processing them + remote_ui_flush_buf(ui); + } } else { for (int i = 0; i < endcol - startcol; i++) { remote_ui_cursor_goto(ui, row, startcol + i); @@ -917,6 +925,8 @@ void remote_ui_flush_buf(UI *ui) // we have sent events to the client, but possibly not yet the final "flush" // event. data->flushed_events = true; + + data->ncells_pending = 0; } /// An intentional flush (vsync) when Nvim is finished redrawing the screen -- cgit From 7224c889e0d5d70b99ae377036baa6377c33a568 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 11 Feb 2023 10:25:24 +0100 Subject: build: enable MSVC level 3 warnings (#21934) MSVC has 4 different warning levels: 1 (severe), 2 (significant), 3 (production quality) and 4 (informational). Enabling level 3 warnings mostly revealed conversion problems, similar to GCC/clang -Wconversion flag. --- src/nvim/api/command.c | 4 ++-- src/nvim/api/options.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index abd265f2cf..7e7df3ee0f 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -512,7 +512,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } else if (cmd->count.type != kObjectTypeInteger || cmd->count.data.integer < 0) { VALIDATION_ERROR("'count' must be a non-negative Integer"); } - set_cmd_count(&ea, cmd->count.data.integer, true); + set_cmd_count(&ea, (linenr_T)cmd->count.data.integer, true); } if (HAS_KEY(cmd->reg)) { @@ -1005,7 +1005,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, Error *err) { uint32_t argt = 0; - long def = -1; + int64_t def = -1; cmd_addr_T addr_type_arg = ADDR_NONE; int compl = EXPAND_NOTHING; char *compl_arg = NULL; diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index bfcb99754f..2a54c3b132 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -181,7 +181,7 @@ void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error switch (value.type) { case kObjectTypeInteger: - numval = value.data.integer; + numval = (long)value.data.integer; break; case kObjectTypeBoolean: numval = value.data.boolean ? 1 : 0; -- cgit From 4be6c6cf0ddf5e31d4103cb5df06651ba6f4897b Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 11 Feb 2023 11:05:57 +0100 Subject: refactor: replace char_u with char (#21901) refactor: replace char_u with char Work on https://github.com/neovim/neovim/issues/459 --- src/nvim/api/autocmd.c | 16 ++++++++-------- src/nvim/api/command.c | 8 ++++---- src/nvim/api/vim.c | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index a2cb297b15..f801c716e5 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -194,8 +194,8 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) goto cleanup; } - snprintf((char *)pattern_buflocal, BUFLOCAL_PAT_LEN, "", (int)buf->handle); - ADD(buffers, CSTR_TO_OBJ((char *)pattern_buflocal)); + snprintf(pattern_buflocal, BUFLOCAL_PAT_LEN, "", (int)buf->handle); + ADD(buffers, CSTR_TO_OBJ(pattern_buflocal)); } else if (opts->buffer.type == kObjectTypeArray) { if (opts->buffer.data.array.size > AUCMD_MAX_PATTERNS) { api_set_error(err, @@ -215,8 +215,8 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) goto cleanup; } - snprintf((char *)pattern_buflocal, BUFLOCAL_PAT_LEN, "", (int)buf->handle); - ADD(buffers, CSTR_TO_OBJ((char *)pattern_buflocal)); + snprintf(pattern_buflocal, BUFLOCAL_PAT_LEN, "", (int)buf->handle); + ADD(buffers, CSTR_TO_OBJ(pattern_buflocal)); }); } else if (opts->buffer.type != kObjectTypeNil) { api_set_error(err, kErrorTypeValidation, @@ -319,7 +319,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) PUT(autocmd_info, "pattern", - STRING_OBJ(cstr_to_string((char *)ap->pat))); + STRING_OBJ(cstr_to_string(ap->pat))); PUT(autocmd_info, "event", @@ -934,7 +934,7 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob char *pat = v->data.string.data; size_t patlen = aucmd_pattern_length(pat); while (patlen) { - ADD(*patterns, STRING_OBJ(cbuf_to_string((char *)pat, patlen))); + ADD(*patterns, STRING_OBJ(cbuf_to_string(pat, patlen))); pat = aucmd_next_pattern(pat, patlen); patlen = aucmd_pattern_length(pat); @@ -949,7 +949,7 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob char *pat = entry.data.string.data; size_t patlen = aucmd_pattern_length(pat); while (patlen) { - ADD(*patterns, STRING_OBJ(cbuf_to_string((char *)pat, patlen))); + ADD(*patterns, STRING_OBJ(cbuf_to_string(pat, patlen))); pat = aucmd_next_pattern(pat, patlen); patlen = aucmd_pattern_length(pat); @@ -975,7 +975,7 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob } snprintf((char *)pattern_buflocal, BUFLOCAL_PAT_LEN, "", (int)buf->handle); - ADD(*patterns, STRING_OBJ(cstr_to_string((char *)pattern_buflocal))); + ADD(*patterns, STRING_OBJ(cstr_to_string(pattern_buflocal))); } return true; diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 7e7df3ee0f..f09a00e5c2 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -127,7 +127,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) // otherwise split arguments by whitespace. if (ea.argt & EX_NOSPC) { if (*ea.arg != NUL) { - ADD(args, STRING_OBJ(cstrn_to_string((char *)ea.arg, length))); + ADD(args, STRING_OBJ(cstrn_to_string(ea.arg, length))); } } else { size_t end = 0; @@ -153,9 +153,9 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) } if (cmd != NULL) { - PUT(result, "cmd", CSTR_TO_OBJ((char *)cmd->uc_name)); + PUT(result, "cmd", CSTR_TO_OBJ(cmd->uc_name)); } else { - PUT(result, "cmd", CSTR_TO_OBJ((char *)get_command_name(NULL, ea.cmdidx))); + PUT(result, "cmd", CSTR_TO_OBJ(get_command_name(NULL, ea.cmdidx))); } if (ea.argt & EX_RANGE) { @@ -237,7 +237,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) break; } PUT(result, "addr", CSTR_TO_OBJ(addr)); - PUT(result, "nextcmd", CSTR_TO_OBJ((char *)ea.nextcmd)); + PUT(result, "nextcmd", CSTR_TO_OBJ(ea.nextcmd)); Dictionary mods = ARRAY_DICT_INIT; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index a53b30dd8a..12ab40a687 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -554,7 +554,7 @@ static void find_runtime_cb(char *fname, void *cookie) { Array *rv = (Array *)cookie; if (fname != NULL) { - ADD(*rv, STRING_OBJ(cstr_to_string((char *)fname))); + ADD(*rv, STRING_OBJ(cstr_to_string(fname))); } } @@ -2266,7 +2266,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * for (stl_hlrec_t *sp = hltab; sp->start != NULL; sp++) { Dictionary hl_info = ARRAY_DICT_INIT; - PUT(hl_info, "start", INTEGER_OBJ((char *)sp->start - buf)); + PUT(hl_info, "start", INTEGER_OBJ(sp->start - buf)); if (sp->userhl == 0) { grpname = get_default_stl_hl(wp, use_winbar); @@ -2281,7 +2281,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * } PUT(result, "highlights", ARRAY_OBJ(hl_values)); } - PUT(result, "str", CSTR_TO_OBJ((char *)buf)); + PUT(result, "str", CSTR_TO_OBJ(buf)); return result; } -- cgit From 5ca6cf55f9c772f5c691b08dc49581f27f88e8f9 Mon Sep 17 00:00:00 2001 From: glacambre Date: Sat, 11 Feb 2023 13:51:33 +0100 Subject: fix(helpers): restore channel id after a call to WITH_SCRIPT_CONTEXT In https://github.com/neovim/neovim/pull/22214, init_default_autocmds has been turned into a lua function call to nvim_create_augroup and nvim_create_autocmd. This introduced a strange regression: a test in vim_spec.lua started failing with its last_set_chan value switching from 0 to -9223372036854775808. It turns out that -9223372036854775808 is the value of LUA_INTERNAL_CALL and would be inherited as last_set_chan by options set from the command line due to the WITH_SCRIPT_CONTEXT macro not restoring the channel id (WITH_SCRIPT_CONTEXT is used by nvim_create_augroup). --- src/nvim/api/private/helpers.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index ec97ba9ec6..b70452d7cb 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -175,11 +175,13 @@ typedef struct { #define WITH_SCRIPT_CONTEXT(channel_id, code) \ do { \ const sctx_T save_current_sctx = current_sctx; \ + const uint64_t save_channel_id = current_channel_id; \ current_sctx.sc_sid = \ (channel_id) == LUA_INTERNAL_CALL ? SID_LUA : SID_API_CLIENT; \ current_sctx.sc_lnum = 0; \ current_channel_id = channel_id; \ code; \ + current_channel_id = save_channel_id; \ current_sctx = save_current_sctx; \ } while (0); -- cgit From 41ebe41b62921142bb486e5f30bd2fa9f53f1700 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 12 Feb 2023 19:02:14 +0800 Subject: fix(ui-ext): force cursor update after resize in char-based UI Neither ui/screen.lua nor Neovim Qt keep cursor position after resizing. --- src/nvim/api/ui.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 3ad625234c..8f5465db77 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -645,6 +645,8 @@ void remote_ui_grid_resize(UI *ui, Integer grid, Integer width, Integer height) Array args = data->call_buf; if (ui->ui_ext[kUILinegrid]) { ADD_C(args, INTEGER_OBJ(grid)); + } else { + data->client_col = -1; // force cursor update } ADD_C(args, INTEGER_OBJ(width)); ADD_C(args, INTEGER_OBJ(height)); -- cgit From 46a87a5d2bac598fed0870f0d3c926087f95d30f Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 14 Feb 2023 05:19:04 -0500 Subject: refactor(api): VALIDATE macros #22187 Problem: - API validation involves too much boilerplate. - API validation errors are not consistently worded. Solution: Introduce some macros. Currently these are clumsy, but they at least help with consistency and avoid some nesting. --- src/nvim/api/autocmd.c | 229 ++++++++++++++-------------------- src/nvim/api/buffer.c | 153 +++++++++-------------- src/nvim/api/command.c | 63 +++++----- src/nvim/api/extmark.c | 268 ++++++++++++++++++++-------------------- src/nvim/api/options.c | 128 ++++++++----------- src/nvim/api/private/helpers.c | 30 +++++ src/nvim/api/private/validate.h | 69 +++++++++++ src/nvim/api/vim.c | 171 ++++++++++--------------- 8 files changed, 532 insertions(+), 579 deletions(-) create mode 100644 src/nvim/api/private/validate.h (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index f801c716e5..9aadd48a13 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -12,6 +12,7 @@ #include "nvim/api/autocmd.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" @@ -107,22 +108,21 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) break; case kObjectTypeString: group = augroup_find(opts->group.data.string.data); - if (group < 0) { - api_set_error(err, kErrorTypeValidation, "invalid augroup passed."); + VALIDATE_S((group >= 0), "group", "", { goto cleanup; - } + }); break; case kObjectTypeInteger: group = (int)opts->group.data.integer; char *name = augroup_name(group); - if (!augroup_exists(name)) { - api_set_error(err, kErrorTypeValidation, "invalid augroup passed."); + VALIDATE_S(augroup_exists(name), "group", "", { goto cleanup; - } + }); break; default: - api_set_error(err, kErrorTypeValidation, "group must be a string or an integer."); - goto cleanup; + VALIDATE_S(false, "group (must be string or integer)", "", { + goto cleanup; + }); } if (opts->event.type != kObjectTypeNil) { @@ -134,29 +134,24 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) event_set[event_nr] = true; } else if (v.type == kObjectTypeArray) { FOREACH_ITEM(v.data.array, event_v, { - if (event_v.type != kObjectTypeString) { - api_set_error(err, - kErrorTypeValidation, - "Every event must be a string in 'event'"); + VALIDATE_T("event item", kObjectTypeString, event_v.type, { goto cleanup; - } + }); GET_ONE_EVENT(event_nr, event_v, cleanup); event_set[event_nr] = true; }) } else { - api_set_error(err, - kErrorTypeValidation, - "Not a valid 'event' value. Must be a string or an array"); - goto cleanup; + VALIDATE_S(false, "event (must be String or Array)", "", { + goto cleanup; + }); } } - if (opts->pattern.type != kObjectTypeNil && opts->buffer.type != kObjectTypeNil) { - api_set_error(err, kErrorTypeValidation, - "Cannot use both 'pattern' and 'buffer'"); + VALIDATE((opts->pattern.type == kObjectTypeNil || opts->buffer.type == kObjectTypeNil), + "Cannot use both 'pattern' and 'buffer'", { goto cleanup; - } + }); int pattern_filter_count = 0; if (opts->pattern.type != kObjectTypeNil) { @@ -166,25 +161,23 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) pattern_filter_count += 1; } else if (v.type == kObjectTypeArray) { if (v.data.array.size > AUCMD_MAX_PATTERNS) { - api_set_error(err, kErrorTypeValidation, - "Too many patterns. Please limit yourself to %d or fewer", + api_set_error(err, kErrorTypeValidation, "Too many patterns (maximum of %d)", AUCMD_MAX_PATTERNS); goto cleanup; } FOREACH_ITEM(v.data.array, item, { - if (item.type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'pattern': must be a string"); + VALIDATE_T("pattern", kObjectTypeString, item.type, { goto cleanup; - } + }); pattern_filters[pattern_filter_count] = item.data.string.data; pattern_filter_count += 1; }); } else { - api_set_error(err, kErrorTypeValidation, - "Not a valid 'pattern' value. Must be a string or an array"); - goto cleanup; + VALIDATE_EXP(false, "pattern", "String or Array", api_typename(v.type), { + goto cleanup; + }); } } @@ -198,17 +191,16 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) ADD(buffers, CSTR_TO_OBJ(pattern_buflocal)); } else if (opts->buffer.type == kObjectTypeArray) { if (opts->buffer.data.array.size > AUCMD_MAX_PATTERNS) { - api_set_error(err, - kErrorTypeValidation, - "Too many buffers. Please limit yourself to %d or fewer", AUCMD_MAX_PATTERNS); + api_set_error(err, kErrorTypeValidation, "Too many buffers (maximum of %d)", + AUCMD_MAX_PATTERNS); goto cleanup; } FOREACH_ITEM(opts->buffer.data.array, bufnr, { - if (bufnr.type != kObjectTypeInteger && bufnr.type != kObjectTypeBuffer) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'buffer': must be an integer"); + VALIDATE_EXP((bufnr.type == kObjectTypeInteger || bufnr.type == kObjectTypeBuffer), + "buffer", "Integer", api_typename(bufnr.type), { goto cleanup; - } + }); buf_T *buf = find_buffer_by_handle((Buffer)bufnr.data.integer, err); if (ERROR_SET(err)) { @@ -219,9 +211,9 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) ADD(buffers, CSTR_TO_OBJ(pattern_buflocal)); }); } else if (opts->buffer.type != kObjectTypeNil) { - api_set_error(err, kErrorTypeValidation, - "Invalid value for 'buffer': must be an integer or array of integers"); - goto cleanup; + VALIDATE_EXP(false, "buffer", "Integer or Array", api_typename(opts->buffer.type), { + goto cleanup; + }); } FOREACH_ITEM(buffers, bufnr, { @@ -432,30 +424,23 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc goto cleanup; } - if (opts->callback.type != kObjectTypeNil && opts->command.type != kObjectTypeNil) { - api_set_error(err, kErrorTypeValidation, "specify either 'callback' or 'command', not both"); + VALIDATE((opts->callback.type == kObjectTypeNil || opts->command.type == kObjectTypeNil), + "Cannot use both 'callback' and 'command'", { goto cleanup; - } else if (opts->callback.type != kObjectTypeNil) { - // TODO(tjdevries): It's possible we could accept callable tables, - // but we don't do that many other places, so for the moment let's - // not do that. + }); + + if (opts->callback.type != kObjectTypeNil) { + // NOTE: We could accept callable tables, but that isn't common in the API. Object *callback = &opts->callback; switch (callback->type) { case kObjectTypeLuaRef: - if (callback->data.luaref == LUA_NOREF) { - api_set_error(err, - kErrorTypeValidation, - "must pass an actual value"); + VALIDATE_S((callback->data.luaref != LUA_NOREF), "callback", "", { goto cleanup; - } - - if (!nlua_ref_is_function(callback->data.luaref)) { - api_set_error(err, - kErrorTypeValidation, - "must pass a function for callback"); + }); + VALIDATE_S(nlua_ref_is_function(callback->data.luaref), "callback", "", { goto cleanup; - } + }); cb.type = kCallbackLua; cb.data.luaref = api_new_luaref(callback->data.luaref); @@ -465,28 +450,25 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc cb.data.funcref = string_to_cstr(callback->data.string); break; default: - api_set_error(err, - kErrorTypeException, - "'callback' must be a lua function or name of vim function"); - goto cleanup; + VALIDATE_EXP(false, "callback", "Lua function or Vim function name", + api_typename(callback->type), { + goto cleanup; + }); } aucmd.type = CALLABLE_CB; aucmd.callable.cb = cb; } else if (opts->command.type != kObjectTypeNil) { Object *command = &opts->command; - if (command->type == kObjectTypeString) { - aucmd.type = CALLABLE_EX; - aucmd.callable.cmd = string_to_cstr(command->data.string); - } else { - api_set_error(err, - kErrorTypeValidation, - "'command' must be a string"); + VALIDATE_T("command", kObjectTypeString, command->type, { goto cleanup; - } + }); + aucmd.type = CALLABLE_EX; + aucmd.callable.cmd = string_to_cstr(command->data.string); } else { - api_set_error(err, kErrorTypeValidation, "must pass one of: 'command', 'callback'"); - goto cleanup; + VALIDATE_S(false, "'command' or 'callback' is required", "", { + goto cleanup; + }); } bool is_once = api_object_to_bool(opts->once, "once", false, err); @@ -502,24 +484,19 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc } if (opts->desc.type != kObjectTypeNil) { - if (opts->desc.type == kObjectTypeString) { - desc = opts->desc.data.string.data; - } else { - api_set_error(err, - kErrorTypeValidation, - "'desc' must be a string"); + VALIDATE_T("desc", kObjectTypeString, opts->desc.type, { goto cleanup; - } + }); + desc = opts->desc.data.string.data; } if (patterns.size == 0) { ADD(patterns, STRING_OBJ(STATIC_CSTR_TO_STRING("*"))); } - if (event_array.size == 0) { - api_set_error(err, kErrorTypeValidation, "'event' is a required key"); + VALIDATE_R((event_array.size != 0), "event", { goto cleanup; - } + }); autocmd_id = next_autocmd_id++; FOREACH_ITEM(event_array, event_str, { @@ -564,10 +541,9 @@ cleanup: void nvim_del_autocmd(Integer id, Error *err) FUNC_API_SINCE(9) { - if (id <= 0) { - api_set_error(err, kErrorTypeException, "Invalid autocmd id"); + VALIDATE_INT((id > 0), "autocmd id", id, { return; - } + }); if (!autocmd_delete_id(id)) { api_set_error(err, kErrorTypeException, "Failed to delete autocmd"); } @@ -610,11 +586,10 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err) goto cleanup; } - if (opts->pattern.type != kObjectTypeNil && opts->buffer.type != kObjectTypeNil) { - api_set_error(err, kErrorTypeValidation, - "Cannot use both 'pattern' and 'buffer'"); + VALIDATE((opts->pattern.type == kObjectTypeNil || opts->buffer.type == kObjectTypeNil), + "Cannot use both 'pattern' and 'buffer'", { goto cleanup; - } + }); int au_group = get_augroup_from_object(opts->group, err); if (au_group == AUGROUP_ERROR) { @@ -772,32 +747,29 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err) break; case kObjectTypeString: au_group = augroup_find(opts->group.data.string.data); - if (au_group == AUGROUP_ERROR) { - api_set_error(err, - kErrorTypeValidation, - "invalid augroup: %s", opts->group.data.string.data); + VALIDATE_S((au_group != AUGROUP_ERROR), "group", opts->group.data.string.data, { goto cleanup; - } + }); break; case kObjectTypeInteger: au_group = (int)opts->group.data.integer; char *name = augroup_name(au_group); - if (!augroup_exists(name)) { - api_set_error(err, kErrorTypeValidation, "invalid augroup: %d", au_group); + VALIDATE_INT(augroup_exists(name), "group", (int64_t)au_group, { goto cleanup; - } + }); break; default: - api_set_error(err, kErrorTypeValidation, "'group' must be a string or an integer."); - goto cleanup; + VALIDATE_EXP(false, "group", "String or Integer", api_typename(opts->group.type), { + goto cleanup; + }); } if (opts->buffer.type != kObjectTypeNil) { Object buf_obj = opts->buffer; - if (buf_obj.type != kObjectTypeInteger && buf_obj.type != kObjectTypeBuffer) { - api_set_error(err, kErrorTypeException, "invalid buffer: %d", buf_obj.type); + VALIDATE_EXP((buf_obj.type == kObjectTypeInteger || buf_obj.type == kObjectTypeBuffer), + "buffer", "Integer", api_typename(buf_obj.type), { goto cleanup; - } + }); buf = find_buffer_by_handle((Buffer)buf_obj.data.integer, err); @@ -844,18 +816,15 @@ static bool check_autocmd_string_array(Array arr, char *k, Error *err) { FOREACH_ITEM(arr, entry, { if (entry.type != kObjectTypeString) { - api_set_error(err, - kErrorTypeValidation, - "All entries in '%s' must be strings", - k); + api_set_error(err, kErrorTypeValidation, "Invalid '%s' item type: expected String, got %s", + k, api_typename(entry.type)); return false; } // Disallow newlines in the middle of the line. const String l = entry.data.string; if (memchr(l.data, NL, l.size)) { - api_set_error(err, kErrorTypeValidation, - "String cannot contain newlines"); + api_set_error(err, kErrorTypeValidation, "'%s' item cannot contain newlines", k); return false; } }) @@ -873,10 +842,9 @@ static bool unpack_string_or_array(Array *array, Object *v, char *k, bool requir *array = copy_array(v->data.array, NULL); } else { if (required) { - api_set_error(err, - kErrorTypeValidation, - "'%s' must be an array or a string.", - k); + api_set_error(err, kErrorTypeValidation, + "Invalid '%s' type: expected Array or String, got %s", + k, api_typename(v->type)); return false; } } @@ -894,27 +862,22 @@ static int get_augroup_from_object(Object group, Error *err) return AUGROUP_DEFAULT; case kObjectTypeString: au_group = augroup_find(group.data.string.data); - if (au_group == AUGROUP_ERROR) { - api_set_error(err, - kErrorTypeValidation, - "invalid augroup: %s", group.data.string.data); - + VALIDATE_S((au_group != AUGROUP_ERROR), "group", group.data.string.data, { return AUGROUP_ERROR; - } + }); return au_group; case kObjectTypeInteger: au_group = (int)group.data.integer; char *name = augroup_name(au_group); - if (!augroup_exists(name)) { - api_set_error(err, kErrorTypeValidation, "invalid augroup: %d", au_group); + VALIDATE_INT(augroup_exists(name), "group", (int64_t)au_group, { return AUGROUP_ERROR; - } - + }); return au_group; default: - api_set_error(err, kErrorTypeValidation, "'group' must be a string or an integer."); - return AUGROUP_ERROR; + VALIDATE_EXP(false, "group", "String or Integer", api_typename(group.type), { + return AUGROUP_ERROR; + }); } } @@ -923,11 +886,12 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob { const char pattern_buflocal[BUFLOCAL_PAT_LEN]; - if (pattern.type != kObjectTypeNil && buffer.type != kObjectTypeNil) { - api_set_error(err, kErrorTypeValidation, - "cannot pass both: 'pattern' and 'buffer' for the same autocmd"); + VALIDATE((pattern.type == kObjectTypeNil || buffer.type == kObjectTypeNil), + "Cannot use both 'pattern' and 'buffer' for the same autocmd", { return false; - } else if (pattern.type != kObjectTypeNil) { + }); + + if (pattern.type != kObjectTypeNil) { Object *v = &pattern; if (v->type == kObjectTypeString) { @@ -956,18 +920,15 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob } }) } else { - api_set_error(err, - kErrorTypeValidation, - "'pattern' must be a string or table"); - return false; + VALIDATE_EXP(false, "pattern", "String or Table", api_typename(v->type), { + return false; + }); } } else if (buffer.type != kObjectTypeNil) { - if (buffer.type != kObjectTypeInteger && buffer.type != kObjectTypeBuffer) { - api_set_error(err, - kErrorTypeValidation, - "'buffer' must be an integer"); + VALIDATE_EXP((buffer.type == kObjectTypeInteger || buffer.type == kObjectTypeBuffer), + "buffer", "Integer", api_typename(buffer.type), { return false; - } + }); buf_T *buf = find_buffer_by_handle((Buffer)buffer.data.integer, err); if (ERROR_SET(err)) { diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index fe9e6077d6..b2e78db278 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -16,6 +16,7 @@ #include "nvim/api/buffer.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" @@ -179,11 +180,9 @@ Boolean nvim_buf_attach(uint64_t channel_id, Buffer buffer, Boolean send_buffer, if (is_lua) { for (size_t j = 0; cbs[j].name; j++) { if (strequal(cbs[j].name, k.data)) { - if (v->type != kObjectTypeLuaRef) { - api_set_error(err, kErrorTypeValidation, - "%s is not a function", cbs[j].name); + VALIDATE_T(cbs[j].name, kObjectTypeLuaRef, v->type, { goto error; - } + }); *(cbs[j].dest) = v->data.luaref; v->data.luaref = LUA_NOREF; key_used = true; @@ -194,26 +193,23 @@ Boolean nvim_buf_attach(uint64_t channel_id, Buffer buffer, Boolean send_buffer, if (key_used) { continue; } else if (strequal("utf_sizes", k.data)) { - if (v->type != kObjectTypeBoolean) { - api_set_error(err, kErrorTypeValidation, "utf_sizes must be boolean"); + VALIDATE_T("utf_sizes", kObjectTypeBoolean, v->type, { goto error; - } + }); cb.utf_sizes = v->data.boolean; key_used = true; } else if (strequal("preview", k.data)) { - if (v->type != kObjectTypeBoolean) { - api_set_error(err, kErrorTypeValidation, "preview must be boolean"); + VALIDATE_T("preview", kObjectTypeBoolean, v->type, { goto error; - } + }); cb.preview = v->data.boolean; key_used = true; } } - if (!key_used) { - api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); + VALIDATE_S(key_used, "key", k.data, { goto error; - } + }); } return buf_updates_register(buf, channel_id, cb, send_buffer); @@ -297,10 +293,9 @@ ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id, start = normalize_index(buf, start, true, &oob); end = normalize_index(buf, end, true, &oob); - if (strict_indexing && oob) { - api_set_error(err, kErrorTypeValidation, "Index out of bounds"); + VALIDATE((!strict_indexing || !oob), "Index out of bounds", { return rv; - } + }); if (start >= end) { // Return 0-length array @@ -328,20 +323,15 @@ end: static bool check_string_array(Array arr, bool disallow_nl, Error *err) { for (size_t i = 0; i < arr.size; i++) { - if (arr.items[i].type != kObjectTypeString) { - api_set_error(err, - kErrorTypeValidation, - "All items in the replacement array must be strings"); + VALIDATE_T("replacement item", kObjectTypeString, arr.items[i].type, { return false; - } + }); // Disallow newlines in the middle of the line. if (disallow_nl) { const String l = arr.items[i].data.string; - if (memchr(l.data, NL, l.size)) { - api_set_error(err, kErrorTypeValidation, - "String cannot contain newlines"); + VALIDATE(!memchr(l.data, NL, l.size), "String cannot contain newlines", { return false; - } + }); } } return true; @@ -383,17 +373,12 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ start = normalize_index(buf, start, true, &oob); end = normalize_index(buf, end, true, &oob); - if (strict_indexing && oob) { - api_set_error(err, kErrorTypeValidation, "Index out of bounds"); + VALIDATE((!strict_indexing || !oob), "Index out of bounds", { return; - } - - if (start > end) { - api_set_error(err, - kErrorTypeValidation, - "Argument \"start\" is higher than \"end\""); + }); + VALIDATE((start <= end), "\"start\" is higher than \"end\"", { return; - } + }); bool disallow_nl = (channel_id != VIML_INTERNAL_CALL); if (!check_string_array(replacement, disallow_nl, err)) { @@ -453,10 +438,9 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ for (size_t i = 0; i < to_replace; i++) { int64_t lnum = start + (int64_t)i; - if (lnum >= MAXLNUM) { - api_set_error(err, kErrorTypeValidation, "Index value is too high"); + VALIDATE(lnum < MAXLNUM, "Index value is too high", { goto end; - } + }); if (ml_replace((linenr_T)lnum, lines[i], false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to replace line"); @@ -473,10 +457,9 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ for (size_t i = to_replace; i < new_len; i++) { int64_t lnum = start + (int64_t)i - 1; - if (lnum >= MAXLNUM) { - api_set_error(err, kErrorTypeValidation, "Index value is too high"); + VALIDATE(lnum < MAXLNUM, "Index value is too high", { goto end; - } + }); if (ml_append((linenr_T)lnum, lines[i], 0, false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to insert line"); @@ -563,16 +546,14 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In // check range is ordered and everything! // start_row, end_row within buffer len (except add text past the end?) start_row = normalize_index(buf, start_row, false, &oob); - if (oob) { - api_set_error(err, kErrorTypeValidation, "start_row out of bounds"); + VALIDATE((!oob), "start_row out of bounds", { return; - } + }); end_row = normalize_index(buf, end_row, false, &oob); - if (oob) { - api_set_error(err, kErrorTypeValidation, "end_row out of bounds"); + VALIDATE((!oob), "end_row out of bounds", { return; - } + }); char *str_at_start = NULL; char *str_at_end = NULL; @@ -580,23 +561,21 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In // Another call to ml_get_buf() may free the line, so make a copy. str_at_start = xstrdup(ml_get_buf(buf, (linenr_T)start_row, false)); size_t len_at_start = strlen(str_at_start); - if (start_col < 0 || (size_t)start_col > len_at_start) { - api_set_error(err, kErrorTypeValidation, "start_col out of bounds"); + VALIDATE((start_col >= 0 && (size_t)start_col <= len_at_start), "start_col out of bounds", { goto early_end; - } + }); // Another call to ml_get_buf() may free the line, so make a copy. str_at_end = xstrdup(ml_get_buf(buf, (linenr_T)end_row, false)); size_t len_at_end = strlen(str_at_end); - if (end_col < 0 || (size_t)end_col > len_at_end) { - api_set_error(err, kErrorTypeValidation, "end_col out of bounds"); + VALIDATE((end_col >= 0 && (size_t)end_col <= len_at_end), "end_col out of bounds", { goto early_end; - } + }); - if (start_row > end_row || (end_row == start_row && start_col > end_col)) { - api_set_error(err, kErrorTypeValidation, "start is higher than end"); + VALIDATE((start_row <= end_row && !(end_row == start_row && start_col > end_col)), + "start is higher than end", { goto early_end; - } + }); bool disallow_nl = (channel_id != VIML_INTERNAL_CALL); if (!check_string_array(replacement, disallow_nl, err)) { @@ -702,10 +681,9 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In for (size_t i = 0; i < to_replace; i++) { int64_t lnum = start_row + (int64_t)i; - if (lnum >= MAXLNUM) { - api_set_error(err, kErrorTypeValidation, "Index value is too high"); + VALIDATE((lnum < MAXLNUM), "Index value is too high", { goto end; - } + }); if (ml_replace((linenr_T)lnum, lines[i], false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to replace line"); @@ -720,10 +698,9 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In for (size_t i = to_replace; i < new_len; i++) { int64_t lnum = start_row + (int64_t)i - 1; - if (lnum >= MAXLNUM) { - api_set_error(err, kErrorTypeValidation, "Index value is too high"); + VALIDATE((lnum < MAXLNUM), "Index value is too high", { goto end; - } + }); if (ml_append((linenr_T)lnum, lines[i], 0, false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to insert line"); @@ -800,10 +777,9 @@ ArrayOf(String) nvim_buf_get_text(uint64_t channel_id, Buffer buffer, { Array rv = ARRAY_DICT_INIT; - if (opts.size > 0) { - api_set_error(err, kErrorTypeValidation, "opts dict isn't empty"); + VALIDATE((opts.size == 0), "opts dict isn't empty", { return rv; - } + }); buf_T *buf = find_buffer_by_handle(buffer, err); @@ -820,18 +796,16 @@ ArrayOf(String) nvim_buf_get_text(uint64_t channel_id, Buffer buffer, start_row = normalize_index(buf, start_row, false, &oob); end_row = normalize_index(buf, end_row, false, &oob); - if (oob) { - api_set_error(err, kErrorTypeValidation, "Index out of bounds"); + VALIDATE((!oob), "Index out of bounds", { return rv; - } + }); // nvim_buf_get_lines doesn't care if the start row is greater than the end // row (it will just return an empty array), but nvim_buf_get_text does in // order to maintain symmetry with nvim_buf_set_text. - if (start_row > end_row) { - api_set_error(err, kErrorTypeValidation, "start is higher than end"); + VALIDATE((start_row <= end_row), "start is higher than end", { return rv; - } + }); bool replace_nl = (channel_id != VIML_INTERNAL_CALL); @@ -907,10 +881,9 @@ Integer nvim_buf_get_offset(Buffer buffer, Integer index, Error *err) return -1; } - if (index < 0 || index > buf->b_ml.ml_line_count) { - api_set_error(err, kErrorTypeValidation, "Index out of bounds"); + VALIDATE((index >= 0 && index <= buf->b_ml.ml_line_count), "Index out of bounds", { return 0; - } + }); return ml_find_line_or_offset(buf, (int)index + 1, NULL, true); } @@ -1118,8 +1091,9 @@ void nvim_buf_delete(Buffer buffer, Dictionary opts, Error *err) } else if (strequal("unload", k.data)) { unload = api_object_to_bool(v, "unload", false, err); } else { - api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); - return; + VALIDATE_S(false, "key", k.data, { + return; + }); } } @@ -1174,20 +1148,16 @@ Boolean nvim_buf_del_mark(Buffer buffer, String name, Error *err) return res; } - if (name.size != 1) { - api_set_error(err, kErrorTypeValidation, - "Mark name must be a single character"); + VALIDATE_S((name.size == 1), "mark name (must be a single char)", name.data, { return res; - } + }); fmark_T *fm = mark_get(buf, curwin, NULL, kMarkAllNoResolve, *name.data); // fm is NULL when there's no mark with the given name - if (fm == NULL) { - api_set_error(err, kErrorTypeValidation, "Invalid mark name: '%c'", - *name.data); + VALIDATE_S((fm != NULL), "mark name", name.data, { return res; - } + }); // mark.lnum is 0 when the mark is not valid in the buffer, or is not set. if (fm->mark.lnum != 0 && fm->fnum == buf->handle) { @@ -1224,11 +1194,9 @@ Boolean nvim_buf_set_mark(Buffer buffer, String name, Integer line, Integer col, return res; } - if (name.size != 1) { - api_set_error(err, kErrorTypeValidation, - "Mark name must be a single character"); + VALIDATE_S((name.size == 1), "mark name (must be a single char)", name.data, { return res; - } + }); res = set_mark(buf, name, line, col, err); @@ -1257,21 +1225,18 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err) return rv; } - if (name.size != 1) { - api_set_error(err, kErrorTypeValidation, - "Mark name must be a single character"); + VALIDATE_S((name.size == 1), "mark name (must be a single char)", name.data, { return rv; - } + }); fmark_T *fm; pos_T pos; char mark = *name.data; fm = mark_get(buf, curwin, NULL, kMarkAllNoResolve, mark); - if (fm == NULL) { - api_set_error(err, kErrorTypeValidation, "Invalid mark name"); + VALIDATE_S((fm != NULL), "mark name", name.data, { return rv; - } + }); // (0, 0) uppercase/file mark set in another buffer. if (fm->fnum != buf->handle) { pos.lnum = 0; diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index f09a00e5c2..0a95833256 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -11,6 +11,7 @@ #include "nvim/api/command.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" @@ -99,10 +100,9 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) { Dictionary result = ARRAY_DICT_INIT; - if (opts.size > 0) { - api_set_error(err, kErrorTypeValidation, "opts dict isn't empty"); + VALIDATE((opts.size == 0), "opts dict isn't empty", { return result; - } + }); // Parse command line exarg_T ea; @@ -998,7 +998,7 @@ void nvim_buf_del_user_command(Buffer buffer, String name, Error *err) } } - api_set_error(err, kErrorTypeException, "No such user-defined command: %s", name.data); + api_set_error(err, kErrorTypeException, "Invalid command (not found): %s", name.data); } void create_user_command(String name, Object command, Dict(user_command) *opts, int flags, @@ -1014,20 +1014,17 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, LuaRef compl_luaref = LUA_NOREF; LuaRef preview_luaref = LUA_NOREF; - if (!uc_validate_name(name.data)) { - api_set_error(err, kErrorTypeValidation, "Invalid command name"); + VALIDATE_S(uc_validate_name(name.data), "command name", name.data, { goto err; - } - - if (mb_islower(name.data[0])) { - api_set_error(err, kErrorTypeValidation, "'name' must begin with an uppercase letter"); + }); + VALIDATE_S(!mb_islower(name.data[0]), "command name (must begin with an uppercase letter)", + name.data, { goto err; - } - - if (HAS_KEY(opts->range) && HAS_KEY(opts->count)) { - api_set_error(err, kErrorTypeValidation, "'range' and 'count' are mutually exclusive"); + }); + VALIDATE((!HAS_KEY(opts->range) || !HAS_KEY(opts->count)), + "Cannot use both 'range' and 'count'", { goto err; - } + }); if (opts->nargs.type == kObjectTypeInteger) { switch (opts->nargs.data.integer) { @@ -1038,14 +1035,14 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, argt |= EX_EXTRA | EX_NOSPC | EX_NEEDARG; break; default: - api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'"); - goto err; + VALIDATE_INT(false, "nargs", (int64_t)opts->nargs.data.integer, { + goto err; + }); } } else if (opts->nargs.type == kObjectTypeString) { - if (opts->nargs.data.string.size > 1) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'"); + VALIDATE_S((opts->nargs.data.string.size <= 1), "nargs", opts->nargs.data.string.data, { goto err; - } + }); switch (opts->nargs.data.string.data[0]) { case '*': @@ -1058,18 +1055,19 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, argt |= EX_EXTRA | EX_NEEDARG; break; default: - api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'"); - goto err; + VALIDATE_S(false, "nargs", opts->nargs.data.string.data, { + goto err; + }); } } else if (HAS_KEY(opts->nargs)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'"); - goto err; + VALIDATE_S(false, "nargs", "", { + goto err; + }); } - if (HAS_KEY(opts->complete) && !argt) { - api_set_error(err, kErrorTypeValidation, "'complete' used without 'nargs'"); + VALIDATE((!HAS_KEY(opts->complete) || argt), "'complete' used without 'nargs'", { goto err; - } + }); if (opts->range.type == kObjectTypeBoolean) { if (opts->range.data.boolean) { @@ -1077,13 +1075,12 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, addr_type_arg = ADDR_LINES; } } else if (opts->range.type == kObjectTypeString) { - if (opts->range.data.string.data[0] == '%' && opts->range.data.string.size == 1) { - argt |= EX_RANGE | EX_DFLALL; - addr_type_arg = ADDR_LINES; - } else { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'range'"); + VALIDATE_S((opts->range.data.string.data[0] == '%' && opts->range.data.string.size == 1), + "range", "", { goto err; - } + }); + argt |= EX_RANGE | EX_DFLALL; + addr_type_arg = ADDR_LINES; } else if (opts->range.type == kObjectTypeInteger) { argt |= EX_RANGE | EX_ZEROR; def = opts->range.data.integer; diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index ab3b3485e4..71ba9cfd4c 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -11,6 +11,7 @@ #include "nvim/api/extmark.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/decoration.h" @@ -218,10 +219,9 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, return rv; } - if (!ns_initialized((uint32_t)ns_id)) { - api_set_error(err, kErrorTypeValidation, "Invalid ns_id"); + VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, { return rv; - } + }); bool details = false; for (size_t i = 0; i < opts.size; i++) { @@ -233,12 +233,14 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, } else if (v->type == kObjectTypeInteger) { details = v->data.integer; } else { - api_set_error(err, kErrorTypeValidation, "details is not an boolean"); - return rv; + VALIDATE_EXP(false, "details", "Boolean or Integer", api_typename(v->type), { + return rv; + }); } } else { - api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); - return rv; + VALIDATE_S(false, "key", k.data, { + return rv; + }); } } @@ -301,10 +303,9 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e return rv; } - if (!ns_initialized((uint32_t)ns_id)) { - api_set_error(err, kErrorTypeValidation, "Invalid ns_id"); + VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, { return rv; - } + }); Integer limit = -1; bool details = false; @@ -313,10 +314,9 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e String k = opts.items[i].key; Object *v = &opts.items[i].value; if (strequal("limit", k.data)) { - if (v->type != kObjectTypeInteger) { - api_set_error(err, kErrorTypeValidation, "limit is not an integer"); + VALIDATE_T("limit", kObjectTypeInteger, v->type, { return rv; - } + }); limit = v->data.integer; } else if (strequal("details", k.data)) { if (v->type == kObjectTypeBoolean) { @@ -324,12 +324,14 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e } else if (v->type == kObjectTypeInteger) { details = v->data.integer; } else { - api_set_error(err, kErrorTypeValidation, "details is not an boolean"); - return rv; + VALIDATE_EXP(false, "details", "Boolean or Integer", api_typename(v->type), { + return rv; + }); } } else { - api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); - return rv; + VALIDATE_S(false, "key", k.data, { + return rv; + }); } } @@ -501,27 +503,26 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer goto error; } - if (!ns_initialized((uint32_t)ns_id)) { - api_set_error(err, kErrorTypeValidation, "Invalid ns_id"); + VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, { goto error; - } + }); uint32_t id = 0; if (opts->id.type == kObjectTypeInteger && opts->id.data.integer > 0) { id = (uint32_t)opts->id.data.integer; } else if (HAS_KEY(opts->id)) { - api_set_error(err, kErrorTypeValidation, "id is not a positive integer"); - goto error; + VALIDATE_S(false, "id (must be positive integer)", "", { + goto error; + }); } int line2 = -1; // For backward compatibility we support "end_line" as an alias for "end_row" if (HAS_KEY(opts->end_line)) { - if (HAS_KEY(opts->end_row)) { - api_set_error(err, kErrorTypeValidation, "cannot use both end_row and end_line"); + VALIDATE(!HAS_KEY(opts->end_row), "cannot use both end_row and end_line", { goto error; - } + }); opts->end_row = opts->end_line; } @@ -536,29 +537,28 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer if (opts->end_row.type == kObjectTypeInteger) { Integer val = opts->end_row.data.integer; - if (val < 0 || (val > buf->b_ml.ml_line_count && strict)) { - api_set_error(err, kErrorTypeValidation, "end_row value outside range"); + VALIDATE((val >= 0 && !(val > buf->b_ml.ml_line_count && strict)), + "end_row value outside range", { goto error; - } else { - line2 = (int)val; - } + }); + line2 = (int)val; } else if (HAS_KEY(opts->end_row)) { - api_set_error(err, kErrorTypeValidation, "end_row is not an integer"); - goto error; + VALIDATE_T("end_row", kObjectTypeInteger, opts->end_row.type, { + goto error; + }); } colnr_T col2 = -1; if (opts->end_col.type == kObjectTypeInteger) { Integer val = opts->end_col.data.integer; - if (val < 0 || val > MAXCOL) { - api_set_error(err, kErrorTypeValidation, "end_col value outside range"); + VALIDATE((val >= 0 && val <= MAXCOL), "end_col value outside range", { goto error; - } else { - col2 = (int)val; - } + }); + col2 = (int)val; } else if (HAS_KEY(opts->end_col)) { - api_set_error(err, kErrorTypeValidation, "end_col is not an integer"); - goto error; + VALIDATE_T("end_col", kObjectTypeInteger, opts->end_col.type, { + goto error; + }); } // uncrustify:off @@ -596,8 +596,9 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } has_decor = true; } else if (HAS_KEY(opts->conceal)) { - api_set_error(err, kErrorTypeValidation, "conceal is not a String"); - goto error; + VALIDATE_T("conceal", kObjectTypeString, opts->conceal.type, { + goto error; + }); } if (opts->virt_text.type == kObjectTypeArray) { @@ -608,8 +609,9 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer goto error; } } else if (HAS_KEY(opts->virt_text)) { - api_set_error(err, kErrorTypeValidation, "virt_text is not an Array"); - goto error; + VALIDATE_T("virt_text", kObjectTypeArray, opts->virt_text.type, { + goto error; + }); } if (opts->virt_text_pos.type == kObjectTypeString) { @@ -621,21 +623,23 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } else if (strequal("right_align", str.data)) { decor.virt_text_pos = kVTRightAlign; } else { - api_set_error(err, kErrorTypeValidation, "virt_text_pos: invalid value"); - goto error; + VALIDATE_S(false, "virt_text_pos", "", { + goto error; + }); } } else if (HAS_KEY(opts->virt_text_pos)) { - api_set_error(err, kErrorTypeValidation, "virt_text_pos is not a String"); - goto error; + VALIDATE_T("virt_text_pos", kObjectTypeString, opts->virt_text_pos.type, { + goto error; + }); } if (opts->virt_text_win_col.type == kObjectTypeInteger) { decor.col = (int)opts->virt_text_win_col.data.integer; decor.virt_text_pos = kVTWinCol; } else if (HAS_KEY(opts->virt_text_win_col)) { - api_set_error(err, kErrorTypeValidation, - "virt_text_win_col is not a Number of the correct size"); - goto error; + VALIDATE_T("virt_text_win_col", kObjectTypeInteger, opts->virt_text_win_col.type, { + goto error; + }); } OPTION_TO_BOOL(decor.virt_text_hide, virt_text_hide, false); @@ -650,13 +654,14 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } else if (strequal("blend", str.data)) { decor.hl_mode = kHlModeBlend; } else { - api_set_error(err, kErrorTypeValidation, - "virt_text_pos: invalid value"); - goto error; + VALIDATE_S(false, "virt_text_pos", "", { + goto error; + }); } } else if (HAS_KEY(opts->hl_mode)) { - api_set_error(err, kErrorTypeValidation, "hl_mode is not a String"); - goto error; + VALIDATE_T("hl_mode", kObjectTypeString, opts->hl_mode.type, { + goto error; + }); } bool virt_lines_leftcol = false; @@ -665,10 +670,9 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer if (opts->virt_lines.type == kObjectTypeArray) { Array a = opts->virt_lines.data.array; for (size_t j = 0; j < a.size; j++) { - if (a.items[j].type != kObjectTypeArray) { - api_set_error(err, kErrorTypeValidation, "virt_text_line item is not an Array"); + VALIDATE_T("virt_text_line", kObjectTypeArray, a.items[j].type, { goto error; - } + }); int dummig; VirtText jtem = parse_virt_text(a.items[j].data.array, err, &dummig); kv_push(decor.virt_lines, ((struct virt_line){ jtem, virt_lines_leftcol })); @@ -678,8 +682,9 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer has_decor = true; } } else if (HAS_KEY(opts->virt_lines)) { - api_set_error(err, kErrorTypeValidation, "virt_lines is not an Array"); - goto error; + VALIDATE_T("virt_lines", kObjectTypeArray, opts->virt_lines.type, { + goto error; + }); } OPTION_TO_BOOL(decor.virt_lines_above, virt_lines_above, false); @@ -687,26 +692,26 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer if (opts->priority.type == kObjectTypeInteger) { Integer val = opts->priority.data.integer; - if (val < 0 || val > UINT16_MAX) { - api_set_error(err, kErrorTypeValidation, "priority is not a valid value"); + VALIDATE_S((val >= 0 && val <= UINT16_MAX), "priority", "(out of range)", { goto error; - } + }); decor.priority = (DecorPriority)val; } else if (HAS_KEY(opts->priority)) { - api_set_error(err, kErrorTypeValidation, "priority is not a Number of the correct size"); - goto error; + VALIDATE_T("priority", kObjectTypeInteger, opts->priority.type, { + goto error; + }); } if (opts->sign_text.type == kObjectTypeString) { - if (!init_sign_text(&decor.sign_text, - opts->sign_text.data.string.data)) { - api_set_error(err, kErrorTypeValidation, "sign_text is not a valid value"); + VALIDATE_S(init_sign_text(&decor.sign_text, opts->sign_text.data.string.data), + "sign_text", "", { goto error; - } + }); has_decor = true; } else if (HAS_KEY(opts->sign_text)) { - api_set_error(err, kErrorTypeValidation, "sign_text is not a String"); - goto error; + VALIDATE_T("sign_text", kObjectTypeString, opts->sign_text.type, { + goto error; + }); } bool right_gravity = true; @@ -714,11 +719,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer // Only error out if they try to set end_right_gravity without // setting end_col or end_row - if (line2 == -1 && col2 == -1 && HAS_KEY(opts->end_right_gravity)) { - api_set_error(err, kErrorTypeValidation, - "cannot set end_right_gravity without setting end_row or end_col"); + VALIDATE(!(line2 == -1 && col2 == -1 && HAS_KEY(opts->end_right_gravity)), + "cannot set end_right_gravity without setting end_row or end_col", { goto error; - } + }); bool end_right_gravity = false; OPTION_TO_BOOL(end_right_gravity, end_right_gravity, false); @@ -742,16 +746,15 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer has_decor = true; } - if (line < 0) { - api_set_error(err, kErrorTypeValidation, "line value outside range"); + VALIDATE_S((line >= 0), "line", "(out of range)", { goto error; - } else if (line > buf->b_ml.ml_line_count) { - if (strict) { - api_set_error(err, kErrorTypeValidation, "line value outside range"); + }); + + if (line > buf->b_ml.ml_line_count) { + VALIDATE_S(!strict, "line", "(out of range)", { goto error; - } else { - line = buf->b_ml.ml_line_count; - } + }); + 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)); } @@ -759,15 +762,14 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer if (col == -1) { col = (Integer)len; } else if (col > (Integer)len) { - if (strict) { - api_set_error(err, kErrorTypeValidation, "col value outside range"); + VALIDATE_S(!strict, "col", "(out of range)", { goto error; - } else { - col = (Integer)len; - } + }); + col = (Integer)len; } else if (col < -1) { - api_set_error(err, kErrorTypeValidation, "col value outside range"); - goto error; + VALIDATE_S(false, "col", "(out of range)", { + goto error; + }); } if (col2 >= 0) { @@ -781,12 +783,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer line2 = (int)line; } if (col2 > (Integer)len) { - if (strict) { - api_set_error(err, kErrorTypeValidation, "end_col value outside range"); + VALIDATE_S(!strict, "end_col", "(out of range)", { goto error; - } else { - col2 = (int)len; - } + }); + col2 = (int)len; } } else if (line2 >= 0) { col2 = 0; @@ -829,10 +829,9 @@ Boolean nvim_buf_del_extmark(Buffer buffer, Integer ns_id, Integer id, Error *er if (!buf) { return false; } - if (!ns_initialized((uint32_t)ns_id)) { - api_set_error(err, kErrorTypeValidation, "Invalid ns_id"); + VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, { return false; - } + }); return extmark_del(buf, (uint32_t)ns_id, (uint32_t)id); } @@ -887,14 +886,13 @@ Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, In return 0; } - if (line < 0 || line >= MAXLNUM) { - api_set_error(err, kErrorTypeValidation, "Line number outside range"); + VALIDATE_S((line >= 0 && line < MAXLNUM), "line number", "(out of range)", { return 0; - } - if (col_start < 0 || col_start > MAXCOL) { - api_set_error(err, kErrorTypeValidation, "Column value outside range"); + }); + VALIDATE_S((col_start >= 0 && col_start <= MAXCOL), "column", "(out of range)", { return 0; - } + }); + if (col_end < 0 || col_end > MAXCOL) { col_end = MAXCOL; } @@ -950,10 +948,10 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, return; } - if (line_start < 0 || line_start >= MAXLNUM) { - api_set_error(err, kErrorTypeValidation, "Line number outside range"); + VALIDATE_S((line_start >= 0 && line_start < MAXLNUM), "line number", "(out of range)", { return; - } + }); + if (line_end < 0 || line_end > MAXLNUM) { line_end = MAXLNUM; } @@ -1034,11 +1032,10 @@ void nvim_set_decoration_provider(Integer ns_id, Dict(set_decoration_provider) * continue; } - if (v->type != kObjectTypeLuaRef) { - api_set_error(err, kErrorTypeValidation, - "%s is not a function", cbs[i].name); + VALIDATE_T(cbs[i].name, kObjectTypeLuaRef, v->type, { goto error; - } + }); + *(cbs[i].dest) = v->data.luaref; v->data.luaref = LUA_NOREF; } @@ -1075,39 +1072,39 @@ static bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, in *col = MAXCOL; return true; } else if (id < 0) { - api_set_error(err, kErrorTypeValidation, "Mark id must be positive"); - return false; + VALIDATE_INT(false, "mark id", id, { + return false; + }); } ExtmarkInfo extmark = extmark_from_id(buf, (uint32_t)ns_id, (uint32_t)id); - if (extmark.row >= 0) { - *row = extmark.row; - *col = extmark.col; - return true; - } else { - api_set_error(err, kErrorTypeValidation, "No mark with requested id"); + + VALIDATE_INT((extmark.row >= 0), "mark id (not found)", id, { return false; - } + }); + *row = extmark.row; + *col = extmark.col; + return true; // Check if it is a position } else if (obj.type == kObjectTypeArray) { Array pos = obj.data.array; - if (pos.size != 2 - || pos.items[0].type != kObjectTypeInteger - || pos.items[1].type != kObjectTypeInteger) { - api_set_error(err, kErrorTypeValidation, - "Position must have 2 integer elements"); + VALIDATE((pos.size == 2 + && pos.items[0].type == kObjectTypeInteger + && pos.items[1].type == kObjectTypeInteger), + "Invalid position: expected 2 Integer items", { return false; - } + }); + Integer pos_row = pos.items[0].data.integer; Integer pos_col = pos.items[1].data.integer; *row = (int)(pos_row >= 0 ? pos_row : MAXLNUM); *col = (colnr_T)(pos_col >= 0 ? pos_col : MAXCOL); return true; } else { - api_set_error(err, kErrorTypeValidation, - "Position must be a mark id Integer or position Array"); - return false; + VALIDATE(false, "Invalid position: expected mark id Integer or 2-item Array", { + return false; + }); } } // adapted from sign.c:sign_define_init_text. @@ -1151,17 +1148,14 @@ 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"); + VALIDATE_T("chunk", kObjectTypeArray, chunks.items[i].type, { goto free_exit; - } + }); Array chunk = chunks.items[i].data.array; - if (chunk.size == 0 || chunk.size > 2 - || chunk.items[0].type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, - "Chunk is not an array with one or two strings"); + VALIDATE((chunk.size > 0 && chunk.size <= 2 && chunk.items[0].type == kObjectTypeString), + "Invalid chunk: expected Array with 1 or 2 Strings", { goto free_exit; - } + }); String str = chunk.items[0].data.string; diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 2a54c3b132..5b57b49ad6 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -9,6 +9,7 @@ #include "nvim/api/options.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/eval/window.h" @@ -31,11 +32,14 @@ static int validate_option_value_args(Dict(option) *opts, int *scope, int *opt_t } else if (!strcmp(opts->scope.data.string.data, "global")) { *scope = OPT_GLOBAL; } else { - api_set_error(err, kErrorTypeValidation, "invalid scope: must be 'local' or 'global'"); - return FAIL; + VALIDATE(false, "Invalid scope (expected 'local' or 'global')", { + return FAIL; + }); } } else if (HAS_KEY(opts->scope)) { - api_set_error(err, kErrorTypeValidation, "invalid value for key: scope"); + VALIDATE_T("scope", kObjectTypeString, opts->scope.type, { + return FAIL; + }); return FAIL; } @@ -48,8 +52,9 @@ static int validate_option_value_args(Dict(option) *opts, int *scope, int *opt_t return FAIL; } } else if (HAS_KEY(opts->win)) { - api_set_error(err, kErrorTypeValidation, "invalid value for key: win"); - return FAIL; + VALIDATE_T("win", kObjectTypeInteger, opts->win.type, { + return FAIL; + }); } if (opts->buf.type == kObjectTypeInteger) { @@ -60,19 +65,17 @@ static int validate_option_value_args(Dict(option) *opts, int *scope, int *opt_t return FAIL; } } else if (HAS_KEY(opts->buf)) { - api_set_error(err, kErrorTypeValidation, "invalid value for key: buf"); - return FAIL; + VALIDATE_T("buf", kObjectTypeInteger, opts->buf.type, { + return FAIL; + }); } - if (HAS_KEY(opts->scope) && HAS_KEY(opts->buf)) { - api_set_error(err, kErrorTypeValidation, "scope and buf cannot be used together"); + VALIDATE((!HAS_KEY(opts->scope) || !HAS_KEY(opts->buf)), "cannot use both 'scope' and 'buf'", { return FAIL; - } - - if (HAS_KEY(opts->win) && HAS_KEY(opts->buf)) { - api_set_error(err, kErrorTypeValidation, "buf and win cannot be used together"); + }); + VALIDATE((!HAS_KEY(opts->win) || !HAS_KEY(opts->buf)), "cannot use both 'buf' and 'win'", { return FAIL; - } + }); return OK; } @@ -132,8 +135,9 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) } break; default: - api_set_error(err, kErrorTypeValidation, "unknown option '%s'", name.data); - return rv; + VALIDATE_S(false, "option", name.data, { + return rv; + }); } return rv; @@ -193,8 +197,9 @@ void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error scope |= OPT_CLEAR; break; default: - api_set_error(err, kErrorTypeValidation, "invalid value for option"); - return; + VALIDATE_EXP(false, "option type", "Integer, Boolean, or String", api_typename(value.type), { + return; + }); } access_option_value_for(name.data, &numval, &stringval, scope, opt_type, to, false, err); @@ -351,21 +356,18 @@ static Object get_option_from(void *from, int type, String name, Error *err) { Object rv = OBJECT_INIT; - if (name.size == 0) { - api_set_error(err, kErrorTypeValidation, "Empty option name"); + VALIDATE_S(name.size > 0, "option name", "", { return rv; - } + }); // Return values int64_t numval; char *stringval = NULL; - int flags = get_option_value_strict(name.data, &numval, &stringval, type, from); - if (!flags) { - api_set_error(err, kErrorTypeValidation, "Invalid option name: '%s'", - name.data); + int flags = get_option_value_strict(name.data, &numval, &stringval, type, from); + VALIDATE_S(flags != 0, "option name", name.data, { return rv; - } + }); if (flags & SOPT_BOOL) { rv.type = kObjectTypeBoolean; @@ -374,20 +376,15 @@ static Object get_option_from(void *from, int type, String name, Error *err) rv.type = kObjectTypeInteger; rv.data.integer = numval; } else if (flags & SOPT_STRING) { - if (stringval) { - rv.type = kObjectTypeString; - rv.data.string.data = stringval; - rv.data.string.size = strlen(stringval); - } else { - api_set_error(err, kErrorTypeException, - "Failed to get value for option '%s'", - name.data); + if (!stringval) { + api_set_error(err, kErrorTypeException, "Failed to get option '%s'", name.data); + return rv; } + rv.type = kObjectTypeString; + rv.data.string.data = stringval; + rv.data.string.size = strlen(stringval); } else { - api_set_error(err, - kErrorTypeException, - "Unknown type for option '%s'", - name.data); + api_set_error(err, kErrorTypeException, "Unknown type for option '%s'", name.data); } return rv; @@ -402,29 +399,22 @@ static Object get_option_from(void *from, int type, String name, Error *err) /// @param[out] err Details of an error that may have occurred void set_option_to(uint64_t channel_id, void *to, int type, String name, Object value, Error *err) { - if (name.size == 0) { - api_set_error(err, kErrorTypeValidation, "Empty option name"); + VALIDATE_S(name.size > 0, "option name", "", { return; - } + }); int flags = get_option_value_strict(name.data, NULL, NULL, type, to); - - if (flags == 0) { - api_set_error(err, kErrorTypeValidation, "Invalid option name '%s'", - name.data); + VALIDATE_S(flags != 0, "option name", name.data, { return; - } + }); if (value.type == kObjectTypeNil) { if (type == SREQ_GLOBAL) { - api_set_error(err, kErrorTypeException, "Cannot unset option '%s'", - name.data); + api_set_error(err, kErrorTypeException, "Cannot unset option '%s'", name.data); return; } else if (!(flags & SOPT_GLOBAL)) { - api_set_error(err, - kErrorTypeException, - "Cannot unset option '%s' " - "because it doesn't have a global value", + api_set_error(err, kErrorTypeException, + "Cannot unset option '%s' because it doesn't have a global value", name.data); return; } else { @@ -437,39 +427,23 @@ void set_option_to(uint64_t channel_id, void *to, int type, String name, Object char *stringval = NULL; if (flags & SOPT_BOOL) { - if (value.type != kObjectTypeBoolean) { - api_set_error(err, - kErrorTypeValidation, - "Option '%s' requires a Boolean value", - name.data); + VALIDATE_FMT(value.type == kObjectTypeBoolean, "Option '%s' value must be Boolean", name.data, { return; - } - + }); numval = value.data.boolean; } else if (flags & SOPT_NUM) { - if (value.type != kObjectTypeInteger) { - api_set_error(err, kErrorTypeValidation, - "Option '%s' requires an integer value", - name.data); + VALIDATE_FMT(value.type == kObjectTypeInteger, "Option '%s' value must be Integer", name.data, { return; - } - - if (value.data.integer > INT_MAX || value.data.integer < INT_MIN) { - api_set_error(err, kErrorTypeValidation, - "Value for option '%s' is out of range", - name.data); + }); + VALIDATE_FMT((value.data.integer <= INT_MAX && value.data.integer >= INT_MIN), + "Option '%s' value is out of range", name.data, { return; - } - + }); numval = (int)value.data.integer; } else { - if (value.type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, - "Option '%s' requires a string value", - name.data); + VALIDATE_FMT(value.type == kObjectTypeString, "Option '%s' value must be String", name.data, { return; - } - + }); stringval = value.data.string.data; } diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 519f2cc5bf..6beb3d8683 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -827,6 +827,36 @@ int object_to_hl_id(Object obj, const char *what, Error *err) } } +char *api_typename(ObjectType t) +{ + switch (t) { + case kObjectTypeNil: + return "nil"; + case kObjectTypeBoolean: + return "Boolean"; + case kObjectTypeInteger: + return "Integer"; + case kObjectTypeFloat: + return "Float"; + case kObjectTypeString: + return "String"; + case kObjectTypeArray: + return "Array"; + case kObjectTypeDictionary: + return "Dict"; + case kObjectTypeLuaRef: + return "Function"; + case kObjectTypeBuffer: + return "Buffer"; + case kObjectTypeWindow: + return "Window"; + case kObjectTypeTabpage: + return "Tabpage"; + default: + abort(); + } +} + HlMessage parse_hl_msg(Array chunks, Error *err) { HlMessage hl_msg = KV_INITIAL_VALUE; diff --git a/src/nvim/api/private/validate.h b/src/nvim/api/private/validate.h new file mode 100644 index 0000000000..8448b416be --- /dev/null +++ b/src/nvim/api/private/validate.h @@ -0,0 +1,69 @@ +#ifndef NVIM_API_PRIVATE_VALIDATE_H +#define NVIM_API_PRIVATE_VALIDATE_H + +#include "nvim/api/private/defs.h" +#include "nvim/api/private/helpers.h" + +#define VALIDATE_INT(cond, name, val_, code) \ + do { \ + if (!(cond)) { \ + api_set_error(err, kErrorTypeValidation, "Invalid " name ": %" PRId64, val_); \ + code; \ + } \ + } while (0) + +#define VALIDATE_S(cond, name, val_, code) \ + do { \ + if (!(cond)) { \ + if (strequal(val_, "")) { \ + api_set_error(err, kErrorTypeValidation, "Invalid " name); \ + } else { \ + api_set_error(err, kErrorTypeValidation, "Invalid " name ": '%s'", val_); \ + } \ + code; \ + } \ + } while (0) + +#define VALIDATE_R(cond, name, code) \ + do { \ + if (!(cond)) { \ + api_set_error(err, kErrorTypeValidation, "'" name "' is required"); \ + code; \ + } \ + } while (0) + +#define VALIDATE_EXP(cond, name, expected, actual, code) \ + do { \ + if (!(cond)) { \ + api_set_error(err, kErrorTypeValidation, "Invalid " name ": expected %s, got %s", \ + expected, actual); \ + code; \ + } \ + } while (0) + +#define VALIDATE_T(name, expected_t, actual_t, code) \ + do { \ + if (expected_t != actual_t) { \ + api_set_error(err, kErrorTypeValidation, "Invalid %s: expected %s, got %s", \ + name, api_typename(expected_t), api_typename(actual_t)); \ + code; \ + } \ + } while (0) + +#define VALIDATE(cond, msg_, code) \ + do { \ + if (!(cond)) { \ + api_set_error(err, kErrorTypeValidation, "%s", msg_); \ + code; \ + } \ + } while (0) + +#define VALIDATE_FMT(cond, fmt_, msg_, code) \ + do { \ + if (!(cond)) { \ + api_set_error(err, kErrorTypeValidation, fmt_, msg_); \ + code; \ + } \ + } while (0) + +#endif // NVIM_API_PRIVATE_VALIDATE_H diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 12ab40a687..333749c42f 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -18,6 +18,7 @@ #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/api/vim.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" @@ -193,10 +194,9 @@ void nvim_set_hl(Integer ns_id, String name, Dict(highlight) *val, Error *err) void nvim_set_hl_ns(Integer ns_id, Error *err) FUNC_API_SINCE(10) { - if (ns_id < 0) { - api_set_error(err, kErrorTypeValidation, "no such namespace"); + VALIDATE_INT((ns_id >= 0), "namespace", ns_id, { return; - } + }); ns_hl_global = (NS)ns_id; hl_check_ns(); @@ -500,10 +500,9 @@ Object nvim_notify(String msg, Integer log_level, Dictionary opts, Error *err) Integer nvim_strwidth(String text, Error *err) FUNC_API_SINCE(1) { - if (text.size > INT_MAX) { - api_set_error(err, kErrorTypeValidation, "String is too long"); + VALIDATE((text.size <= INT_MAX), "text length (too long)", { return 0; - } + }); return (Integer)mb_string2cells(text.data); } @@ -575,9 +574,7 @@ ArrayOf(String) nvim__get_runtime(Array pat, Boolean all, Dict(runtime) *opts, E { bool is_lua = api_object_to_bool(opts->is_lua, "is_lua", false, err); bool source = api_object_to_bool(opts->do_source, "do_source", false, err); - if (source && !nlua_is_deferred_safe()) { - api_set_error(err, kErrorTypeValidation, "'do_source' cannot be used in fast callback"); - } + VALIDATE((!source || nlua_is_deferred_safe()), "'do_source' used in fast callback", {}); if (ERROR_SET(err)) { return (Array)ARRAY_DICT_INIT; @@ -602,10 +599,9 @@ ArrayOf(String) nvim__get_runtime(Array pat, Boolean all, Dict(runtime) *opts, E void nvim_set_current_dir(String dir, Error *err) FUNC_API_SINCE(1) { - if (dir.size >= MAXPATHL) { - api_set_error(err, kErrorTypeValidation, "Directory name is too long"); + VALIDATE((dir.size < MAXPATHL), "directory name (too long)", { return; - } + }); char string[MAXPATHL]; memcpy(string, dir.data, dir.size); @@ -664,16 +660,14 @@ Object nvim_get_var(String name, Error *err) { dictitem_T *di = tv_dict_find(&globvardict, name.data, (ptrdiff_t)name.size); if (di == NULL) { // try to autoload script - if (!script_autoload(name.data, name.size, false) || aborting()) { - api_set_error(err, kErrorTypeValidation, "Key not found: %s", name.data); + VALIDATE_S((script_autoload(name.data, name.size, false) && !aborting()), "key", name.data, { return (Object)OBJECT_INIT; - } + }); di = tv_dict_find(&globvardict, name.data, (ptrdiff_t)name.size); } - if (di == NULL) { - api_set_error(err, kErrorTypeValidation, "Key not found: %s", name.data); + VALIDATE_S((di != NULL), "key (not found)", name.data, { return (Object)OBJECT_INIT; - } + }); return vim_to_object(&di->di_tv); } @@ -991,16 +985,14 @@ Integer nvim_open_term(Buffer buffer, DictionaryOf(LuaRef) opts, Error *err) String k = opts.items[i].key; Object *v = &opts.items[i].value; if (strequal("on_input", k.data)) { - if (v->type != kObjectTypeLuaRef) { - api_set_error(err, kErrorTypeValidation, - "%s is not a function", "on_input"); + VALIDATE_T("on_input", kObjectTypeLuaRef, v->type, { return 0; - } + }); cb = v->data.luaref; v->data.luaref = LUA_NOREF; break; } else { - api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); + VALIDATE_S(false, "key", k.data, {}); } } @@ -1075,9 +1067,7 @@ void nvim_chan_send(Integer chan, String data, Error *err) channel_send((uint64_t)chan, data.data, data.size, false, &error); - if (error) { - api_set_error(err, kErrorTypeValidation, "%s", error); - } + VALIDATE(!error, error, {}); } /// Gets the current list of tabpage handles. @@ -1164,10 +1154,9 @@ Boolean nvim_paste(String data, Boolean crlf, Integer phase, Error *err) static bool draining = false; bool cancel = false; - if (phase < -1 || phase > 3) { - api_set_error(err, kErrorTypeValidation, "Invalid phase: %" PRId64, phase); + VALIDATE_INT((phase >= -1 && phase <= 3), "phase", phase, { return false; - } + }); Array args = ARRAY_DICT_INIT; Object rv = OBJECT_INIT; if (phase == -1 || phase == 1) { // Start of paste-stream. @@ -1234,20 +1223,17 @@ void nvim_put(ArrayOf(String) lines, String type, Boolean after, Boolean follow, FUNC_API_CHECK_TEXTLOCK { yankreg_T *reg = xcalloc(1, sizeof(yankreg_T)); - if (!prepare_yankreg_from_object(reg, type, lines.size)) { - api_set_error(err, kErrorTypeValidation, "Invalid type: '%s'", type.data); + VALIDATE_S((prepare_yankreg_from_object(reg, type, lines.size)), "type", type.data, { goto cleanup; - } + }); if (lines.size == 0) { goto cleanup; // Nothing to do. } for (size_t i = 0; i < lines.size; i++) { - if (lines.items[i].type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, - "Invalid lines (expected array of strings)"); + VALIDATE_T("line", kObjectTypeString, lines.items[i].type, { goto cleanup; - } + }); String line = lines.items[i].data.string; reg->y_array[i] = xmemdupz(line.data, line.size); memchrsub(reg->y_array[i], NUL, NL, line.size); @@ -1351,8 +1337,9 @@ Dictionary nvim_get_context(Dict(context) *opts, Error *err) if (opts->types.type == kObjectTypeArray) { types = opts->types.data.array; } else if (opts->types.type != kObjectTypeNil) { - api_set_error(err, kErrorTypeValidation, "invalid value for key: types"); - return (Dictionary)ARRAY_DICT_INIT; + VALIDATE_T("types", kObjectTypeArray, opts->types.type, { + return (Dictionary)ARRAY_DICT_INIT; + }); } int int_types = types.size > 0 ? 0 : kCtxAll; @@ -1373,8 +1360,9 @@ Dictionary nvim_get_context(Dict(context) *opts, Error *err) } else if (strequal(s, "funcs")) { int_types |= kCtxFuncs; } else { - api_set_error(err, kErrorTypeValidation, "unexpected type: %s", s); - return (Dictionary)ARRAY_DICT_INIT; + VALIDATE_S(false, "type", s, { + return (Dictionary)ARRAY_DICT_INIT; + }); } } } @@ -1651,34 +1639,20 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Arena *arena, Error *er size_t i; // also used for freeing the variables for (i = 0; i < calls.size; i++) { - if (calls.items[i].type != kObjectTypeArray) { - api_set_error(err, - kErrorTypeValidation, - "Items in calls array must be arrays"); + VALIDATE_T("calls item", kObjectTypeArray, calls.items[i].type, { goto theend; - } + }); Array call = calls.items[i].data.array; - if (call.size != 2) { - api_set_error(err, - kErrorTypeValidation, - "Items in calls array must be arrays of size 2"); + VALIDATE((call.size == 2), "Items in calls array must be arrays of size 2", { goto theend; - } - - if (call.items[0].type != kObjectTypeString) { - api_set_error(err, - kErrorTypeValidation, - "Name must be String"); + }); + VALIDATE_T("name", kObjectTypeString, call.items[0].type, { goto theend; - } + }); String name = call.items[0].data.string; - - if (call.items[1].type != kObjectTypeArray) { - api_set_error(err, - kErrorTypeValidation, - "Args must be Array"); + VALIDATE_T("args", kObjectTypeArray, call.items[1].type, { goto theend; - } + }); Array args = call.items[1].data.array; MsgpackRpcRequestHandler handler = @@ -1937,10 +1911,9 @@ void nvim_select_popupmenu_item(Integer item, Boolean insert, Boolean finish, Di Error *err) FUNC_API_SINCE(6) { - if (opts.size > 0) { - api_set_error(err, kErrorTypeValidation, "opts dict isn't empty"); + VALIDATE((opts.size == 0), "opts dict isn't empty", { return; - } + }); if (finish) { insert = true; @@ -1961,13 +1934,10 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Arena *arena, E g = &pum_grid; } else if (grid > 1) { win_T *wp = get_win_by_grid_handle((handle_T)grid); - if (wp != NULL && wp->w_grid_alloc.chars != NULL) { - g = &wp->w_grid_alloc; - } else { - api_set_error(err, kErrorTypeValidation, - "No grid with the given handle"); + VALIDATE_INT((wp != NULL && wp->w_grid_alloc.chars != NULL), "grid handle", grid, { return ret; - } + }); + g = &wp->w_grid_alloc; } if (row < 0 || row >= g->rows @@ -2009,20 +1979,16 @@ Boolean nvim_del_mark(String name, Error *err) FUNC_API_SINCE(8) { bool res = false; - if (name.size != 1) { - api_set_error(err, kErrorTypeValidation, - "Mark name must be a single character"); + VALIDATE_S((name.size == 1), "mark name (must be a single char)", name.data, { return res; - } + }); // Only allow file/uppercase marks // TODO(muniter): Refactor this ASCII_ISUPPER macro to a proper function - if (ASCII_ISUPPER(*name.data) || ascii_isdigit(*name.data)) { - res = set_mark(NULL, name, 0, 0, err); - } else { - api_set_error(err, kErrorTypeValidation, - "Only file/uppercase marks allowed, invalid mark name: '%c'", - *name.data); - } + VALIDATE_S((ASCII_ISUPPER(*name.data) || ascii_isdigit(*name.data)), + "mark name (must be file/uppercase)", name.data, { + return res; + }); + res = set_mark(NULL, name, 0, 0, err); return res; } @@ -2043,16 +2009,13 @@ Array nvim_get_mark(String name, Dictionary opts, Error *err) { Array rv = ARRAY_DICT_INIT; - if (name.size != 1) { - api_set_error(err, kErrorTypeValidation, - "Mark name must be a single character"); + VALIDATE_S((name.size == 1), "mark name (must be a single char)", name.data, { return rv; - } else if (!(ASCII_ISUPPER(*name.data) || ascii_isdigit(*name.data))) { - api_set_error(err, kErrorTypeValidation, - "Only file/uppercase marks allowed, invalid mark name: '%c'", - *name.data); + }); + VALIDATE_S((ASCII_ISUPPER(*name.data) || ascii_isdigit(*name.data)), + "mark name (must be file/uppercase)", name.data, { return rv; - } + }); xfmark_T *mark = mark_get_global(false, *name.data); // false avoids loading the mark buffer pos_T pos = mark->fmark.mark; @@ -2137,27 +2100,28 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * if (str.size < 2 || memcmp(str.data, "%!", 2) != 0) { const char *const errmsg = check_stl_option(str.data); - if (errmsg) { - api_set_error(err, kErrorTypeValidation, "%s", errmsg); + VALIDATE(!errmsg, errmsg, { return result; - } + }); } if (HAS_KEY(opts->winid)) { - if (opts->winid.type != kObjectTypeInteger) { - api_set_error(err, kErrorTypeValidation, "winid must be an integer"); + VALIDATE_T("winid", kObjectTypeInteger, opts->winid.type, { return result; - } + }); window = (Window)opts->winid.data.integer; } if (HAS_KEY(opts->fillchar)) { - if (opts->fillchar.type != kObjectTypeString || opts->fillchar.data.string.size == 0 - || ((size_t)utf_ptr2len(opts->fillchar.data.string.data) - != opts->fillchar.data.string.size)) { - api_set_error(err, kErrorTypeValidation, "fillchar must be a single character"); + VALIDATE_T("fillchar", kObjectTypeString, opts->fillchar.type, { return result; - } + }); + VALIDATE((opts->fillchar.data.string.size != 0 + && ((size_t)utf_ptr2len(opts->fillchar.data.string.data) + == opts->fillchar.data.string.size)), + "Invalid fillchar (not a single character)", { + return result; + }); fillchar = utf_ptr2char(opts->fillchar.data.string.data); } if (HAS_KEY(opts->highlights)) { @@ -2211,10 +2175,9 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * } if (HAS_KEY(opts->maxwidth)) { - if (opts->maxwidth.type != kObjectTypeInteger) { - api_set_error(err, kErrorTypeValidation, "maxwidth must be an integer"); + VALIDATE_T("maxwidth", kObjectTypeInteger, opts->maxwidth.type, { return result; - } + }); maxwidth = (int)opts->maxwidth.data.integer; } else { -- cgit From ff3d04b75b4a9314815c37d53ebc4d035a043335 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 14 Feb 2023 08:07:38 -0500 Subject: refactor(api): VALIDATE macros #22256 - VALIDATE() takes a format string - deduplicate check_string_array - VALIDATE_RANGE - validate UI args --- src/nvim/api/autocmd.c | 74 +++++++++---------------- src/nvim/api/buffer.c | 53 +++++++----------- src/nvim/api/command.c | 62 +++++++++++---------- src/nvim/api/extmark.c | 117 ++++++++++++++++++++-------------------- src/nvim/api/options.c | 46 ++++++++-------- src/nvim/api/private/helpers.c | 3 +- src/nvim/api/private/validate.c | 28 ++++++++++ src/nvim/api/private/validate.h | 27 +++++----- src/nvim/api/ui.c | 66 ++++++++++------------- src/nvim/api/vim.c | 59 +++++++++----------- 10 files changed, 253 insertions(+), 282 deletions(-) create mode 100644 src/nvim/api/private/validate.c (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 9aadd48a13..36d3e04f54 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -125,7 +125,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) }); } - if (opts->event.type != kObjectTypeNil) { + if (HAS_KEY(opts->event)) { check_event = true; Object v = opts->event; @@ -148,13 +148,13 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) } } - VALIDATE((opts->pattern.type == kObjectTypeNil || opts->buffer.type == kObjectTypeNil), - "Cannot use both 'pattern' and 'buffer'", { + VALIDATE((!HAS_KEY(opts->pattern) || !HAS_KEY(opts->buffer)), + "%s", "Cannot use both 'pattern' and 'buffer'", { goto cleanup; }); int pattern_filter_count = 0; - if (opts->pattern.type != kObjectTypeNil) { + if (HAS_KEY(opts->pattern)) { Object v = opts->pattern; if (v.type == kObjectTypeString) { pattern_filters[pattern_filter_count] = v.data.string.data; @@ -210,7 +210,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) snprintf(pattern_buflocal, BUFLOCAL_PAT_LEN, "", (int)buf->handle); ADD(buffers, CSTR_TO_OBJ(pattern_buflocal)); }); - } else if (opts->buffer.type != kObjectTypeNil) { + } else if (HAS_KEY(opts->buffer)) { VALIDATE_EXP(false, "buffer", "Integer or Array", api_typename(opts->buffer.type), { goto cleanup; }); @@ -413,10 +413,8 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc { int64_t autocmd_id = -1; char *desc = NULL; - Array patterns = ARRAY_DICT_INIT; Array event_array = ARRAY_DICT_INIT; - AucmdExecutable aucmd = AUCMD_EXECUTABLE_INIT; Callback cb = CALLBACK_NONE; @@ -424,12 +422,12 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc goto cleanup; } - VALIDATE((opts->callback.type == kObjectTypeNil || opts->command.type == kObjectTypeNil), - "Cannot use both 'callback' and 'command'", { + VALIDATE((!HAS_KEY(opts->callback) || !HAS_KEY(opts->command)), + "%s", "Cannot use both 'callback' and 'command'", { goto cleanup; }); - if (opts->callback.type != kObjectTypeNil) { + if (HAS_KEY(opts->callback)) { // NOTE: We could accept callable tables, but that isn't common in the API. Object *callback = &opts->callback; @@ -458,7 +456,7 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc aucmd.type = CALLABLE_CB; aucmd.callable.cb = cb; - } else if (opts->command.type != kObjectTypeNil) { + } else if (HAS_KEY(opts->command)) { Object *command = &opts->command; VALIDATE_T("command", kObjectTypeString, command->type, { goto cleanup; @@ -466,7 +464,7 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc aucmd.type = CALLABLE_EX; aucmd.callable.cmd = string_to_cstr(command->data.string); } else { - VALIDATE_S(false, "'command' or 'callback' is required", "", { + VALIDATE(false, "%s", "Required: 'command' or 'callback'", { goto cleanup; }); } @@ -483,7 +481,7 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc goto cleanup; } - if (opts->desc.type != kObjectTypeNil) { + if (HAS_KEY(opts->desc)) { VALIDATE_T("desc", kObjectTypeString, opts->desc.type, { goto cleanup; }); @@ -494,7 +492,7 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc ADD(patterns, STRING_OBJ(STATIC_CSTR_TO_STRING("*"))); } - VALIDATE_R((event_array.size != 0), "event", { + VALIDATE_R((event_array.size > 0), "event", { goto cleanup; }); @@ -586,8 +584,8 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err) goto cleanup; } - VALIDATE((opts->pattern.type == kObjectTypeNil || opts->buffer.type == kObjectTypeNil), - "Cannot use both 'pattern' and 'buffer'", { + VALIDATE((!HAS_KEY(opts->pattern) || !HAS_KEY(opts->buffer)), + "%s", "Cannot use both 'pattern' and 'buffer'", { goto cleanup; }); @@ -764,7 +762,7 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err) }); } - if (opts->buffer.type != kObjectTypeNil) { + if (HAS_KEY(opts->buffer)) { Object buf_obj = opts->buffer; VALIDATE_EXP((buf_obj.type == kObjectTypeInteger || buf_obj.type == kObjectTypeBuffer), "buffer", "Integer", api_typename(buf_obj.type), { @@ -786,7 +784,7 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err) ADD(patterns, STRING_OBJ(STATIC_CSTR_TO_STRING(""))); } - if (opts->data.type != kObjectTypeNil) { + if (HAS_KEY(opts->data)) { data = &opts->data; } @@ -797,7 +795,7 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err) GET_ONE_EVENT(event_nr, event_str, cleanup) FOREACH_ITEM(patterns, pat, { - char *fname = opts->buffer.type == kObjectTypeNil ? pat.data.string.data : NULL; + char *fname = !HAS_KEY(opts->buffer) ? pat.data.string.data : NULL; did_aucmd |= apply_autocmds_group(event_nr, fname, NULL, true, au_group, buf, NULL, data); }) @@ -812,41 +810,19 @@ cleanup: api_free_array(patterns); } -static bool check_autocmd_string_array(Array arr, char *k, Error *err) -{ - FOREACH_ITEM(arr, entry, { - if (entry.type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, "Invalid '%s' item type: expected String, got %s", - k, api_typename(entry.type)); - return false; - } - - // Disallow newlines in the middle of the line. - const String l = entry.data.string; - if (memchr(l.data, NL, l.size)) { - api_set_error(err, kErrorTypeValidation, "'%s' item cannot contain newlines", k); - return false; - } - }) - return true; -} - static bool unpack_string_or_array(Array *array, Object *v, char *k, bool required, Error *err) { if (v->type == kObjectTypeString) { ADD(*array, copy_object(*v, NULL)); } else if (v->type == kObjectTypeArray) { - if (!check_autocmd_string_array(v->data.array, k, err)) { + if (!check_string_array(v->data.array, k, true, err)) { return false; } *array = copy_array(v->data.array, NULL); } else { - if (required) { - api_set_error(err, kErrorTypeValidation, - "Invalid '%s' type: expected Array or String, got %s", - k, api_typename(v->type)); + VALIDATE_EXP(!required, k, "Array or String", api_typename(v->type), { return false; - } + }); } return true; @@ -886,12 +862,12 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob { const char pattern_buflocal[BUFLOCAL_PAT_LEN]; - VALIDATE((pattern.type == kObjectTypeNil || buffer.type == kObjectTypeNil), - "Cannot use both 'pattern' and 'buffer' for the same autocmd", { + VALIDATE((!HAS_KEY(pattern) || !HAS_KEY(buffer)), + "%s", "Cannot use both 'pattern' and 'buffer' for the same autocmd", { return false; }); - if (pattern.type != kObjectTypeNil) { + if (HAS_KEY(pattern)) { Object *v = &pattern; if (v->type == kObjectTypeString) { @@ -904,7 +880,7 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob patlen = aucmd_pattern_length(pat); } } else if (v->type == kObjectTypeArray) { - if (!check_autocmd_string_array(v->data.array, "pattern", err)) { + if (!check_string_array(v->data.array, "pattern", true, err)) { return false; } @@ -924,7 +900,7 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob return false; }); } - } else if (buffer.type != kObjectTypeNil) { + } else if (HAS_KEY(buffer)) { VALIDATE_EXP((buffer.type == kObjectTypeInteger || buffer.type == kObjectTypeBuffer), "buffer", "Integer", api_typename(buffer.type), { return false; diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index b2e78db278..9c2d14d30f 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -293,7 +293,7 @@ ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id, start = normalize_index(buf, start, true, &oob); end = normalize_index(buf, end, true, &oob); - VALIDATE((!strict_indexing || !oob), "Index out of bounds", { + VALIDATE((!strict_indexing || !oob), "%s", "Index out of bounds", { return rv; }); @@ -320,23 +320,6 @@ end: return rv; } -static bool check_string_array(Array arr, bool disallow_nl, Error *err) -{ - for (size_t i = 0; i < arr.size; i++) { - VALIDATE_T("replacement item", kObjectTypeString, arr.items[i].type, { - return false; - }); - // Disallow newlines in the middle of the line. - if (disallow_nl) { - const String l = arr.items[i].data.string; - VALIDATE(!memchr(l.data, NL, l.size), "String cannot contain newlines", { - return false; - }); - } - } - return true; -} - /// Sets (replaces) a line-range in the buffer. /// /// Indexing is zero-based, end-exclusive. Negative indices are interpreted @@ -373,15 +356,15 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ start = normalize_index(buf, start, true, &oob); end = normalize_index(buf, end, true, &oob); - VALIDATE((!strict_indexing || !oob), "Index out of bounds", { + VALIDATE((!strict_indexing || !oob), "%s", "Index out of bounds", { return; }); - VALIDATE((start <= end), "\"start\" is higher than \"end\"", { + VALIDATE((start <= end), "%s", "'start' is higher than 'end'", { return; }); bool disallow_nl = (channel_id != VIML_INTERNAL_CALL); - if (!check_string_array(replacement, disallow_nl, err)) { + if (!check_string_array(replacement, "replacement string", disallow_nl, err)) { return; } @@ -438,7 +421,7 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ for (size_t i = 0; i < to_replace; i++) { int64_t lnum = start + (int64_t)i; - VALIDATE(lnum < MAXLNUM, "Index value is too high", { + VALIDATE(lnum < MAXLNUM, "%s", "Index out of bounds", { goto end; }); @@ -457,7 +440,7 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ for (size_t i = to_replace; i < new_len; i++) { int64_t lnum = start + (int64_t)i - 1; - VALIDATE(lnum < MAXLNUM, "Index value is too high", { + VALIDATE(lnum < MAXLNUM, "%s", "Index out of bounds", { goto end; }); @@ -546,12 +529,12 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In // check range is ordered and everything! // start_row, end_row within buffer len (except add text past the end?) start_row = normalize_index(buf, start_row, false, &oob); - VALIDATE((!oob), "start_row out of bounds", { + VALIDATE_RANGE((!oob), "start_row", { return; }); end_row = normalize_index(buf, end_row, false, &oob); - VALIDATE((!oob), "end_row out of bounds", { + VALIDATE_RANGE((!oob), "end_row", { return; }); @@ -561,24 +544,24 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In // Another call to ml_get_buf() may free the line, so make a copy. str_at_start = xstrdup(ml_get_buf(buf, (linenr_T)start_row, false)); size_t len_at_start = strlen(str_at_start); - VALIDATE((start_col >= 0 && (size_t)start_col <= len_at_start), "start_col out of bounds", { + VALIDATE_RANGE((start_col >= 0 && (size_t)start_col <= len_at_start), "start_col", { goto early_end; }); // Another call to ml_get_buf() may free the line, so make a copy. str_at_end = xstrdup(ml_get_buf(buf, (linenr_T)end_row, false)); size_t len_at_end = strlen(str_at_end); - VALIDATE((end_col >= 0 && (size_t)end_col <= len_at_end), "end_col out of bounds", { + VALIDATE_RANGE((end_col >= 0 && (size_t)end_col <= len_at_end), "end_col", { goto early_end; }); VALIDATE((start_row <= end_row && !(end_row == start_row && start_col > end_col)), - "start is higher than end", { + "%s", "'start' is higher than 'end'", { goto early_end; }); bool disallow_nl = (channel_id != VIML_INTERNAL_CALL); - if (!check_string_array(replacement, disallow_nl, err)) { + if (!check_string_array(replacement, "replacement string", disallow_nl, err)) { goto early_end; } @@ -681,7 +664,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In for (size_t i = 0; i < to_replace; i++) { int64_t lnum = start_row + (int64_t)i; - VALIDATE((lnum < MAXLNUM), "Index value is too high", { + VALIDATE((lnum < MAXLNUM), "%s", "Index out of bounds", { goto end; }); @@ -698,7 +681,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In for (size_t i = to_replace; i < new_len; i++) { int64_t lnum = start_row + (int64_t)i - 1; - VALIDATE((lnum < MAXLNUM), "Index value is too high", { + VALIDATE((lnum < MAXLNUM), "%s", "Index out of bounds", { goto end; }); @@ -777,7 +760,7 @@ ArrayOf(String) nvim_buf_get_text(uint64_t channel_id, Buffer buffer, { Array rv = ARRAY_DICT_INIT; - VALIDATE((opts.size == 0), "opts dict isn't empty", { + VALIDATE((opts.size == 0), "%s", "opts dict isn't empty", { return rv; }); @@ -796,14 +779,14 @@ ArrayOf(String) nvim_buf_get_text(uint64_t channel_id, Buffer buffer, start_row = normalize_index(buf, start_row, false, &oob); end_row = normalize_index(buf, end_row, false, &oob); - VALIDATE((!oob), "Index out of bounds", { + VALIDATE((!oob), "%s", "Index out of bounds", { return rv; }); // nvim_buf_get_lines doesn't care if the start row is greater than the end // row (it will just return an empty array), but nvim_buf_get_text does in // order to maintain symmetry with nvim_buf_set_text. - VALIDATE((start_row <= end_row), "start is higher than end", { + VALIDATE((start_row <= end_row), "%s", "'start' is higher than 'end'", { return rv; }); @@ -881,7 +864,7 @@ Integer nvim_buf_get_offset(Buffer buffer, Integer index, Error *err) return -1; } - VALIDATE((index >= 0 && index <= buf->b_ml.ml_line_count), "Index out of bounds", { + VALIDATE((index >= 0 && index <= buf->b_ml.ml_line_count), "%s", "Index out of bounds", { return 0; }); diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 0a95833256..cae3927dfd 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -100,7 +100,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) { Dictionary result = ARRAY_DICT_INIT; - VALIDATE((opts.size == 0), "opts dict isn't empty", { + VALIDATE((opts.size == 0), "%s", "opts dict isn't empty", { return result; }); @@ -1021,7 +1021,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, name.data, { goto err; }); - VALIDATE((!HAS_KEY(opts->range) || !HAS_KEY(opts->count)), + VALIDATE((!HAS_KEY(opts->range) || !HAS_KEY(opts->count)), "%s", "Cannot use both 'range' and 'count'", { goto err; }); @@ -1065,7 +1065,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, }); } - VALIDATE((!HAS_KEY(opts->complete) || argt), "'complete' used without 'nargs'", { + VALIDATE((!HAS_KEY(opts->complete) || argt), "%s", "'complete' used without 'nargs'", { goto err; }); @@ -1086,8 +1086,9 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, def = opts->range.data.integer; addr_type_arg = ADDR_LINES; } else if (HAS_KEY(opts->range)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'range'"); - goto err; + VALIDATE_S(false, "range", "", { + goto err; + }); } if (opts->count.type == kObjectTypeBoolean) { @@ -1101,23 +1102,25 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, addr_type_arg = ADDR_OTHER; def = opts->count.data.integer; } else if (HAS_KEY(opts->count)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'count'"); - goto err; + VALIDATE_S(false, "count", "", { + goto err; + }); } - if (opts->addr.type == kObjectTypeString) { - if (parse_addr_type_arg(opts->addr.data.string.data, (int)opts->addr.data.string.size, - &addr_type_arg) != OK) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'addr'"); + if (HAS_KEY(opts->addr)) { + VALIDATE_T("addr", kObjectTypeString, opts->addr.type, { goto err; - } + }); + + VALIDATE_S(OK == parse_addr_type_arg(opts->addr.data.string.data, + (int)opts->addr.data.string.size, &addr_type_arg), "addr", + opts->addr.data.string.data, { + goto err; + }); if (addr_type_arg != ADDR_LINES) { argt |= EX_ZEROR; } - } else if (HAS_KEY(opts->addr)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'addr'"); - goto err; } if (api_object_to_bool(opts->bang, "bang", false, err)) { @@ -1153,23 +1156,25 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, compl = EXPAND_USER_LUA; compl_luaref = api_new_luaref(opts->complete.data.luaref); } else if (opts->complete.type == kObjectTypeString) { - if (parse_compl_arg(opts->complete.data.string.data, - (int)opts->complete.data.string.size, &compl, &argt, - &compl_arg) != OK) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'complete'"); + VALIDATE_S(OK == parse_compl_arg(opts->complete.data.string.data, + (int)opts->complete.data.string.size, &compl, &argt, + &compl_arg), + "complete", opts->complete.data.string.data, { goto err; - } + }); } else if (HAS_KEY(opts->complete)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'complete'"); - goto err; + VALIDATE(false, "%s", "Invalid complete: expected Function or String", { + goto err; + }); } - if (opts->preview.type == kObjectTypeLuaRef) { + if (HAS_KEY(opts->preview)) { + VALIDATE_T("preview", kObjectTypeLuaRef, opts->preview.type, { + goto err; + }); + argt |= EX_PREVIEW; preview_luaref = api_new_luaref(opts->preview.data.luaref); - } else if (HAS_KEY(opts->preview)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'preview'"); - goto err; } switch (command.type) { @@ -1185,8 +1190,9 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, rep = command.data.string.data; break; default: - api_set_error(err, kErrorTypeValidation, "'command' must be a string or Lua function"); - goto err; + VALIDATE(false, "%s", "Invalid command: expected Function or String", { + goto err; + }); } if (uc_add_command(name.data, name.size, rep, argt, def, flags, compl, compl_arg, compl_luaref, diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 71ba9cfd4c..15f759eddf 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -520,7 +520,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer // 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), "cannot use both end_row and end_line", { + VALIDATE(!HAS_KEY(opts->end_row), "%s", "cannot use both 'end_row' and 'end_line'", { goto error; }); opts->end_row = opts->end_line; @@ -535,30 +535,29 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer bool strict = true; OPTION_TO_BOOL(strict, strict, true); - if (opts->end_row.type == kObjectTypeInteger) { - Integer val = opts->end_row.data.integer; - VALIDATE((val >= 0 && !(val > buf->b_ml.ml_line_count && strict)), - "end_row value outside range", { + if (HAS_KEY(opts->end_row)) { + VALIDATE_T("end_row", kObjectTypeInteger, opts->end_row.type, { goto error; }); - line2 = (int)val; - } else if (HAS_KEY(opts->end_row)) { - VALIDATE_T("end_row", kObjectTypeInteger, opts->end_row.type, { + + Integer val = opts->end_row.data.integer; + VALIDATE_RANGE((val >= 0 && !(val > buf->b_ml.ml_line_count && strict)), "end_row", { goto error; }); + line2 = (int)val; } colnr_T col2 = -1; - if (opts->end_col.type == kObjectTypeInteger) { - Integer val = opts->end_col.data.integer; - VALIDATE((val >= 0 && val <= MAXCOL), "end_col value outside range", { + if (HAS_KEY(opts->end_col)) { + VALIDATE_T("end_col", kObjectTypeInteger, opts->end_col.type, { goto error; }); - col2 = (int)val; - } else if (HAS_KEY(opts->end_col)) { - VALIDATE_T("end_col", kObjectTypeInteger, opts->end_col.type, { + + Integer val = opts->end_col.data.integer; + VALIDATE_RANGE((val >= 0 && val <= MAXCOL), "end_col", { goto error; }); + col2 = (int)val; } // uncrustify:off @@ -588,33 +587,37 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } } - if (opts->conceal.type == kObjectTypeString) { + if (HAS_KEY(opts->conceal)) { + VALIDATE_T("conceal", kObjectTypeString, opts->conceal.type, { + goto error; + }); + String c = opts->conceal.data.string; decor.conceal = true; if (c.size) { decor.conceal_char = utf_ptr2char(c.data); } has_decor = true; - } else if (HAS_KEY(opts->conceal)) { - VALIDATE_T("conceal", kObjectTypeString, opts->conceal.type, { + } + + if (HAS_KEY(opts->virt_text)) { + VALIDATE_T("virt_text", kObjectTypeArray, opts->virt_text.type, { goto error; }); - } - if (opts->virt_text.type == kObjectTypeArray) { decor.virt_text = parse_virt_text(opts->virt_text.data.array, err, &decor.virt_text_width); has_decor = true; if (ERROR_SET(err)) { goto error; } - } else if (HAS_KEY(opts->virt_text)) { - VALIDATE_T("virt_text", kObjectTypeArray, opts->virt_text.type, { + } + + if (HAS_KEY(opts->virt_text_pos)) { + VALIDATE_T("virt_text_pos", kObjectTypeString, opts->virt_text_pos.type, { goto error; }); - } - if (opts->virt_text_pos.type == kObjectTypeString) { String str = opts->virt_text_pos.data.string; if (strequal("eol", str.data)) { decor.virt_text_pos = kVTEndOfLine; @@ -627,19 +630,15 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer goto error; }); } - } else if (HAS_KEY(opts->virt_text_pos)) { - VALIDATE_T("virt_text_pos", kObjectTypeString, opts->virt_text_pos.type, { - goto error; - }); } - if (opts->virt_text_win_col.type == kObjectTypeInteger) { - decor.col = (int)opts->virt_text_win_col.data.integer; - decor.virt_text_pos = kVTWinCol; - } else if (HAS_KEY(opts->virt_text_win_col)) { + 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; + decor.virt_text_pos = kVTWinCol; } OPTION_TO_BOOL(decor.virt_text_hide, virt_text_hide, false); @@ -667,7 +666,11 @@ 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); - if (opts->virt_lines.type == kObjectTypeArray) { + if (HAS_KEY(opts->virt_lines)) { + VALIDATE_T("virt_lines", kObjectTypeArray, opts->virt_lines.type, { + goto error; + }); + Array a = opts->virt_lines.data.array; for (size_t j = 0; j < a.size; j++) { VALIDATE_T("virt_text_line", kObjectTypeArray, a.items[j].type, { @@ -681,37 +684,33 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } has_decor = true; } - } else if (HAS_KEY(opts->virt_lines)) { - VALIDATE_T("virt_lines", kObjectTypeArray, opts->virt_lines.type, { - goto error; - }); } OPTION_TO_BOOL(decor.virt_lines_above, virt_lines_above, false); - if (opts->priority.type == kObjectTypeInteger) { + if (HAS_KEY(opts->priority)) { + VALIDATE_T("priority", kObjectTypeInteger, opts->priority.type, { + goto error; + }); + Integer val = opts->priority.data.integer; - VALIDATE_S((val >= 0 && val <= UINT16_MAX), "priority", "(out of range)", { + VALIDATE_RANGE((val >= 0 && val <= UINT16_MAX), "priority", { goto error; }); decor.priority = (DecorPriority)val; - } else if (HAS_KEY(opts->priority)) { - VALIDATE_T("priority", kObjectTypeInteger, opts->priority.type, { + } + + if (HAS_KEY(opts->sign_text)) { + VALIDATE_T("sign_text", kObjectTypeString, opts->sign_text.type, { goto error; }); - } - if (opts->sign_text.type == kObjectTypeString) { VALIDATE_S(init_sign_text(&decor.sign_text, opts->sign_text.data.string.data), "sign_text", "", { goto error; }); has_decor = true; - } else if (HAS_KEY(opts->sign_text)) { - VALIDATE_T("sign_text", kObjectTypeString, opts->sign_text.type, { - goto error; - }); } bool right_gravity = true; @@ -720,7 +719,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer // 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)), - "cannot set end_right_gravity without setting end_row or end_col", { + "%s", "cannot set end_right_gravity without end_row or end_col", { goto error; }); @@ -732,7 +731,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer bool ephemeral = false; OPTION_TO_BOOL(ephemeral, ephemeral, false); - if (opts->spell.type == kObjectTypeNil) { + if (!HAS_KEY(opts->spell)) { decor.spell = kNone; } else { bool spell = false; @@ -746,12 +745,12 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer has_decor = true; } - VALIDATE_S((line >= 0), "line", "(out of range)", { + VALIDATE_RANGE((line >= 0), "line", { goto error; }); if (line > buf->b_ml.ml_line_count) { - VALIDATE_S(!strict, "line", "(out of range)", { + VALIDATE_RANGE(!strict, "line", { goto error; }); line = buf->b_ml.ml_line_count; @@ -762,12 +761,12 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer if (col == -1) { col = (Integer)len; } else if (col > (Integer)len) { - VALIDATE_S(!strict, "col", "(out of range)", { + VALIDATE_RANGE(!strict, "col", { goto error; }); col = (Integer)len; } else if (col < -1) { - VALIDATE_S(false, "col", "(out of range)", { + VALIDATE_RANGE(false, "col", { goto error; }); } @@ -783,7 +782,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer line2 = (int)line; } if (col2 > (Integer)len) { - VALIDATE_S(!strict, "end_col", "(out of range)", { + VALIDATE_RANGE(!strict, "end_col", { goto error; }); col2 = (int)len; @@ -886,10 +885,10 @@ Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, In return 0; } - VALIDATE_S((line >= 0 && line < MAXLNUM), "line number", "(out of range)", { + VALIDATE_RANGE((line >= 0 && line < MAXLNUM), "line number", { return 0; }); - VALIDATE_S((col_start >= 0 && col_start <= MAXCOL), "column", "(out of range)", { + VALIDATE_RANGE((col_start >= 0 && col_start <= MAXCOL), "column", { return 0; }); @@ -948,7 +947,7 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, return; } - VALIDATE_S((line_start >= 0 && line_start < MAXLNUM), "line number", "(out of range)", { + VALIDATE_RANGE((line_start >= 0 && line_start < MAXLNUM), "line number", { return; }); @@ -1092,7 +1091,7 @@ static bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, in VALIDATE((pos.size == 2 && pos.items[0].type == kObjectTypeInteger && pos.items[1].type == kObjectTypeInteger), - "Invalid position: expected 2 Integer items", { + "%s", "Invalid position: expected 2 Integer items", { return false; }); @@ -1102,7 +1101,7 @@ static bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, in *col = (colnr_T)(pos_col >= 0 ? pos_col : MAXCOL); return true; } else { - VALIDATE(false, "Invalid position: expected mark id Integer or 2-item Array", { + VALIDATE(false, "%s", "Invalid position: expected mark id Integer or 2-item Array", { return false; }); } @@ -1153,7 +1152,7 @@ VirtText parse_virt_text(Array chunks, Error *err, int *width) }); Array chunk = chunks.items[i].data.array; VALIDATE((chunk.size > 0 && chunk.size <= 2 && chunk.items[0].type == kObjectTypeString), - "Invalid chunk: expected Array with 1 or 2 Strings", { + "%s", "Invalid chunk: expected Array with 1 or 2 Strings", { goto free_exit; }); diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 5b57b49ad6..40720c31c7 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -26,54 +26,54 @@ static int validate_option_value_args(Dict(option) *opts, int *scope, int *opt_type, void **from, Error *err) { - if (opts->scope.type == kObjectTypeString) { + if (HAS_KEY(opts->scope)) { + VALIDATE_T("scope", kObjectTypeString, opts->scope.type, { + return FAIL; + }); + if (!strcmp(opts->scope.data.string.data, "local")) { *scope = OPT_LOCAL; } else if (!strcmp(opts->scope.data.string.data, "global")) { *scope = OPT_GLOBAL; } else { - VALIDATE(false, "Invalid scope (expected 'local' or 'global')", { + VALIDATE(false, "%s", "Invalid scope: expected 'local' or 'global'", { return FAIL; }); } - } else if (HAS_KEY(opts->scope)) { - VALIDATE_T("scope", kObjectTypeString, opts->scope.type, { - return FAIL; - }); - return FAIL; } *opt_type = SREQ_GLOBAL; - if (opts->win.type == kObjectTypeInteger) { + if (HAS_KEY(opts->win)) { + VALIDATE_T("win", kObjectTypeInteger, opts->win.type, { + return FAIL; + }); + *opt_type = SREQ_WIN; *from = find_window_by_handle((int)opts->win.data.integer, err); if (ERROR_SET(err)) { return FAIL; } - } else if (HAS_KEY(opts->win)) { - VALIDATE_T("win", kObjectTypeInteger, opts->win.type, { + } + + if (HAS_KEY(opts->buf)) { + VALIDATE_T("buf", kObjectTypeInteger, opts->buf.type, { return FAIL; }); - } - if (opts->buf.type == kObjectTypeInteger) { *scope = OPT_LOCAL; *opt_type = SREQ_BUF; *from = find_buffer_by_handle((int)opts->buf.data.integer, err); if (ERROR_SET(err)) { return FAIL; } - } else if (HAS_KEY(opts->buf)) { - VALIDATE_T("buf", kObjectTypeInteger, opts->buf.type, { - return FAIL; - }); } - VALIDATE((!HAS_KEY(opts->scope) || !HAS_KEY(opts->buf)), "cannot use both 'scope' and 'buf'", { + VALIDATE((!HAS_KEY(opts->scope) || !HAS_KEY(opts->buf)), "%s", + "cannot use both 'scope' and 'buf'", { return FAIL; }); - VALIDATE((!HAS_KEY(opts->win) || !HAS_KEY(opts->buf)), "cannot use both 'buf' and 'win'", { + VALIDATE((!HAS_KEY(opts->win) || !HAS_KEY(opts->buf)), "%s", "cannot use both 'buf' and 'win'", { return FAIL; }); @@ -427,21 +427,21 @@ void set_option_to(uint64_t channel_id, void *to, int type, String name, Object char *stringval = NULL; if (flags & SOPT_BOOL) { - VALIDATE_FMT(value.type == kObjectTypeBoolean, "Option '%s' value must be Boolean", name.data, { + VALIDATE(value.type == kObjectTypeBoolean, "Option '%s' value must be Boolean", name.data, { return; }); numval = value.data.boolean; } else if (flags & SOPT_NUM) { - VALIDATE_FMT(value.type == kObjectTypeInteger, "Option '%s' value must be Integer", name.data, { + VALIDATE(value.type == kObjectTypeInteger, "Option '%s' value must be Integer", name.data, { return; }); - VALIDATE_FMT((value.data.integer <= INT_MAX && value.data.integer >= INT_MIN), - "Option '%s' value is out of range", name.data, { + VALIDATE((value.data.integer <= INT_MAX && value.data.integer >= INT_MIN), + "Option '%s' value is out of range", name.data, { return; }); numval = (int)value.data.integer; } else { - VALIDATE_FMT(value.type == kObjectTypeString, "Option '%s' value must be String", name.data, { + VALIDATE(value.type == kObjectTypeString, "Option '%s' value must be String", name.data, { return; }); stringval = value.data.string.data; diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 6beb3d8683..c996e19eb9 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -821,8 +821,7 @@ int object_to_hl_id(Object obj, const char *what, Error *err) } else if (obj.type == kObjectTypeInteger) { return MAX((int)obj.data.integer, 0); } else { - api_set_error(err, kErrorTypeValidation, - "%s is not a valid highlight", what); + api_set_error(err, kErrorTypeValidation, "Invalid highlight: %s", what); return 0; } } diff --git a/src/nvim/api/private/validate.c b/src/nvim/api/private/validate.c new file mode 100644 index 0000000000..41c9472a39 --- /dev/null +++ b/src/nvim/api/private/validate.c @@ -0,0 +1,28 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + +#include "nvim/api/private/defs.h" +#include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "api/private/validate.c.generated.h" +#endif + +bool check_string_array(Array arr, char *name, bool disallow_nl, Error *err) +{ + snprintf(IObuff, sizeof(IObuff), "'%s' item", name); + for (size_t i = 0; i < arr.size; i++) { + VALIDATE_T(IObuff, kObjectTypeString, arr.items[i].type, { + return false; + }); + // Disallow newlines in the middle of the line. + if (disallow_nl) { + const String l = arr.items[i].data.string; + VALIDATE(!memchr(l.data, NL, l.size), "'%s' item contains newlines", name, { + return false; + }); + } + } + return true; +} diff --git a/src/nvim/api/private/validate.h b/src/nvim/api/private/validate.h index 8448b416be..4a1b99408e 100644 --- a/src/nvim/api/private/validate.h +++ b/src/nvim/api/private/validate.h @@ -24,19 +24,11 @@ } \ } while (0) -#define VALIDATE_R(cond, name, code) \ - do { \ - if (!(cond)) { \ - api_set_error(err, kErrorTypeValidation, "'" name "' is required"); \ - code; \ - } \ - } while (0) - #define VALIDATE_EXP(cond, name, expected, actual, code) \ do { \ if (!(cond)) { \ - api_set_error(err, kErrorTypeValidation, "Invalid " name ": expected %s, got %s", \ - expected, actual); \ + api_set_error(err, kErrorTypeValidation, "Invalid %s: expected %s, got %s", \ + name, expected, actual); \ code; \ } \ } while (0) @@ -50,20 +42,27 @@ } \ } while (0) -#define VALIDATE(cond, msg_, code) \ +#define VALIDATE(cond, fmt_, fmt_arg1, code) \ do { \ if (!(cond)) { \ - api_set_error(err, kErrorTypeValidation, "%s", msg_); \ + api_set_error(err, kErrorTypeValidation, fmt_, fmt_arg1); \ code; \ } \ } while (0) -#define VALIDATE_FMT(cond, fmt_, msg_, code) \ +#define VALIDATE_RANGE(cond, name, code) \ do { \ if (!(cond)) { \ - api_set_error(err, kErrorTypeValidation, fmt_, msg_); \ + api_set_error(err, kErrorTypeValidation, "Invalid '%s': out of range", name); \ code; \ } \ } while (0) +#define VALIDATE_R(cond, name, code) \ + VALIDATE(cond, "Required: '%s'", name, code); + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "api/private/validate.h.generated.h" +#endif + #endif // NVIM_API_PRIVATE_VALIDATE_H diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 8f5465db77..61f2c881b3 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -12,6 +12,7 @@ #include "klib/kvec.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/api/ui.h" #include "nvim/autocmd.h" #include "nvim/channel.h" @@ -291,22 +292,20 @@ void nvim_ui_set_option(uint64_t channel_id, String name, Object value, Error *e ui_set_option(ui, false, name, value, error); } -static void ui_set_option(UI *ui, bool init, String name, Object value, Error *error) +static void ui_set_option(UI *ui, bool init, String name, Object value, Error *err) { if (strequal(name.data, "override")) { - if (value.type != kObjectTypeBoolean) { - api_set_error(error, kErrorTypeValidation, "override must be a Boolean"); + VALIDATE_T("override", kObjectTypeBoolean, value.type, { return; - } + }); ui->override = value.data.boolean; return; } if (strequal(name.data, "rgb")) { - if (value.type != kObjectTypeBoolean) { - api_set_error(error, kErrorTypeValidation, "rgb must be a Boolean"); + VALIDATE_T("rgb", kObjectTypeBoolean, value.type, { return; - } + }); ui->rgb = value.data.boolean; // A little drastic, but only takes effect for legacy uis. For linegrid UI // only changes metadata for nvim_list_uis(), no refresh needed. @@ -317,62 +316,56 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e } if (strequal(name.data, "term_name")) { - if (value.type != kObjectTypeString) { - api_set_error(error, kErrorTypeValidation, "term_name must be a String"); + VALIDATE_T("term_name", kObjectTypeString, value.type, { return; - } + }); set_tty_option("term", string_to_cstr(value.data.string)); return; } if (strequal(name.data, "term_colors")) { - if (value.type != kObjectTypeInteger) { - api_set_error(error, kErrorTypeValidation, "term_colors must be a Integer"); + VALIDATE_T("term_colors", kObjectTypeInteger, value.type, { return; - } + }); t_colors = (int)value.data.integer; return; } if (strequal(name.data, "term_background")) { - if (value.type != kObjectTypeString) { - api_set_error(error, kErrorTypeValidation, "term_background must be a String"); + VALIDATE_T("term_background", kObjectTypeString, value.type, { return; - } + }); set_tty_background(value.data.string.data); return; } if (strequal(name.data, "stdin_fd")) { - if (value.type != kObjectTypeInteger || value.data.integer < 0) { - api_set_error(error, kErrorTypeValidation, "stdin_fd must be a non-negative Integer"); + VALIDATE_T("stdin_fd", kObjectTypeInteger, value.type, { return; - } - - if (starting != NO_SCREEN) { - api_set_error(error, kErrorTypeValidation, - "stdin_fd can only be used with first attached ui"); + }); + VALIDATE_INT((value.data.integer >= 0), "stdin_fd", value.data.integer, { return; - } + }); + VALIDATE((starting == NO_SCREEN), "%s", "stdin_fd can only be used with first attached UI", { + return; + }); stdin_fd = (int)value.data.integer; return; } if (strequal(name.data, "stdin_tty")) { - if (value.type != kObjectTypeBoolean) { - api_set_error(error, kErrorTypeValidation, "stdin_tty must be a Boolean"); + VALIDATE_T("stdin_tty", kObjectTypeBoolean, value.type, { return; - } + }); stdin_isatty = value.data.boolean; return; } if (strequal(name.data, "stdout_tty")) { - if (value.type != kObjectTypeBoolean) { - api_set_error(error, kErrorTypeValidation, "stdout_tty must be a Boolean"); + VALIDATE_T("stdout_tty", kObjectTypeBoolean, value.type, { return; - } + }); stdout_isatty = value.data.boolean; return; } @@ -383,17 +376,15 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e for (UIExtension i = 0; i < kUIExtCount; i++) { if (strequal(name.data, ui_ext_names[i]) || (i == kUIPopupmenu && is_popupmenu)) { - if (value.type != kObjectTypeBoolean) { - api_set_error(error, kErrorTypeValidation, "%s must be a Boolean", - name.data); + VALIDATE_EXP((value.type == kObjectTypeBoolean), name.data, "Boolean", + api_typename(value.type), { return; - } + }); bool boolval = value.data.boolean; if (!init && i == kUILinegrid && boolval != ui->ui_ext[i]) { // There shouldn't be a reason for an UI to do this ever // so explicitly don't support this. - api_set_error(error, kErrorTypeValidation, - "ext_linegrid option cannot be changed"); + api_set_error(err, kErrorTypeValidation, "ext_linegrid option cannot be changed"); } ui->ui_ext[i] = boolval; if (!init) { @@ -403,8 +394,7 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e } } - api_set_error(error, kErrorTypeValidation, "No such UI option: %s", - name.data); + api_set_error(err, kErrorTypeValidation, "No such UI option: %s", name.data); } /// Tell Nvim to resize a grid. Triggers a grid_resize event with the requested diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 333749c42f..50683ac403 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -87,10 +87,9 @@ Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Arena *arena, Error *er Dictionary result = ARRAY_DICT_INIT; int id = syn_name2id(name.data); - if (id == 0) { - api_set_error(err, kErrorTypeException, "Invalid highlight name: %s", name.data); + VALIDATE_S((id != 0), "highlight name", name.data, { return result; - } + }); return nvim_get_hl_by_id(id, rgb, arena, err); } @@ -104,10 +103,9 @@ Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Arena *arena, Error *er FUNC_API_SINCE(3) { Dictionary dic = ARRAY_DICT_INIT; - if (syn_get_final_id((int)hl_id) == 0) { - api_set_error(err, kErrorTypeException, "Invalid highlight id: %" PRId64, hl_id); + VALIDATE_INT((syn_get_final_id((int)hl_id) != 0), "highlight id", hl_id, { return dic; - } + }); int attrcode = syn_id2attr((int)hl_id); return hl_get_attr_by_id(attrcode, rgb, arena, err); } @@ -174,10 +172,9 @@ void nvim_set_hl(Integer ns_id, String name, Dict(highlight) *val, Error *err) FUNC_API_SINCE(7) { int hl_id = syn_check_group(name.data, name.size); - if (hl_id == 0) { - api_set_error(err, kErrorTypeException, "Invalid highlight name: %s", name.data); + VALIDATE_S((hl_id != 0), "highlight name", name.data, { return; - } + }); int link_id = -1; HlAttrs attrs = dict2hlattrs(val, true, &link_id, err); @@ -403,11 +400,9 @@ void nvim_input_mouse(String button, String action, String modifier, Integer gri continue; } int mod = name_to_mod_mask(byte); - if (mod == 0) { - api_set_error(err, kErrorTypeValidation, - "invalid modifier %c", byte); + VALIDATE((mod != 0), "Invalid modifier: %c", byte, { return; - } + }); modmask |= mod; } @@ -500,7 +495,7 @@ Object nvim_notify(String msg, Integer log_level, Dictionary opts, Error *err) Integer nvim_strwidth(String text, Error *err) FUNC_API_SINCE(1) { - VALIDATE((text.size <= INT_MAX), "text length (too long)", { + VALIDATE_S((text.size <= INT_MAX), "text length", "(too long)", { return 0; }); @@ -574,8 +569,7 @@ ArrayOf(String) nvim__get_runtime(Array pat, Boolean all, Dict(runtime) *opts, E { bool is_lua = api_object_to_bool(opts->is_lua, "is_lua", false, err); bool source = api_object_to_bool(opts->do_source, "do_source", false, err); - VALIDATE((!source || nlua_is_deferred_safe()), "'do_source' used in fast callback", {}); - + VALIDATE((!source || nlua_is_deferred_safe()), "%s", "'do_source' used in fast callback", {}); if (ERROR_SET(err)) { return (Array)ARRAY_DICT_INIT; } @@ -599,7 +593,7 @@ ArrayOf(String) nvim__get_runtime(Array pat, Boolean all, Dict(runtime) *opts, E void nvim_set_current_dir(String dir, Error *err) FUNC_API_SINCE(1) { - VALIDATE((dir.size < MAXPATHL), "directory name (too long)", { + VALIDATE_S((dir.size < MAXPATHL), "directory name", "(too long)", { return; }); @@ -1067,7 +1061,7 @@ void nvim_chan_send(Integer chan, String data, Error *err) channel_send((uint64_t)chan, data.data, data.size, false, &error); - VALIDATE(!error, error, {}); + VALIDATE(!error, "%s", error, {}); } /// Gets the current list of tabpage handles. @@ -1334,12 +1328,11 @@ Dictionary nvim_get_context(Dict(context) *opts, Error *err) FUNC_API_SINCE(6) { Array types = ARRAY_DICT_INIT; - if (opts->types.type == kObjectTypeArray) { - types = opts->types.data.array; - } else if (opts->types.type != kObjectTypeNil) { + if (HAS_KEY(opts->types)) { VALIDATE_T("types", kObjectTypeArray, opts->types.type, { return (Dictionary)ARRAY_DICT_INIT; }); + types = opts->types.data.array; } int int_types = types.size > 0 ? 0 : kCtxAll; @@ -1643,7 +1636,7 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Arena *arena, Error *er goto theend; }); Array call = calls.items[i].data.array; - VALIDATE((call.size == 2), "Items in calls array must be arrays of size 2", { + VALIDATE((call.size == 2), "%s", "calls item must be a 2-item Array", { goto theend; }); VALIDATE_T("name", kObjectTypeString, call.items[0].type, { @@ -1824,10 +1817,9 @@ Array nvim_get_proc_children(Integer pid, Error *err) Array rvobj = ARRAY_DICT_INIT; int *proc_list = NULL; - if (pid <= 0 || pid > INT_MAX) { - api_set_error(err, kErrorTypeException, "Invalid pid: %" PRId64, pid); + VALIDATE_INT((pid > 0 && pid <= INT_MAX), "pid", pid, { goto end; - } + }); size_t proc_count; int rv = os_proc_children((int)pid, &proc_list, &proc_count); @@ -1866,10 +1858,10 @@ Object nvim_get_proc(Integer pid, Error *err) rvobj.data.dictionary = (Dictionary)ARRAY_DICT_INIT; rvobj.type = kObjectTypeDictionary; - if (pid <= 0 || pid > INT_MAX) { - api_set_error(err, kErrorTypeException, "Invalid pid: %" PRId64, pid); + VALIDATE_INT((pid > 0 && pid <= INT_MAX), "pid", pid, { return NIL; - } + }); + #ifdef MSWIN rvobj.data.dictionary = os_proc_info((int)pid); if (rvobj.data.dictionary.size == 0) { // Process not found. @@ -1911,7 +1903,7 @@ void nvim_select_popupmenu_item(Integer item, Boolean insert, Boolean finish, Di Error *err) FUNC_API_SINCE(6) { - VALIDATE((opts.size == 0), "opts dict isn't empty", { + VALIDATE((opts.size == 0), "%s", "opts dict isn't empty", { return; }); @@ -2100,7 +2092,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * if (str.size < 2 || memcmp(str.data, "%!", 2) != 0) { const char *const errmsg = check_stl_option(str.data); - VALIDATE(!errmsg, errmsg, { + VALIDATE(!errmsg, "%s", errmsg, { return result; }); } @@ -2119,7 +2111,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * VALIDATE((opts->fillchar.data.string.size != 0 && ((size_t)utf_ptr2len(opts->fillchar.data.string.data) == opts->fillchar.data.string.size)), - "Invalid fillchar (not a single character)", { + "%s", "Invalid fillchar: expected single character", { return result; }); fillchar = utf_ptr2char(opts->fillchar.data.string.data); @@ -2145,10 +2137,9 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * return result; } } - if (use_winbar && use_tabline) { - api_set_error(err, kErrorTypeValidation, "use_winbar and use_tabline are mutually exclusive"); + VALIDATE(!(use_winbar && use_tabline), "%s", "Cannot use both 'use_winbar' and 'use_tabline'", { return result; - } + }); win_T *wp, *ewp; -- cgit From 556f8646c01d1751cf39fe4df9c622899dceab9d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 14 Feb 2023 14:19:28 -0500 Subject: refactor(api): consistent VALIDATE messages #22262 Problem: Validation messages are not consistently formatted. - Parameter names sometimes are NOT quoted. - Descriptive names (non-parameters) sometimes ARE quoted. Solution: Always quote the `name` value passed to a VALIDATE macro _unless_ the value has whitespace. --- src/nvim/api/autocmd.c | 15 ++++++------- src/nvim/api/buffer.c | 4 ++-- src/nvim/api/command.c | 6 ++--- src/nvim/api/extmark.c | 23 ++++++++++--------- src/nvim/api/options.c | 4 ++-- src/nvim/api/private/validate.c | 49 +++++++++++++++++++++++++++++++++++++++++ src/nvim/api/private/validate.h | 32 +++++++++++---------------- src/nvim/api/vim.c | 21 +++++++++--------- 8 files changed, 99 insertions(+), 55 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 36d3e04f54..aff7622dc5 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -108,19 +108,19 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) break; case kObjectTypeString: group = augroup_find(opts->group.data.string.data); - VALIDATE_S((group >= 0), "group", "", { + VALIDATE_S((group >= 0), "group", opts->group.data.string.data, { goto cleanup; }); break; case kObjectTypeInteger: group = (int)opts->group.data.integer; char *name = augroup_name(group); - VALIDATE_S(augroup_exists(name), "group", "", { + VALIDATE_INT(augroup_exists(name), "group", opts->group.data.integer, { goto cleanup; }); break; default: - VALIDATE_S(false, "group (must be string or integer)", "", { + VALIDATE_EXP(false, "group", "String or Integer", api_typename(opts->group.type), { goto cleanup; }); } @@ -142,7 +142,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) event_set[event_nr] = true; }) } else { - VALIDATE_S(false, "event (must be String or Array)", "", { + VALIDATE_EXP(false, "event", "String or Array", NULL, { goto cleanup; }); } @@ -160,11 +160,10 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) pattern_filters[pattern_filter_count] = v.data.string.data; pattern_filter_count += 1; } else if (v.type == kObjectTypeArray) { - if (v.data.array.size > AUCMD_MAX_PATTERNS) { - api_set_error(err, kErrorTypeValidation, "Too many patterns (maximum of %d)", - AUCMD_MAX_PATTERNS); + VALIDATE((v.data.array.size <= AUCMD_MAX_PATTERNS), + "Too many patterns (maximum of %d)", AUCMD_MAX_PATTERNS, { goto cleanup; - } + }); FOREACH_ITEM(v.data.array, item, { VALIDATE_T("pattern", kObjectTypeString, item.type, { diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 9c2d14d30f..bbdb66988b 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -207,7 +207,7 @@ Boolean nvim_buf_attach(uint64_t channel_id, Buffer buffer, Boolean send_buffer, } } - VALIDATE_S(key_used, "key", k.data, { + VALIDATE_S(key_used, "'opts' key", k.data, { goto error; }); } @@ -1074,7 +1074,7 @@ void nvim_buf_delete(Buffer buffer, Dictionary opts, Error *err) } else if (strequal("unload", k.data)) { unload = api_object_to_bool(v, "unload", false, err); } else { - VALIDATE_S(false, "key", k.data, { + VALIDATE_S(false, "'opts' key", k.data, { return; }); } diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index cae3927dfd..81b70b07d0 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -1017,7 +1017,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, VALIDATE_S(uc_validate_name(name.data), "command name", name.data, { goto err; }); - VALIDATE_S(!mb_islower(name.data[0]), "command name (must begin with an uppercase letter)", + VALIDATE_S(!mb_islower(name.data[0]), "command name (must start with uppercase)", name.data, { goto err; }); @@ -1163,7 +1163,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, goto err; }); } else if (HAS_KEY(opts->complete)) { - VALIDATE(false, "%s", "Invalid complete: expected Function or String", { + VALIDATE_EXP(false, "complete", "Function or String", NULL, { goto err; }); } @@ -1190,7 +1190,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, rep = command.data.string.data; break; default: - VALIDATE(false, "%s", "Invalid command: expected Function or String", { + VALIDATE_EXP(false, "command", "Function or String", NULL, { goto err; }); } diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 15f759eddf..91486abf38 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -238,7 +238,7 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, }); } } else { - VALIDATE_S(false, "key", k.data, { + VALIDATE_S(false, "'opts' key", k.data, { return rv; }); } @@ -329,7 +329,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e }); } } else { - VALIDATE_S(false, "key", k.data, { + VALIDATE_S(false, "'opts' key", k.data, { return rv; }); } @@ -508,12 +508,13 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer }); uint32_t id = 0; - if (opts->id.type == kObjectTypeInteger && opts->id.data.integer > 0) { - id = (uint32_t)opts->id.data.integer; - } else if (HAS_KEY(opts->id)) { - VALIDATE_S(false, "id (must be positive integer)", "", { + if (HAS_KEY(opts->id)) { + VALIDATE_EXP((opts->id.type == kObjectTypeInteger && opts->id.data.integer > 0), + "id", "positive Integer", NULL, { goto error; }); + + id = (uint32_t)opts->id.data.integer; } int line2 = -1; @@ -1088,10 +1089,10 @@ static bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, in // Check if it is a position } else if (obj.type == kObjectTypeArray) { Array pos = obj.data.array; - VALIDATE((pos.size == 2 - && pos.items[0].type == kObjectTypeInteger - && pos.items[1].type == kObjectTypeInteger), - "%s", "Invalid position: expected 2 Integer items", { + VALIDATE_EXP((pos.size == 2 + && pos.items[0].type == kObjectTypeInteger + && pos.items[1].type == kObjectTypeInteger), + "mark position", "2 Integer items", NULL, { return false; }); @@ -1101,7 +1102,7 @@ static bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, in *col = (colnr_T)(pos_col >= 0 ? pos_col : MAXCOL); return true; } else { - VALIDATE(false, "%s", "Invalid position: expected mark id Integer or 2-item Array", { + VALIDATE_EXP(false, "mark position", "mark id Integer or 2-item Array", NULL, { return false; }); } diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 40720c31c7..ddaed3a254 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -36,7 +36,7 @@ static int validate_option_value_args(Dict(option) *opts, int *scope, int *opt_t } else if (!strcmp(opts->scope.data.string.data, "global")) { *scope = OPT_GLOBAL; } else { - VALIDATE(false, "%s", "Invalid scope: expected 'local' or 'global'", { + VALIDATE_EXP(false, "scope", "'local' or 'global'", NULL, { return FAIL; }); } @@ -197,7 +197,7 @@ void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error scope |= OPT_CLEAR; break; default: - VALIDATE_EXP(false, "option type", "Integer, Boolean, or String", api_typename(value.type), { + VALIDATE_EXP(false, name.data, "Integer/Boolean/String", api_typename(value.type), { return; }); } diff --git a/src/nvim/api/private/validate.c b/src/nvim/api/private/validate.c index 41c9472a39..c4dd5bcac8 100644 --- a/src/nvim/api/private/validate.c +++ b/src/nvim/api/private/validate.c @@ -9,6 +9,55 @@ # include "api/private/validate.c.generated.h" #endif +/// Creates "Invalid …" message and sets it on `err`. +void api_err_invalid(Error *err, const char *name, const char *val_s, int64_t val_n, bool quote_val) +{ + ErrorType errtype = kErrorTypeValidation; + // Treat `name` without whitespace as a parameter (surround in quotes). + // Treat `name` with whitespace as a description (no quotes). + char *has_space = strchr(name, ' '); + + // No value. + if (val_s && val_s[0] == '\0') { + api_set_error(err, errtype, has_space ? "Invalid %s" : "Invalid '%s'", name); + return; + } + + // Number value. + if (val_s == NULL) { + api_set_error(err, errtype, has_space ? "Invalid %s: %" PRId64 : "Invalid '%s': %" PRId64, + name, val_n); + return; + } + + // String value. + if (has_space) { + api_set_error(err, errtype, quote_val ? "Invalid %s: '%s'" : "Invalid %s: %s", name, val_s); + } else { + api_set_error(err, errtype, quote_val ? "Invalid '%s': '%s'" : "Invalid '%s': %s", name, val_s); + } +} + +/// Creates "Invalid …: expected …" message and sets it on `err`. +void api_err_exp(Error *err, const char *name, const char *expected, const char *actual) +{ + ErrorType errtype = kErrorTypeValidation; + // Treat `name` without whitespace as a parameter (surround in quotes). + // Treat `name` with whitespace as a description (no quotes). + char *has_space = strchr(name, ' '); + + if (!actual) { + api_set_error(err, errtype, + has_space ? "Invalid %s: expected %s" : "Invalid '%s': expected %s", + name, expected); + return; + } + + api_set_error(err, errtype, + has_space ? "Invalid %s: expected %s, got %s" : "Invalid '%s': expected %s, got %s", + name, expected, actual); +} + bool check_string_array(Array arr, char *name, bool disallow_nl, Error *err) { snprintf(IObuff, sizeof(IObuff), "'%s' item", name); diff --git a/src/nvim/api/private/validate.h b/src/nvim/api/private/validate.h index 4a1b99408e..469fed0f83 100644 --- a/src/nvim/api/private/validate.h +++ b/src/nvim/api/private/validate.h @@ -4,48 +4,42 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" -#define VALIDATE_INT(cond, name, val_, code) \ +#define VALIDATE(cond, fmt_, fmt_arg1, code) \ do { \ if (!(cond)) { \ - api_set_error(err, kErrorTypeValidation, "Invalid " name ": %" PRId64, val_); \ + api_set_error(err, kErrorTypeValidation, fmt_, fmt_arg1); \ code; \ } \ } while (0) -#define VALIDATE_S(cond, name, val_, code) \ +#define VALIDATE_INT(cond, name, val_, code) \ do { \ if (!(cond)) { \ - if (strequal(val_, "")) { \ - api_set_error(err, kErrorTypeValidation, "Invalid " name); \ - } else { \ - api_set_error(err, kErrorTypeValidation, "Invalid " name ": '%s'", val_); \ - } \ + api_err_invalid(err, name, NULL, val_, false); \ code; \ } \ } while (0) -#define VALIDATE_EXP(cond, name, expected, actual, code) \ +#define VALIDATE_S(cond, name, val_, code) \ do { \ if (!(cond)) { \ - api_set_error(err, kErrorTypeValidation, "Invalid %s: expected %s, got %s", \ - name, expected, actual); \ + api_err_invalid(err, name, val_, 0, true); \ code; \ } \ } while (0) -#define VALIDATE_T(name, expected_t, actual_t, code) \ +#define VALIDATE_EXP(cond, name, expected, actual, code) \ do { \ - if (expected_t != actual_t) { \ - api_set_error(err, kErrorTypeValidation, "Invalid %s: expected %s, got %s", \ - name, api_typename(expected_t), api_typename(actual_t)); \ + if (!(cond)) { \ + api_err_exp(err, name, expected, actual); \ code; \ } \ } while (0) -#define VALIDATE(cond, fmt_, fmt_arg1, code) \ +#define VALIDATE_T(name, expected_t, actual_t, code) \ do { \ - if (!(cond)) { \ - api_set_error(err, kErrorTypeValidation, fmt_, fmt_arg1); \ + if (expected_t != actual_t) { \ + api_err_exp(err, name, api_typename(expected_t), api_typename(actual_t)); \ code; \ } \ } while (0) @@ -53,7 +47,7 @@ #define VALIDATE_RANGE(cond, name, code) \ do { \ if (!(cond)) { \ - api_set_error(err, kErrorTypeValidation, "Invalid '%s': out of range", name); \ + api_err_invalid(err, name, "out of range", 0, false); \ code; \ } \ } while (0) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 50683ac403..3a93005841 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -654,12 +654,13 @@ Object nvim_get_var(String name, Error *err) { dictitem_T *di = tv_dict_find(&globvardict, name.data, (ptrdiff_t)name.size); if (di == NULL) { // try to autoload script - VALIDATE_S((script_autoload(name.data, name.size, false) && !aborting()), "key", name.data, { + bool found = script_autoload(name.data, name.size, false) && !aborting(); + VALIDATE(found, "Key not found: %s", name.data, { return (Object)OBJECT_INIT; }); di = tv_dict_find(&globvardict, name.data, (ptrdiff_t)name.size); } - VALIDATE_S((di != NULL), "key (not found)", name.data, { + VALIDATE((di != NULL), "Key not found: %s", name.data, { return (Object)OBJECT_INIT; }); return vim_to_object(&di->di_tv); @@ -986,7 +987,7 @@ Integer nvim_open_term(Buffer buffer, DictionaryOf(LuaRef) opts, Error *err) v->data.luaref = LUA_NOREF; break; } else { - VALIDATE_S(false, "key", k.data, {}); + VALIDATE_S(false, "'opts' key", k.data, {}); } } @@ -1632,18 +1633,18 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Arena *arena, Error *er size_t i; // also used for freeing the variables for (i = 0; i < calls.size; i++) { - VALIDATE_T("calls item", kObjectTypeArray, calls.items[i].type, { + VALIDATE_T("'calls' item", kObjectTypeArray, calls.items[i].type, { goto theend; }); Array call = calls.items[i].data.array; - VALIDATE((call.size == 2), "%s", "calls item must be a 2-item Array", { + VALIDATE_EXP((call.size == 2), "'calls' item", "2-item Array", NULL, { goto theend; }); VALIDATE_T("name", kObjectTypeString, call.items[0].type, { goto theend; }); String name = call.items[0].data.string; - VALIDATE_T("args", kObjectTypeArray, call.items[1].type, { + VALIDATE_T("call args", kObjectTypeArray, call.items[1].type, { goto theend; }); Array args = call.items[1].data.array; @@ -2108,10 +2109,10 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * VALIDATE_T("fillchar", kObjectTypeString, opts->fillchar.type, { return result; }); - VALIDATE((opts->fillchar.data.string.size != 0 - && ((size_t)utf_ptr2len(opts->fillchar.data.string.data) - == opts->fillchar.data.string.size)), - "%s", "Invalid fillchar: expected single character", { + VALIDATE_EXP((opts->fillchar.data.string.size != 0 + && ((size_t)utf_ptr2len(opts->fillchar.data.string.data) + == opts->fillchar.data.string.size)), + "fillchar", "single character", NULL, { return result; }); fillchar = utf_ptr2char(opts->fillchar.data.string.data); -- cgit From 09b3432eaff3abcadb56d61b6f247f992b80b63f Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 16 Feb 2023 10:07:18 -0500 Subject: fix(api): allow empty Lua table for nested dicts #22268 Problem: The Lua-API bridge allows Dict params to be empty Lua (list) tables at the function-signature level. But not for _nested_ Dicts, because they are not modeled: https://github.com/neovim/neovim/blob/fae754073289566051433fae74ec65783f9e7a6a/src/nvim/api/keysets.lua#L184 Some API functions like nvim_cmd check for kObjectTypeDictionary and don't handle the case of empty Lua tables (treated as "Array"). Solution: Introduce VALIDATE_T_DICT and use it in places where kObjectTypeDictionary was being checked directly. fixes #21005 --- src/nvim/api/command.c | 175 +++++++++++++++++++++------------------- src/nvim/api/private/validate.h | 23 ++++++ 2 files changed, 116 insertions(+), 82 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 81b70b07d0..6d63ae5e24 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -350,20 +350,24 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } \ } while (0) -#define VALIDATION_ERROR(...) \ +#define VALIDATE_MOD(cond, mod_, name_) \ do { \ - api_set_error(err, kErrorTypeValidation, __VA_ARGS__); \ - goto end; \ + if (!(cond)) { \ + api_set_error(err, kErrorTypeValidation, "Command cannot accept %s: %s", (mod_), (name_)); \ + goto end; \ + } \ } while (0) bool output; OBJ_TO_BOOL(output, opts->output, false, "'output'"); - // First, parse the command name and check if it exists and is valid. - if (!HAS_KEY(cmd->cmd) || cmd->cmd.type != kObjectTypeString - || cmd->cmd.data.string.data[0] == NUL) { - VALIDATION_ERROR("'cmd' must be a non-empty String"); - } + VALIDATE_R(HAS_KEY(cmd->cmd), "cmd", { + goto end; + }); + VALIDATE_EXP((cmd->cmd.type == kObjectTypeString && cmd->cmd.data.string.data[0] != NUL), + "cmd", "non-empty String", NULL, { + goto end; + }); cmdname = string_to_cstr(cmd->cmd.data.string); ea.cmd = cmdname; @@ -382,12 +386,12 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error p = (ret && !aborting()) ? find_ex_command(&ea, NULL) : ea.cmd; } - if (p == NULL || ea.cmdidx == CMD_SIZE) { - VALIDATION_ERROR("Command not found: %s", cmdname); - } - if (is_cmd_ni(ea.cmdidx)) { - VALIDATION_ERROR("Command not implemented: %s", cmdname); - } + VALIDATE((p != NULL && ea.cmdidx != CMD_SIZE), "Command not found: %s", cmdname, { + goto end; + }); + VALIDATE(!is_cmd_ni(ea.cmdidx), "Command not implemented: %s", cmdname, { + goto end; + }); // Get the command flags so that we can know what type of arguments the command uses. // Not required for a user command since `find_ex_command` already deals with it in that case. @@ -397,9 +401,9 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error // Parse command arguments since it's needed to get the command address type. if (HAS_KEY(cmd->args)) { - if (cmd->args.type != kObjectTypeArray) { - VALIDATION_ERROR("'args' must be an Array"); - } + VALIDATE_T("args", kObjectTypeArray, cmd->args.type, { + goto end; + }); // Process all arguments. Convert non-String arguments to String and check if String arguments // have non-whitespace characters. @@ -421,14 +425,15 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error snprintf(data_str, NUMBUFLEN, "%" PRId64, elem.data.integer); break; case kObjectTypeString: - if (string_iswhite(elem.data.string)) { - VALIDATION_ERROR("String command argument must have at least one non-whitespace " - "character"); - } + VALIDATE_EXP(!string_iswhite(elem.data.string), "command arg", "non-whitespace", NULL, { + goto end; + }); data_str = xstrndup(elem.data.string.data, elem.data.string.size); break; default: - VALIDATION_ERROR("Invalid type for command argument"); + VALIDATE_EXP(false, "command arg", "valid type", api_typename(elem.type), { + goto end; + }); break; } @@ -456,9 +461,9 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error break; } - if (!argc_valid) { - VALIDATION_ERROR("Incorrect number of arguments supplied"); - } + VALIDATE(argc_valid, "%s", "Wrong number of arguments", { + goto end; + }); } // Simply pass the first argument (if it exists) as the arg pointer to `set_cmd_addr_type()` @@ -466,22 +471,23 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error set_cmd_addr_type(&ea, args.size > 0 ? args.items[0].data.string.data : NULL); if (HAS_KEY(cmd->range)) { - if (!(ea.argt & EX_RANGE)) { - VALIDATION_ERROR("Command cannot accept a range"); - } else if (cmd->range.type != kObjectTypeArray) { - VALIDATION_ERROR("'range' must be an Array"); - } else if (cmd->range.data.array.size > 2) { - VALIDATION_ERROR("'range' cannot contain more than two elements"); - } + VALIDATE_MOD((ea.argt & EX_RANGE), "range", cmd->cmd.data.string.data); + VALIDATE_T("range", kObjectTypeArray, cmd->range.type, { + goto end; + }); + VALIDATE_EXP((cmd->range.data.array.size <= 2), "range", "<=2 elements", NULL, { + goto end; + }); Array range = cmd->range.data.array; ea.addr_count = (int)range.size; for (size_t i = 0; i < range.size; i++) { Object elem = range.items[i]; - if (elem.type != kObjectTypeInteger || elem.data.integer < 0) { - VALIDATION_ERROR("'range' element must be a non-negative Integer"); - } + VALIDATE_EXP((elem.type == kObjectTypeInteger && elem.data.integer >= 0), + "range element", "non-negative Integer", NULL, { + goto end; + }); } if (range.size > 0) { @@ -489,9 +495,9 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error ea.line2 = (linenr_T)range.items[range.size - 1].data.integer; } - if (invalid_range(&ea) != NULL) { - VALIDATION_ERROR("Invalid range provided"); - } + VALIDATE_S((invalid_range(&ea) == NULL), "range", "", { + goto end; + }); } if (ea.addr_count == 0) { if (ea.argt & EX_DFLALL) { @@ -507,38 +513,38 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } if (HAS_KEY(cmd->count)) { - if (!(ea.argt & EX_COUNT)) { - VALIDATION_ERROR("Command cannot accept a count"); - } else if (cmd->count.type != kObjectTypeInteger || cmd->count.data.integer < 0) { - VALIDATION_ERROR("'count' must be a non-negative Integer"); - } + VALIDATE_MOD((ea.argt & EX_COUNT), "count", cmd->cmd.data.string.data); + VALIDATE_EXP((cmd->count.type == kObjectTypeInteger && cmd->count.data.integer >= 0), + "count", "non-negative Integer", NULL, { + goto end; + }); set_cmd_count(&ea, (linenr_T)cmd->count.data.integer, true); } if (HAS_KEY(cmd->reg)) { - if (!(ea.argt & EX_REGSTR)) { - VALIDATION_ERROR("Command cannot accept a register"); - } else if (cmd->reg.type != kObjectTypeString || cmd->reg.data.string.size != 1) { - VALIDATION_ERROR("'reg' must be a single character"); - } + VALIDATE_MOD((ea.argt & EX_REGSTR), "register", cmd->cmd.data.string.data); + VALIDATE_EXP((cmd->reg.type == kObjectTypeString && cmd->reg.data.string.size == 1), + "reg", "single character", cmd->reg.data.string.data, { + goto end; + }); char regname = cmd->reg.data.string.data[0]; - if (regname == '=') { - VALIDATION_ERROR("Cannot use register \"="); - } else if (!valid_yank_reg(regname, ea.cmdidx != CMD_put && !IS_USER_CMDIDX(ea.cmdidx))) { - VALIDATION_ERROR("Invalid register: \"%c", regname); - } + VALIDATE((regname != '='), "%s", "Cannot use register \"=", { + goto end; + }); + VALIDATE(valid_yank_reg(regname, ea.cmdidx != CMD_put && !IS_USER_CMDIDX(ea.cmdidx)), + "Invalid register: \"%c", regname, { + goto end; + }); ea.regname = (uint8_t)regname; } OBJ_TO_BOOL(ea.forceit, cmd->bang, false, "'bang'"); - if (ea.forceit && !(ea.argt & EX_BANG)) { - VALIDATION_ERROR("Command cannot accept a bang"); - } + VALIDATE_MOD((!ea.forceit || (ea.argt & EX_BANG)), "bang", cmd->cmd.data.string.data); if (HAS_KEY(cmd->magic)) { - if (cmd->magic.type != kObjectTypeDictionary) { - VALIDATION_ERROR("'magic' must be a Dictionary"); - } + VALIDATE_T_DICT("magic", cmd->magic, { + goto end; + }); Dict(cmd_magic) magic = { 0 }; if (!api_dict_to_keydict(&magic, KeyDict_cmd_magic_get_field, @@ -559,9 +565,9 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } if (HAS_KEY(cmd->mods)) { - if (cmd->mods.type != kObjectTypeDictionary) { - VALIDATION_ERROR("'mods' must be a Dictionary"); - } + VALIDATE_T_DICT("mods", cmd->mods, { + goto end; + }); Dict(cmd_mods) mods = { 0 }; if (!api_dict_to_keydict(&mods, KeyDict_cmd_mods_get_field, cmd->mods.data.dictionary, err)) { @@ -569,9 +575,9 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } if (HAS_KEY(mods.filter)) { - if (mods.filter.type != kObjectTypeDictionary) { - VALIDATION_ERROR("'mods.filter' must be a Dictionary"); - } + VALIDATE_T_DICT("mods.filter", mods.filter, { + goto end; + }); Dict(cmd_mods_filter) filter = { 0 }; @@ -581,9 +587,9 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } if (HAS_KEY(filter.pattern)) { - if (filter.pattern.type != kObjectTypeString) { - VALIDATION_ERROR("'mods.filter.pattern' must be a String"); - } + VALIDATE_T2(filter.pattern, kObjectTypeString, { + goto end; + }); OBJ_TO_BOOL(cmdinfo.cmdmod.cmod_filter_force, filter.force, false, "'mods.filter.force'"); @@ -598,18 +604,20 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } if (HAS_KEY(mods.tab)) { - if (mods.tab.type != kObjectTypeInteger) { - VALIDATION_ERROR("'mods.tab' must be an Integer"); - } else if ((int)mods.tab.data.integer >= 0) { + VALIDATE_T2(mods.tab, kObjectTypeInteger, { + goto end; + }); + if ((int)mods.tab.data.integer >= 0) { // Silently ignore negative integers to allow mods.tab to be set to -1. cmdinfo.cmdmod.cmod_tab = (int)mods.tab.data.integer + 1; } } if (HAS_KEY(mods.verbose)) { - if (mods.verbose.type != kObjectTypeInteger) { - VALIDATION_ERROR("'mods.verbose' must be an Integer"); - } else if ((int)mods.verbose.data.integer >= 0) { + VALIDATE_T2(mods.verbose, kObjectTypeInteger, { + goto end; + }); + if ((int)mods.verbose.data.integer >= 0) { // Silently ignore negative integers to allow mods.verbose to be set to -1. cmdinfo.cmdmod.cmod_verbose = (int)mods.verbose.data.integer + 1; } @@ -624,9 +632,9 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error cmdinfo.cmdmod.cmod_split |= (horizontal ? WSP_HOR : 0); if (HAS_KEY(mods.split)) { - if (mods.split.type != kObjectTypeString) { - VALIDATION_ERROR("'mods.split' must be a String"); - } + VALIDATE_T2(mods.split, kObjectTypeString, { + goto end; + }); if (*mods.split.data.string.data == NUL) { // Empty string, do nothing. @@ -641,7 +649,9 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } else if (strcmp(mods.split.data.string.data, "botright") == 0) { cmdinfo.cmdmod.cmod_split |= WSP_BOT; } else { - VALIDATION_ERROR("Invalid value for 'mods.split'"); + VALIDATE_S(false, "mods.split", "", { + goto end; + }); } } @@ -666,9 +676,10 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error cmdinfo.cmdmod.cmod_flags |= CMOD_SILENT; } - if ((cmdinfo.cmdmod.cmod_flags & CMOD_SANDBOX) && !(ea.argt & EX_SBOXOK)) { - VALIDATION_ERROR("Command cannot be run in sandbox"); - } + VALIDATE(!((cmdinfo.cmdmod.cmod_flags & CMOD_SANDBOX) && !(ea.argt & EX_SBOXOK)), + "%s", "Command cannot be run in sandbox", { + goto end; + }); } // Finally, build the command line string that will be stored inside ea.cmdlinep. @@ -739,7 +750,7 @@ end: #undef OBJ_TO_BOOL #undef OBJ_TO_CMOD_FLAG -#undef VALIDATION_ERROR +#undef VALIDATE_MOD } /// Check if a string contains only whitespace characters. diff --git a/src/nvim/api/private/validate.h b/src/nvim/api/private/validate.h index 469fed0f83..91a92c2762 100644 --- a/src/nvim/api/private/validate.h +++ b/src/nvim/api/private/validate.h @@ -38,12 +38,35 @@ #define VALIDATE_T(name, expected_t, actual_t, code) \ do { \ + STATIC_ASSERT(expected_t != kObjectTypeDictionary, "use VALIDATE_T_DICT"); \ if (expected_t != actual_t) { \ api_err_exp(err, name, api_typename(expected_t), api_typename(actual_t)); \ code; \ } \ } while (0) +/// Checks that `obj_` has type `expected_t`. +#define VALIDATE_T2(obj_, expected_t, code) \ + do { \ + STATIC_ASSERT(expected_t != kObjectTypeDictionary, "use VALIDATE_T_DICT"); \ + if ((obj_).type != expected_t) { \ + api_err_exp(err, STR(obj_), api_typename(expected_t), api_typename((obj_).type)); \ + code; \ + } \ + } while (0) + +/// Checks that `obj_` has Dict type. Also allows empty Array in a Lua context. +#define VALIDATE_T_DICT(name, obj_, code) \ + do { \ + if ((obj_).type != kObjectTypeDictionary \ + && !(channel_id == LUA_INTERNAL_CALL \ + && (obj_).type == kObjectTypeArray \ + && (obj_).data.array.size == 0)) { \ + api_err_exp(err, name, api_typename(kObjectTypeDictionary), api_typename((obj_).type)); \ + code; \ + } \ + } while (0) + #define VALIDATE_RANGE(cond, name, code) \ do { \ if (!(cond)) { \ -- cgit From b62c0c8d9c22ae7fc9ee200733f8312efa6dbced Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Mon, 20 Feb 2023 08:12:59 +0100 Subject: docs: fix typos (#21961) Co-authored-by: Ben Morgan --- src/nvim/api/ui.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 61f2c881b3..3c3c3008f4 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -254,7 +254,7 @@ void nvim_ui_detach(uint64_t channel_id, Error *err) remote_ui_disconnect(channel_id); } -// TODO(bfredl): use me to detach a specifc ui from the server +// TODO(bfredl): use me to detach a specific ui from the server void remote_ui_stop(UI *ui) {} -- cgit From 344a1ee8e6b7d78120f8393d1babfd285e866334 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 22 Feb 2023 00:07:26 +0800 Subject: docs: fix typos (#22353) --- src/nvim/api/extmark.c | 2 +- src/nvim/api/ui.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 91486abf38..845a4c7dbe 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -445,7 +445,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// buffer. /// - right_gravity : boolean that indicates the direction /// the extmark will be shifted in when new text is inserted -/// (true for right, false for left). defaults to true. +/// (true for right, false for left). Defaults to true. /// - end_right_gravity : boolean that indicates the direction /// the extmark end position (if it exists) will be shifted /// in when new text is inserted (true for right, false diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 3c3c3008f4..f6dee066dc 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -382,7 +382,7 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e }); bool boolval = value.data.boolean; if (!init && i == kUILinegrid && boolval != ui->ui_ext[i]) { - // There shouldn't be a reason for an UI to do this ever + // There shouldn't be a reason for a UI to do this ever // so explicitly don't support this. api_set_error(err, kErrorTypeValidation, "ext_linegrid option cannot be changed"); } -- cgit From 6752f1005d26c93a033d856a60b7b296f3e51634 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 14 Dec 2022 19:58:18 +0100 Subject: docs: naming conventions, guidelines close #21063 --- src/nvim/api/command.c | 29 ++++++++++++++--------------- src/nvim/api/vim.c | 17 ++++++++--------- 2 files changed, 22 insertions(+), 24 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 6d63ae5e24..32378ed244 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -899,15 +899,13 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin } } -/// Create a new user command |user-commands| +/// Creates a global |user-commands| command. /// -/// {name} is the name of the new command. The name must begin with an uppercase letter. -/// -/// {command} is the replacement text or Lua function to execute. +/// For Lua usage see |lua-guide-commands-create|. /// /// Example: ///
vim
-///    :call nvim_create_user_command('SayHello', 'echo "Hello world!"', {})
+///    :call nvim_create_user_command('SayHello', 'echo "Hello world!"', {'bang': v:true})
 ///    :SayHello
 ///    Hello world!
 /// 
@@ -929,15 +927,16 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin /// - mods: (string) Command modifiers, if any || /// - smods: (table) Command modifiers in a structured format. Has the same /// structure as the "mods" key of |nvim_parse_cmd()|. -/// @param opts Optional command attributes. See |command-attributes| for more details. To use -/// boolean attributes (such as |:command-bang| or |:command-bar|) set the value to -/// "true". In addition to the string options listed in |:command-complete|, the -/// "complete" key also accepts a Lua function which works like the "customlist" -/// completion mode |:command-completion-customlist|. Additional parameters: -/// - desc: (string) Used for listing the command when a Lua function is used for -/// {command}. -/// - force: (boolean, default true) Override any previous definition. -/// - preview: (function) Preview callback for 'inccommand' |:command-preview| +/// @param opts Optional |command-attributes|. +/// - Set boolean attributes such as |:command-bang| or |:command-bar| to true (but +/// not |:command-buffer|, use |nvim_buf_create_user_command()| instead). +/// - "complete" |:command-complete| also accepts a Lua function which works like +/// |:command-completion-customlist|. +/// - Other parameters: +/// - desc: (string) Used for listing the command when a Lua function is used for +/// {command}. +/// - force: (boolean, default true) Override any previous definition. +/// - preview: (function) Preview callback for 'inccommand' |:command-preview| /// @param[out] err Error details, if any. void nvim_create_user_command(String name, Object command, Dict(user_command) *opts, Error *err) FUNC_API_SINCE(9) @@ -955,7 +954,7 @@ void nvim_del_user_command(String name, Error *err) nvim_buf_del_user_command(-1, name, err); } -/// Create a new user command |user-commands| in the given buffer. +/// Creates a buffer-local command |user-commands|. /// /// @param buffer Buffer handle, or 0 for current buffer. /// @param[out] err Error details, if any. diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 3a93005841..0f27040fd3 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1442,15 +1442,14 @@ ArrayOf(Dictionary) nvim_get_keymap(String mode) /// or "!" for |:map!|, or empty string for |:map|. /// @param lhs Left-hand-side |{lhs}| of the mapping. /// @param rhs Right-hand-side |{rhs}| of the mapping. -/// @param opts Optional parameters map: keys are |:map-arguments|, values are booleans (default -/// false). Accepts all |:map-arguments| as keys excluding || but including -/// |:noremap| and "desc". Unknown key is an error. -/// "desc" can be used to give a description to the mapping. -/// When called from Lua, also accepts a "callback" key that takes a Lua function to -/// call when the mapping is executed. -/// When "expr" is true, "replace_keycodes" (boolean) can be used to replace keycodes -/// in the resulting string (see |nvim_replace_termcodes()|), and a Lua callback -/// returning `nil` is equivalent to returning an empty string. +/// @param opts Optional parameters map: Accepts all |:map-arguments| as keys except ||, +/// values are booleans (default false). Also: +/// - "noremap" non-recursive mapping |:noremap| +/// - "desc" human-readable description. +/// - "callback" Lua function called when the mapping is executed. +/// - "replace_keycodes" (boolean) When "expr" is true, replace keycodes in the +/// resulting string (see |nvim_replace_termcodes()|). Returning nil from the Lua +/// "callback" is equivalent to returning an empty string. /// @param[out] err Error details, if any. void nvim_set_keymap(uint64_t channel_id, String mode, String lhs, String rhs, Dict(keymap) *opts, Error *err) -- cgit From 7f424e2b65779c59fc0cac3cc7508ba2ec07f200 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 23 Feb 2023 18:29:36 +0100 Subject: feat(api): more fields in nvim_list_uis Problem: nvim_list_uis does not report all ":help ui-option" fields. Solution: Store ":help ui-option" fields on the `UI` object and update ui_array. --- src/nvim/api/ui.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index f6dee066dc..00fd2781ff 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -113,6 +113,10 @@ void remote_ui_disconnect(uint64_t channel_id) kv_destroy(data->call_buf); pmap_del(uint64_t)(&connected_uis, channel_id); ui_detach_impl(ui, channel_id); + + // Destroy `ui`. + XFREE_CLEAR(ui->term_name); + XFREE_CLEAR(ui->term_background); xfree(ui); } @@ -163,15 +167,9 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona UI *ui = xcalloc(1, sizeof(UI)); ui->width = (int)width; ui->height = (int)height; - ui->pum_nlines = 0; - ui->pum_pos = false; - ui->pum_width = 0.0; - ui->pum_height = 0.0; ui->pum_row = -1.0; ui->pum_col = -1.0; ui->rgb = true; - ui->override = false; - CLEAR_FIELD(ui->ui_ext); for (size_t i = 0; i < options.size; i++) { @@ -320,6 +318,7 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e return; }); set_tty_option("term", string_to_cstr(value.data.string)); + ui->term_name = string_to_cstr(value.data.string); return; } @@ -328,6 +327,7 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e return; }); t_colors = (int)value.data.integer; + ui->term_colors = (int)value.data.integer; return; } @@ -336,6 +336,7 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e return; }); set_tty_background(value.data.string.data); + ui->term_background = string_to_cstr(value.data.string); return; } @@ -351,6 +352,7 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e }); stdin_fd = (int)value.data.integer; + ui->stdin_fd = (int)value.data.integer; return; } @@ -359,6 +361,7 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e return; }); stdin_isatty = value.data.boolean; + ui->stdin_tty = value.data.boolean; return; } @@ -367,6 +370,7 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e return; }); stdout_isatty = value.data.boolean; + ui->stdout_tty = value.data.boolean; return; } -- cgit From ce597235a26839826de88ecd8b949ec54c310fbd Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 27 Feb 2023 16:31:05 +0100 Subject: feat(ui): restore has('gui_running') Problem: has('gui_running') is still common in the wild and our answer has changed over time, causing frustration. https://github.com/vimpostor/vim-tpipeline/commit/95a6ccbe9f33bc42dd4cee45731d8bc3fbcd92d1 Solution: Use stdin_tty/stdout_tty to decide if a UI is (not) a GUI. --- src/nvim/api/ui.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 00fd2781ff..a8f5d2e070 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -352,7 +352,6 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e }); stdin_fd = (int)value.data.integer; - ui->stdin_fd = (int)value.data.integer; return; } -- cgit From 7e19cabeb192d2e7f20d7bb965a3f62e1543d2ac Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 28 Feb 2023 12:38:33 +0100 Subject: perf(lsp): only redraw the windows containing LSP tokens redraw! redraws the entire screen instead of just the windows with the buffer which were actually changed. I considered trying to calculating the range for the delta but it looks tricky. Could a follow-up. --- src/nvim/api/buffer.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index bbdb66988b..ca3cf76388 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -248,6 +248,9 @@ void nvim__buf_redraw_range(Buffer buffer, Integer first, Integer last, Error *e if (!buf) { return; } + if (last < 0) { + last = buf->b_ml.ml_line_count; + } redraw_buf_range_later(buf, (linenr_T)first + 1, (linenr_T)last); } -- cgit From 39842be8cd8808c7da2638a6cc84d7c3fe40b996 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 5 Mar 2023 07:09:28 +0800 Subject: fix(extmarks): don't leak memory on error (#22507) --- src/nvim/api/extmark.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 845a4c7dbe..9e03cc8676 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -809,8 +809,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer return (Integer)id; error: - clear_virttext(&decor.virt_text); - xfree(decor.sign_text); + decor_clear(&decor); return 0; } -- cgit From 89a525de9f2551e460cc91d40fd7afbb7e07622f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 9 Mar 2023 10:19:00 +0800 Subject: fix(buffer_updates): save and restore current window cursor (#16732) When a buffer update callback is called, textlock is active so buffer text cannot be changed, but cursor can still be moved. This can cause problems when the buffer update is in the middle of an operator, like the one mentioned in #16729. The solution is to save cursor position and restore it afterwards, like how cursor is saved and restored when evaluating an mapping. --- src/nvim/api/private/helpers.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index b70452d7cb..1b82aeac34 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -155,8 +155,18 @@ typedef struct { msglist_T *private_msg_list; \ msg_list = &private_msg_list; \ private_msg_list = NULL; \ - code \ - msg_list = saved_msg_list; /* Restore the exception context. */ \ + code; \ + msg_list = saved_msg_list; /* Restore the exception context. */ \ + } while (0) + +// Execute code with cursor position saved and restored and textlock active. +#define TEXTLOCK_WRAP(code) \ + do { \ + const pos_T save_cursor = curwin->w_cursor; \ + textlock++; \ + code; \ + textlock--; \ + curwin->w_cursor = save_cursor; \ } while (0) // Useful macro for executing some `code` for each item in an array. -- cgit From 6d0c61d90d316473eee0729363e20bf06825b09b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 11 Mar 2023 21:09:11 +0800 Subject: fix(api): set script context when setting usercmd or option (#22624) --- src/nvim/api/command.c | 25 ++++++++++++++----------- src/nvim/api/options.c | 7 +++++-- 2 files changed, 19 insertions(+), 13 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 32378ed244..de766c14b9 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -938,10 +938,11 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin /// - force: (boolean, default true) Override any previous definition. /// - preview: (function) Preview callback for 'inccommand' |:command-preview| /// @param[out] err Error details, if any. -void nvim_create_user_command(String name, Object command, Dict(user_command) *opts, Error *err) +void nvim_create_user_command(uint64_t channel_id, String name, Object command, + Dict(user_command) *opts, Error *err) FUNC_API_SINCE(9) { - create_user_command(name, command, opts, 0, err); + create_user_command(channel_id, name, command, opts, 0, err); } /// Delete a user-defined command. @@ -959,7 +960,7 @@ void nvim_del_user_command(String name, Error *err) /// @param buffer Buffer handle, or 0 for current buffer. /// @param[out] err Error details, if any. /// @see nvim_create_user_command -void nvim_buf_create_user_command(Buffer buffer, String name, Object command, +void nvim_buf_create_user_command(uint64_t channel_id, Buffer buffer, String name, Object command, Dict(user_command) *opts, Error *err) FUNC_API_SINCE(9) { @@ -970,7 +971,7 @@ void nvim_buf_create_user_command(Buffer buffer, String name, Object command, buf_T *save_curbuf = curbuf; curbuf = target_buf; - create_user_command(name, command, opts, UC_BUFFER, err); + create_user_command(channel_id, name, command, opts, UC_BUFFER, err); curbuf = save_curbuf; } @@ -1011,8 +1012,8 @@ void nvim_buf_del_user_command(Buffer buffer, String name, Error *err) api_set_error(err, kErrorTypeException, "Invalid command (not found): %s", name.data); } -void create_user_command(String name, Object command, Dict(user_command) *opts, int flags, - Error *err) +void create_user_command(uint64_t channel_id, String name, Object command, Dict(user_command) *opts, + int flags, Error *err) { uint32_t argt = 0; int64_t def = -1; @@ -1205,11 +1206,13 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, }); } - if (uc_add_command(name.data, name.size, rep, argt, def, flags, compl, compl_arg, compl_luaref, - preview_luaref, addr_type_arg, luaref, force) != OK) { - api_set_error(err, kErrorTypeException, "Failed to create user command"); - // Do not goto err, since uc_add_command now owns luaref, compl_luaref, and compl_arg - } + WITH_SCRIPT_CONTEXT(channel_id, { + if (uc_add_command(name.data, name.size, rep, argt, def, flags, compl, compl_arg, compl_luaref, + preview_luaref, addr_type_arg, luaref, force) != OK) { + api_set_error(err, kErrorTypeException, "Failed to create user command"); + // Do not goto err, since uc_add_command now owns luaref, compl_luaref, and compl_arg + } + }); return; diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index ddaed3a254..2d9ffcba06 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -157,7 +157,8 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) /// - win: |window-ID|. Used for setting window local option. /// - buf: Buffer number. Used for setting buffer local option. /// @param[out] err Error details, if any -void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error *err) +void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict(option) *opts, + Error *err) FUNC_API_SINCE(9) { int scope = 0; @@ -202,7 +203,9 @@ void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error }); } - access_option_value_for(name.data, &numval, &stringval, scope, opt_type, to, false, err); + WITH_SCRIPT_CONTEXT(channel_id, { + access_option_value_for(name.data, &numval, &stringval, scope, opt_type, to, false, err); + }); } /// Gets the option information for all options. -- cgit From 7dc9182cf0b27cbfb4e289db55dd7b02998ef5c8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 11 Mar 2023 21:29:25 +0800 Subject: vim-patch:8.2.1398: autoload script sourced twice if sourced directly (#22622) Problem: Autoload script sourced twice if sourced directly. Solution: Do not source an autoload script again. (issue vim/vim#6644) https://github.com/vim/vim/commit/daa2f36573db3e1df7eb1fdbc3a09a2815644048 Cherry-pick ret_sid changes from patch 8.2.0149. Use do_in_runtimepath() as that's what source_runtime() calls in Nvim. Co-authored-by: Bram Moolenaar --- src/nvim/api/vim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 0f27040fd3..315ccd13e6 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -579,7 +579,7 @@ ArrayOf(String) nvim__get_runtime(Array pat, Boolean all, Dict(runtime) *opts, E if (source) { for (size_t i = 0; i < res.size; i++) { String name = res.items[i].data.string; - (void)do_source(name.data, false, DOSO_NONE); + (void)do_source(name.data, false, DOSO_NONE, NULL); } } -- cgit From fd2ece278b0941ec6673489e88868120e86b834a Mon Sep 17 00:00:00 2001 From: Matthias Deiml Date: Sun, 12 Mar 2023 23:58:46 +0100 Subject: feat(ui): add scroll_delta to win_viewport event #19270 scroll_delta contains how much the top line of a window moved since the last time win_viewport was emitted. It is expected to be used to implement smooth scrolling. For this purpose it only counts "virtual" or "displayed" so folds should count as one line. Because of this it adds extra information that cannot be computed from the topline parameter. Fixes #19227 --- src/nvim/api/ui_events.in.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index a08e8dbfeb..b93f521ca3 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -114,7 +114,7 @@ void msg_set_pos(Integer grid, Integer row, Boolean scrolled, String sep_char) FUNC_API_SINCE(6) FUNC_API_COMPOSITOR_IMPL FUNC_API_CLIENT_IGNORE; void win_viewport(Integer grid, Window win, Integer topline, Integer botline, Integer curline, - Integer curcol, Integer line_count) + Integer curcol, Integer line_count, Integer scroll_delta) FUNC_API_SINCE(7) FUNC_API_CLIENT_IGNORE; void win_extmark(Integer grid, Window win, Integer ns_id, Integer mark_id, Integer row, Integer col) -- cgit From 320cb344c14b30f8c1aa8c2d86803e4c2f971ae9 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Thu, 16 Mar 2023 09:31:37 +0100 Subject: docs(api): link to nvim_set_hl_ns from nvim_set_hl (#22678) --- src/nvim/api/vim.c | 8 +++++--- src/nvim/api/window.c | 5 +++-- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 315ccd13e6..a8cc7aa454 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -141,6 +141,8 @@ Dictionary nvim__get_hl_defs(Integer ns_id, Arena *arena, Error *err) /// /// @param ns_id Namespace id for this highlight |nvim_create_namespace()|. /// Use 0 to set a highlight group globally |:highlight|. +/// Highlights from non-global namespaces are not active by default, use +/// |nvim_set_hl_ns()| or |nvim_win_set_hl_ns()| to activate them. /// @param name Highlight group name, e.g. "ErrorMsg" /// @param val Highlight definition map, accepts the following keys: /// - fg (or foreground): color name or "#RRGGBB", see note. @@ -183,8 +185,8 @@ void nvim_set_hl(Integer ns_id, String name, Dict(highlight) *val, Error *err) } } -/// Set active namespace for highlights. This can be set for a single window, -/// see |nvim_win_set_hl_ns()|. +/// Set active namespace for highlights defined with |nvim_set_hl()|. This can be set for +/// a single window, see |nvim_win_set_hl_ns()|. /// /// @param ns_id the namespace to use /// @param[out] err Error details, if any @@ -200,7 +202,7 @@ void nvim_set_hl_ns(Integer ns_id, Error *err) redraw_all_later(UPD_NOT_VALID); } -/// Set active namespace for highlights while redrawing. +/// Set active namespace for highlights defined with |nvim_set_hl()| while redrawing. /// /// This function meant to be called while redrawing, primarily from /// |nvim_set_decoration_provider()| on_win and on_line callbacks, which diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index e2c234ab29..abe11e6b72 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -445,8 +445,9 @@ Object nvim_win_call(Window window, LuaRef fun, Error *err) return res; } -/// Set highlight namespace for a window. This will use highlights defined in -/// this namespace, but fall back to global highlights (ns=0) when missing. +/// Set highlight namespace for a window. This will use highlights defined with +/// |nvim_set_hl()| for this namespace, but fall back to global highlights (ns=0) when +/// missing. /// /// This takes precedence over the 'winhighlight' option. /// -- cgit From 8021300806e2ccf04b3ec33970b682ee3c7a9cc3 Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 16 Mar 2023 13:56:05 +0100 Subject: refactor(extmarks): some minor internal API changes extranges and a bunch of other improvements are coming for 0.10 This gets in some minor surrounding API changes to avoid rebase conflicts until then. - decorations will be able to be specific to windows - adjust deletion API to fit with extranges --- src/nvim/api/extmark.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 9e03cc8676..adc2925b7e 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -793,7 +793,7 @@ 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.buf == buf) { + if (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) { -- cgit From e1db0e35e4d5859b96e6aff882df62d6c714b569 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 15 Mar 2023 23:30:14 +0000 Subject: feat(api): add filetype option nvim_get_option_value - Also adjust the expr-mapping behaviour so normal commands and text changes are allowed in internal dummy buffers. --- src/nvim/api/keysets.lua | 1 + src/nvim/api/options.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua index 30dcef6127..2c7532bd27 100644 --- a/src/nvim/api/keysets.lua +++ b/src/nvim/api/keysets.lua @@ -102,6 +102,7 @@ return { "scope"; "win"; "buf"; + "filetype"; }}; { 'highlight', { "bold"; diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 2d9ffcba06..a0351cc6cd 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -24,7 +24,7 @@ #endif static int validate_option_value_args(Dict(option) *opts, int *scope, int *opt_type, void **from, - Error *err) + char **filetype, Error *err) { if (HAS_KEY(opts->scope)) { VALIDATE_T("scope", kObjectTypeString, opts->scope.type, { @@ -44,6 +44,14 @@ static int validate_option_value_args(Dict(option) *opts, int *scope, int *opt_t *opt_type = SREQ_GLOBAL; + if (filetype != NULL && HAS_KEY(opts->filetype)) { + VALIDATE_T("scope", kObjectTypeString, opts->filetype.type, { + return FAIL; + }); + + *filetype = opts->filetype.data.string.data; + } + if (HAS_KEY(opts->win)) { VALIDATE_T("win", kObjectTypeInteger, opts->win.type, { return FAIL; @@ -69,10 +77,17 @@ static int validate_option_value_args(Dict(option) *opts, int *scope, int *opt_t } } + VALIDATE((!HAS_KEY(opts->filetype) + || !(HAS_KEY(opts->buf) || HAS_KEY(opts->scope) || HAS_KEY(opts->win))), + "%s", "cannot use 'filetype' with 'scope', 'buf' or 'win'", { + return FAIL; + }); + VALIDATE((!HAS_KEY(opts->scope) || !HAS_KEY(opts->buf)), "%s", "cannot use both 'scope' and 'buf'", { return FAIL; }); + VALIDATE((!HAS_KEY(opts->win) || !HAS_KEY(opts->buf)), "%s", "cannot use both 'buf' and 'win'", { return FAIL; }); @@ -80,6 +95,30 @@ static int validate_option_value_args(Dict(option) *opts, int *scope, int *opt_t return OK; } +/// Create a dummy buffer and run the FileType autocmd on it. +static buf_T *do_ft_buf(char *filetype, aco_save_T *aco, Error *err) +{ + if (filetype == NULL) { + return NULL; + } + + // Allocate a buffer without putting it in the buffer list. + buf_T *ftbuf = buflist_new(NULL, NULL, 1, BLN_DUMMY); + if (ftbuf == NULL) { + api_set_error(err, kErrorTypeException, "Could not create internal buffer"); + return NULL; + } + + // Set curwin/curbuf to buf and save a few things. + aucmd_prepbuf(aco, ftbuf); + + ftbuf->b_p_ft = xstrdup(filetype); + + apply_autocmds(EVENT_FILETYPE, ftbuf->b_p_ft, ftbuf->b_fname, true, ftbuf); + + return ftbuf; +} + /// Gets the value of an option. The behavior of this function matches that of /// |:set|: the local value of an option is returned if it exists; otherwise, /// the global value is returned. Local values always correspond to the current @@ -92,6 +131,10 @@ static int validate_option_value_args(Dict(option) *opts, int *scope, int *opt_t /// - win: |window-ID|. Used for getting window local options. /// - buf: Buffer number. Used for getting buffer local options. /// Implies {scope} is "local". +/// - filetype: |filetype|. Used to get the default option for a +/// specific filetype. Cannot be used with any other option. +/// Note: this is expensive, it is recommended to cache this +/// value. /// @param[out] err Error details, if any /// @return Option value Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) @@ -102,14 +145,37 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) int scope = 0; int opt_type = SREQ_GLOBAL; void *from = NULL; - if (!validate_option_value_args(opts, &scope, &opt_type, &from, err)) { + char *filetype = NULL; + + if (!validate_option_value_args(opts, &scope, &opt_type, &from, &filetype, err)) { + return rv; + } + + aco_save_T aco; + + buf_T *ftbuf = do_ft_buf(filetype, &aco, err); + if (ERROR_SET(err)) { return rv; } + if (ftbuf != NULL) { + assert(!from); + from = ftbuf; + } + long numval = 0; char *stringval = NULL; getoption_T result = access_option_value_for(name.data, &numval, &stringval, scope, opt_type, from, true, err); + + if (ftbuf != NULL) { + // restore curwin/curbuf and a few other things + aucmd_restbuf(&aco); + + assert(curbuf != ftbuf); // safety check + wipe_buffer(ftbuf, false); + } + if (ERROR_SET(err)) { return rv; } @@ -164,7 +230,7 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict( int scope = 0; int opt_type = SREQ_GLOBAL; void *to = NULL; - if (!validate_option_value_args(opts, &scope, &opt_type, &to, err)) { + if (!validate_option_value_args(opts, &scope, &opt_type, &to, NULL, err)) { return; } -- cgit From e5641df6d3fc3bb6c3c55593b6152082bfc561b6 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sat, 11 Mar 2023 17:11:02 +0000 Subject: feat: add `vim.filetype.get_option()` --- src/nvim/api/options.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index a0351cc6cd..7aef6e6146 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -114,7 +114,11 @@ static buf_T *do_ft_buf(char *filetype, aco_save_T *aco, Error *err) ftbuf->b_p_ft = xstrdup(filetype); - apply_autocmds(EVENT_FILETYPE, ftbuf->b_p_ft, ftbuf->b_fname, true, ftbuf); + TRY_WRAP({ + try_start(); + apply_autocmds(EVENT_FILETYPE, ftbuf->b_p_ft, ftbuf->b_fname, true, ftbuf); + try_end(err); + }); return ftbuf; } @@ -133,8 +137,8 @@ static buf_T *do_ft_buf(char *filetype, aco_save_T *aco, Error *err) /// Implies {scope} is "local". /// - filetype: |filetype|. Used to get the default option for a /// specific filetype. Cannot be used with any other option. -/// Note: this is expensive, it is recommended to cache this -/// value. +/// Note: this will trigger |ftplugin| and all |FileType| +/// autocommands for the corresponding filetype. /// @param[out] err Error details, if any /// @return Option value Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) -- cgit From 3285cd6eccd9b7f33cc32f992c2607c3fc4ca13f Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 22 Mar 2023 10:09:28 +0000 Subject: refactor: do more in TRY_WRAP --- src/nvim/api/autocmd.c | 8 +--- src/nvim/api/command.c | 5 +-- src/nvim/api/options.c | 4 +- src/nvim/api/private/helpers.h | 4 +- src/nvim/api/vim.c | 8 +--- src/nvim/api/vimscript.c | 97 ++++++++++++++++++++++-------------------- 6 files changed, 60 insertions(+), 66 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index aff7622dc5..620a295788 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -683,11 +683,9 @@ Integer nvim_create_augroup(uint64_t channel_id, String name, Dict(create_augrou void nvim_del_augroup_by_id(Integer id, Error *err) FUNC_API_SINCE(9) { - TRY_WRAP({ - try_start(); + TRY_WRAP(err, { char *name = augroup_name((int)id); augroup_del(name, false); - try_end(err); }); } @@ -700,10 +698,8 @@ void nvim_del_augroup_by_id(Integer id, Error *err) void nvim_del_augroup_by_name(String name, Error *err) FUNC_API_SINCE(9) { - TRY_WRAP({ - try_start(); + TRY_WRAP(err, { augroup_del(name.data, false); - try_end(err); }); } diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index de766c14b9..1455f28050 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -697,8 +697,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error capture_ga = &capture_local; } - TRY_WRAP({ - try_start(); + TRY_WRAP(err, { if (output) { msg_silent++; msg_col = 0; // prevent leading spaces @@ -714,8 +713,6 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error // Put msg_col back where it was, since nothing should have been written. msg_col = save_msg_col; } - - try_end(err); }); if (ERROR_SET(err)) { diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 7aef6e6146..502c73d02d 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -114,10 +114,8 @@ static buf_T *do_ft_buf(char *filetype, aco_save_T *aco, Error *err) ftbuf->b_p_ft = xstrdup(filetype); - TRY_WRAP({ - try_start(); + TRY_WRAP(err, { apply_autocmds(EVENT_FILETYPE, ftbuf->b_p_ft, ftbuf->b_fname, true, ftbuf); - try_end(err); }); return ftbuf; diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 1b82aeac34..eef97cccb2 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -149,13 +149,15 @@ typedef struct { // which would otherwise be ignored. This pattern is from do_cmdline(). // // TODO(bfredl): prepare error-handling at "top level" (nv_event). -#define TRY_WRAP(code) \ +#define TRY_WRAP(err, code) \ do { \ msglist_T **saved_msg_list = msg_list; \ msglist_T *private_msg_list; \ msg_list = &private_msg_list; \ private_msg_list = NULL; \ + try_start(); \ code; \ + try_end(err); \ msg_list = saved_msg_list; /* Restore the exception context. */ \ } while (0) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index a8cc7aa454..4689e6b5bf 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -538,10 +538,8 @@ ArrayOf(String) nvim_get_runtime_file(String name, Boolean all, Error *err) int flags = DIP_DIRFILE | (all ? DIP_ALL : 0); - TRY_WRAP({ - try_start(); + TRY_WRAP(err, { do_in_runtimepath((name.size ? name.data : ""), flags, find_runtime_cb, &rv); - try_end(err); }); return rv; } @@ -1238,14 +1236,12 @@ void nvim_put(ArrayOf(String) lines, String type, Boolean after, Boolean follow, finish_yankreg_from_object(reg, false); - TRY_WRAP({ - try_start(); + TRY_WRAP(err, { bool VIsual_was_active = VIsual_active; msg_silent++; // Avoid "N more lines" message. do_put(0, reg, after ? FORWARD : BACKWARD, 1, follow ? PUT_CURSEND : 0); msg_silent--; VIsual_active = VIsual_was_active; - try_end(err); }); cleanup: diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index af1b23b712..32dcbdec3f 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -137,35 +137,37 @@ Object nvim_eval(String expr, Error *err) static int recursive = 0; // recursion depth Object rv = OBJECT_INIT; - TRY_WRAP({ - // Initialize `force_abort` and `suppress_errthrow` at the top level. - if (!recursive) { - force_abort = false; - suppress_errthrow = false; - did_throw = false; - // `did_emsg` is set by emsg(), which cancels execution. - did_emsg = false; - } - recursive++; - try_start(); + // Initialize `force_abort` and `suppress_errthrow` at the top level. + if (!recursive) { + force_abort = false; + suppress_errthrow = false; + did_throw = false; + // `did_emsg` is set by emsg(), which cancels execution. + did_emsg = false; + } - typval_T rettv; - int ok = eval0(expr.data, &rettv, NULL, true); + recursive++; - if (!try_end(err)) { - if (ok == FAIL) { - // Should never happen, try_end() should get the error. #8371 - api_set_error(err, kErrorTypeException, - "Failed to evaluate expression: '%.*s'", 256, expr.data); - } else { - rv = vim_to_object(&rettv); - } - } + typval_T rettv; + int ok; - tv_clear(&rettv); - recursive--; + TRY_WRAP(err, { + ok = eval0(expr.data, &rettv, NULL, true); }); + if (!ERROR_SET(err)) { + if (ok == FAIL) { + // Should never happen, try_end() (in TRY_WRAP) should get the error. #8371 + api_set_error(err, kErrorTypeException, + "Failed to evaluate expression: '%.*s'", 256, expr.data); + } else { + rv = vim_to_object(&rettv); + } + } + + tv_clear(&rettv); + recursive--; + return rv; } @@ -196,34 +198,37 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err) } } - TRY_WRAP({ - // Initialize `force_abort` and `suppress_errthrow` at the top level. - if (!recursive) { - force_abort = false; - suppress_errthrow = false; - did_throw = false; - // `did_emsg` is set by emsg(), which cancels execution. - did_emsg = false; - } - recursive++; - try_start(); - typval_T rettv; - funcexe_T funcexe = FUNCEXE_INIT; - funcexe.fe_firstline = curwin->w_cursor.lnum; - funcexe.fe_lastline = curwin->w_cursor.lnum; - funcexe.fe_evaluate = true; - funcexe.fe_selfdict = self; + // Initialize `force_abort` and `suppress_errthrow` at the top level. + if (!recursive) { + force_abort = false; + suppress_errthrow = false; + did_throw = false; + // `did_emsg` is set by emsg(), which cancels execution. + did_emsg = false; + } + recursive++; + + typval_T rettv; + funcexe_T funcexe = FUNCEXE_INIT; + funcexe.fe_firstline = curwin->w_cursor.lnum; + funcexe.fe_lastline = curwin->w_cursor.lnum; + funcexe.fe_evaluate = true; + funcexe.fe_selfdict = self; + + TRY_WRAP(err, { // call_func() retval is deceptive, ignore it. Instead we set `msg_list` // (see above) to capture abort-causing non-exception errors. (void)call_func(fn.data, (int)fn.size, &rettv, (int)args.size, vim_args, &funcexe); - if (!try_end(err)) { - rv = vim_to_object(&rettv); - } - tv_clear(&rettv); - recursive--; }); + if (!ERROR_SET(err)) { + rv = vim_to_object(&rettv); + } + + tv_clear(&rettv); + recursive--; + free_vim_args: while (i > 0) { tv_clear(&vim_args[--i]); -- cgit From 28cfcf51269b7390b447c8a5b61d5083c830e834 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 22 Mar 2023 16:49:04 +0000 Subject: fix(api): vim.filetype.get_option() (#22753) - Fix a bug in the cache - Set some buffer options on the dummy buffer --- src/nvim/api/options.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 502c73d02d..7a453c01b4 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -111,6 +111,10 @@ static buf_T *do_ft_buf(char *filetype, aco_save_T *aco, Error *err) // Set curwin/curbuf to buf and save a few things. aucmd_prepbuf(aco, ftbuf); + set_option_value("bufhidden", 0L, "hide", OPT_LOCAL); + set_option_value("buftype", 0L, "nofile", OPT_LOCAL); + set_option_value("swapfile", 0L, NULL, OPT_LOCAL); + set_option_value("modeline", 0L, NULL, OPT_LOCAL); // 'nomodeline' ftbuf->b_p_ft = xstrdup(filetype); -- cgit From c0fe6c040e19ef9102a8507ffcbd88b83186326a Mon Sep 17 00:00:00 2001 From: Null Chilly <56817415+nullchilly@users.noreply.github.com> Date: Thu, 23 Mar 2023 16:31:39 +0700 Subject: feat(api): add nvim_get_hl (#22693) Problem: no way of getting all highlight group definitions in a namespace. Solution: add `nvim_get_hl()`, deprecate `nvim_get_hl_by_name()` and `nvim_get_hl_by_id()`. --- src/nvim/api/deprecated.c | 46 ++++++++++++++++++++++++++++++++++++++ src/nvim/api/keysets.lua | 5 +++++ src/nvim/api/ui.c | 8 +++---- src/nvim/api/vim.c | 56 +++++++++++++---------------------------------- 4 files changed, 70 insertions(+), 45 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 332e2b5fc3..b1e2e6811e 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -10,11 +10,14 @@ #include "nvim/api/extmark.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/api/vimscript.h" #include "nvim/buffer_defs.h" #include "nvim/decoration.h" #include "nvim/extmark.h" #include "nvim/globals.h" +#include "nvim/highlight.h" +#include "nvim/highlight_group.h" #include "nvim/lua/executor.h" #include "nvim/memory.h" #include "nvim/pos.h" @@ -159,6 +162,49 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A return src_id; } +/// Gets a highlight definition by id. |hlID()| +/// +/// @deprecated use |nvim_get_hl()| instead +/// +/// @param hl_id Highlight id as returned by |hlID()| +/// @param rgb Export RGB colors +/// @param[out] err Error details, if any +/// @return Highlight definition map +/// @see nvim_get_hl_by_name +Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Arena *arena, Error *err) + FUNC_API_SINCE(3) + FUNC_API_DEPRECATED_SINCE(9) +{ + Dictionary dic = ARRAY_DICT_INIT; + VALIDATE_INT((syn_get_final_id((int)hl_id) != 0), "highlight id", hl_id, { + return dic; + }); + int attrcode = syn_id2attr((int)hl_id); + return hl_get_attr_by_id(attrcode, rgb, arena, err); +} + +/// Gets a highlight definition by name. +/// +/// @deprecated use |nvim_get_hl()| instead +/// +/// @param name Highlight group name +/// @param rgb Export RGB colors +/// @param[out] err Error details, if any +/// @return Highlight definition map +/// @see nvim_get_hl_by_id +Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Arena *arena, Error *err) + FUNC_API_SINCE(3) + FUNC_API_DEPRECATED_SINCE(9) +{ + Dictionary result = ARRAY_DICT_INIT; + int id = syn_name2id(name.data); + + VALIDATE_S((id != 0), "highlight name", name.data, { + return result; + }); + return nvim_get_hl_by_id(id, rgb, arena, err); +} + /// 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/keysets.lua b/src/nvim/api/keysets.lua index 2c7532bd27..b2b327d73e 100644 --- a/src/nvim/api/keysets.lua +++ b/src/nvim/api/keysets.lua @@ -145,6 +145,11 @@ return { "altfont"; "nocombine"; }}; + { 'get_highlight', { + "id"; + "name"; + "link"; + }}; -- Autocmds { 'clear_autocmds', { "buffer"; diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index a8f5d2e070..201989aee5 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -727,8 +727,8 @@ void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs, HlAttrs cte ADD_C(args, INTEGER_OBJ(id)); MAXSIZE_TEMP_DICT(rgb, HLATTRS_DICT_SIZE); MAXSIZE_TEMP_DICT(cterm, HLATTRS_DICT_SIZE); - hlattrs2dict(&rgb, rgb_attrs, true); - hlattrs2dict(&cterm, rgb_attrs, false); + hlattrs2dict(&rgb, rgb_attrs, true, false); + hlattrs2dict(&cterm, rgb_attrs, false, false); ADD_C(args, DICTIONARY_OBJ(rgb)); ADD_C(args, DICTIONARY_OBJ(cterm)); @@ -751,7 +751,7 @@ void remote_ui_highlight_set(UI *ui, int id) } data->hl_id = id; MAXSIZE_TEMP_DICT(dict, HLATTRS_DICT_SIZE); - hlattrs2dict(&dict, syn_attr2entry(id), ui->rgb); + hlattrs2dict(&dict, syn_attr2entry(id), ui->rgb, false); ADD_C(args, DICTIONARY_OBJ(dict)); push_call(ui, "highlight_set", args); } @@ -950,7 +950,7 @@ static Array translate_contents(UI *ui, Array contents, Arena *arena) int attr = (int)item.items[0].data.integer; if (attr) { Dictionary rgb_attrs = arena_dict(arena, HLATTRS_DICT_SIZE); - hlattrs2dict(&rgb_attrs, syn_attr2entry(attr), ui->rgb); + hlattrs2dict(&rgb_attrs, syn_attr2entry(attr), ui->rgb, false); ADD(new_item, DICTIONARY_OBJ(rgb_attrs)); } else { ADD(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 4689e6b5bf..ca5dd97020 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -74,42 +74,6 @@ # include "api/vim.c.generated.h" #endif -/// Gets a highlight definition by name. -/// -/// @param name Highlight group name -/// @param rgb Export RGB colors -/// @param[out] err Error details, if any -/// @return Highlight definition map -/// @see nvim_get_hl_by_id -Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Arena *arena, Error *err) - FUNC_API_SINCE(3) -{ - Dictionary result = ARRAY_DICT_INIT; - int id = syn_name2id(name.data); - - VALIDATE_S((id != 0), "highlight name", name.data, { - return result; - }); - return nvim_get_hl_by_id(id, rgb, arena, err); -} - -/// Gets a highlight definition by id. |hlID()| -/// @param hl_id Highlight id as returned by |hlID()| -/// @param rgb Export RGB colors -/// @param[out] err Error details, if any -/// @return Highlight definition map -/// @see nvim_get_hl_by_name -Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Arena *arena, Error *err) - FUNC_API_SINCE(3) -{ - Dictionary dic = ARRAY_DICT_INIT; - VALIDATE_INT((syn_get_final_id((int)hl_id) != 0), "highlight id", hl_id, { - return dic; - }); - int attrcode = syn_id2attr((int)hl_id); - return hl_get_attr_by_id(attrcode, rgb, arena, err); -} - /// Gets a highlight group by name /// /// similar to |hlID()|, but allocates a new ID if not present. @@ -119,12 +83,22 @@ Integer nvim_get_hl_id_by_name(String name) return syn_check_group(name.data, name.size); } -Dictionary nvim__get_hl_defs(Integer ns_id, Arena *arena, Error *err) +/// Gets all or specific highlight groups in a namespace. +/// +/// @param ns_id Get highlight groups for namespace ns_id |nvim_get_namespaces()|. +/// Use 0 to get global highlight groups |:highlight|. +/// @param opts Options dict: +/// - name: (string) Get a highlight definition by name. +/// - id: (integer) Get a highlight definition by id. +/// - link: (boolean, default true) Show linked group name instead of effective definition |:hi-link|. +/// +/// @param[out] err Error details, if any. +/// @return Highlight groups as a map from group name to a highlight definition map as in |nvim_set_hl()|, +/// or only a single highlight definition map if requested by name or id. +Dictionary nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena *arena, Error *err) + FUNC_API_SINCE(11) { - if (ns_id == 0) { - return get_global_hl_defs(arena); - } - abort(); + return ns_get_hl_defs((NS)ns_id, opts, arena, err); } /// Sets a highlight group. -- cgit From 6d267ad30cf539f520b46e3c92939f7031ce116f Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 23 Mar 2023 12:44:05 +0100 Subject: fix(api): make nvim_get_hl return 'cterm' attrs properly --- src/nvim/api/ui.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 201989aee5..5dd858a6a9 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -727,8 +727,8 @@ void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs, HlAttrs cte ADD_C(args, INTEGER_OBJ(id)); MAXSIZE_TEMP_DICT(rgb, HLATTRS_DICT_SIZE); MAXSIZE_TEMP_DICT(cterm, HLATTRS_DICT_SIZE); - hlattrs2dict(&rgb, rgb_attrs, true, false); - hlattrs2dict(&cterm, rgb_attrs, false, false); + hlattrs2dict(&rgb, NULL, rgb_attrs, true, false); + hlattrs2dict(&cterm, NULL, rgb_attrs, false, false); ADD_C(args, DICTIONARY_OBJ(rgb)); ADD_C(args, DICTIONARY_OBJ(cterm)); @@ -751,7 +751,7 @@ void remote_ui_highlight_set(UI *ui, int id) } data->hl_id = id; MAXSIZE_TEMP_DICT(dict, HLATTRS_DICT_SIZE); - hlattrs2dict(&dict, syn_attr2entry(id), ui->rgb, false); + hlattrs2dict(&dict, NULL, syn_attr2entry(id), ui->rgb, false); ADD_C(args, DICTIONARY_OBJ(dict)); push_call(ui, "highlight_set", args); } @@ -950,7 +950,7 @@ static Array translate_contents(UI *ui, Array contents, Arena *arena) int attr = (int)item.items[0].data.integer; if (attr) { Dictionary rgb_attrs = arena_dict(arena, HLATTRS_DICT_SIZE); - hlattrs2dict(&rgb_attrs, syn_attr2entry(attr), ui->rgb, false); + hlattrs2dict(&rgb_attrs, NULL, syn_attr2entry(attr), ui->rgb, false); ADD(new_item, DICTIONARY_OBJ(rgb_attrs)); } else { ADD(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); -- cgit From fe9cbcb3a5c82932ecfb8f49d07e98a1fc2b31e5 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sat, 25 Mar 2023 18:58:48 +0200 Subject: feat(api): nvim_exec2(), deprecate nvim_exec() #19032 Problem: The signature of nvim_exec() is not extensible per ":help api-contract". Solution: Introduce nvim_exec2() and deprecate nvim_exec(). --- src/nvim/api/command.c | 2 +- src/nvim/api/deprecated.c | 17 +++++++++++++++-- src/nvim/api/keysets.lua | 3 +++ src/nvim/api/vimscript.c | 36 ++++++++++++++++++++++++++++-------- 4 files changed, 47 insertions(+), 11 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 1455f28050..26ee9205b2 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -307,7 +307,7 @@ end: /// /// On execution error: fails with VimL error, updates v:errmsg. /// -/// @see |nvim_exec()| +/// @see |nvim_exec2()| /// @see |nvim_command()| /// /// @param cmd Command to execute. Must be a Dictionary that can contain the same values as diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index b1e2e6811e..6a12cfe2da 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -27,13 +27,26 @@ # include "api/deprecated.c.generated.h" #endif +/// @deprecated Use nvim_exec2() instead. +/// @see nvim_exec2 +String nvim_exec(uint64_t channel_id, String src, Boolean output, Error *err) + FUNC_API_SINCE(7) + FUNC_API_DEPRECATED_SINCE(11) +{ + Dict(exec_opts) opts = { 0 }; + opts.output = BOOLEAN_OBJ(output); + return exec_impl(channel_id, src, &opts, err); +} + /// @deprecated -/// @see nvim_exec +/// @see nvim_exec2 String nvim_command_output(uint64_t channel_id, String command, Error *err) FUNC_API_SINCE(1) FUNC_API_DEPRECATED_SINCE(7) { - return nvim_exec(channel_id, command, true, err); + Dict(exec_opts) opts = { 0 }; + opts.output = BOOLEAN_OBJ(true); + return exec_impl(channel_id, command, &opts, err); } /// @deprecated Use nvim_exec_lua() instead. diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua index b2b327d73e..ce29001787 100644 --- a/src/nvim/api/keysets.lua +++ b/src/nvim/api/keysets.lua @@ -232,4 +232,7 @@ return { { 'echo_opts', { "verbose"; }}; + { 'exec_opts', { + "output"; + }}; } diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 32dcbdec3f..2438a5cf1d 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -45,13 +45,33 @@ /// @see |nvim_cmd()| /// /// @param src Vimscript code -/// @param output Capture and return all (non-error, non-shell |:!|) output +/// @param opts Optional parameters. +/// - output: (boolean, default false) Whether to capture and return +/// all (non-error, non-shell |:!|) output. /// @param[out] err Error details (Vim error), if any -/// @return Output (non-error, non-shell |:!|) if `output` is true, -/// else empty string. -String nvim_exec(uint64_t channel_id, String src, Boolean output, Error *err) - FUNC_API_SINCE(7) +/// @return Dictionary containing information about execution, with these keys: +/// - output: (string|nil) Output if `opts.output` is true. +Dictionary nvim_exec2(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *err) + FUNC_API_SINCE(11) { + Dictionary result = ARRAY_DICT_INIT; + + String output = exec_impl(channel_id, src, opts, err); + if (ERROR_SET(err)) { + return result; + } + + if (HAS_KEY(opts->output) && api_object_to_bool(opts->output, "opts.output", false, err)) { + PUT(result, "output", STRING_OBJ(output)); + } + + return result; +} + +String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *err) +{ + Boolean output = api_object_to_bool(opts->output, "opts.output", false, err); + const int save_msg_silent = msg_silent; garray_T *const save_capture_ga = capture_ga; const int save_msg_col = msg_col; @@ -69,7 +89,7 @@ String nvim_exec(uint64_t channel_id, String src, Boolean output, Error *err) const sctx_T save_current_sctx = api_set_sctx(channel_id); - do_source_str(src.data, "nvim_exec()"); + do_source_str(src.data, "nvim_exec2()"); if (output) { capture_ga = save_capture_ga; msg_silent = save_msg_silent; @@ -108,8 +128,8 @@ theend: /// /// On execution error: fails with VimL error, updates v:errmsg. /// -/// Prefer using |nvim_cmd()| or |nvim_exec()| over this. To evaluate multiple lines of Vim script -/// or an Ex command directly, use |nvim_exec()|. To construct an Ex command using a structured +/// Prefer using |nvim_cmd()| or |nvim_exec2()| over this. To evaluate multiple lines of Vim script +/// or an Ex command directly, use |nvim_exec2()|. To construct an Ex command using a structured /// format and then execute it, use |nvim_cmd()|. To modify an Ex command before evaluating it, use /// |nvim_parse_cmd()| in conjunction with |nvim_cmd()|. /// -- cgit From b7748662ed5b06c12a74560690b728fdf770666f Mon Sep 17 00:00:00 2001 From: Michal Liszcz Date: Wed, 29 Mar 2023 09:59:01 +0200 Subject: fix(api): Use local LastSet structure in nvim_get_option_info (#22741) fix(api): use local LastSet structure in nvim_get_option_info * nvim_get_option_info is deprecated. It is always using the global LastSet information as reported in #15232. * nvim_get_option_info2 is added. The new function additionally accepts an 'opts' table {scope, buf, win} allowing to specify the option scope and query local options from another buffer or window. --- src/nvim/api/deprecated.c | 14 ++++++++++++++ src/nvim/api/options.c | 33 +++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 6 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 6a12cfe2da..5937b2f635 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -20,6 +20,7 @@ #include "nvim/highlight_group.h" #include "nvim/lua/executor.h" #include "nvim/memory.h" +#include "nvim/option.h" #include "nvim/pos.h" #include "nvim/types.h" @@ -508,3 +509,16 @@ static int64_t convert_index(int64_t index) { return index < 0 ? index - 1 : index; } + +/// Gets the option information for one option +/// +/// @deprecated Use @ref nvim_get_option_info2 instead. +/// +/// @param name Option name +/// @param[out] err Error details, if any +/// @return Option Information +Dictionary nvim_get_option_info(String name, Error *err) + FUNC_API_SINCE(7) +{ + return get_vimoption(name, OPT_GLOBAL, curbuf, curwin, err); +} diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 7a453c01b4..31a2fb3b80 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -283,7 +283,7 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict( /// Gets the option information for all options. /// /// The dictionary has the full option names as keys and option metadata -/// dictionaries as detailed at |nvim_get_option_info()|. +/// dictionaries as detailed at |nvim_get_option_info2()|. /// /// @return dictionary of all options Dictionary nvim_get_all_options_info(Error *err) @@ -292,7 +292,7 @@ Dictionary nvim_get_all_options_info(Error *err) return get_all_vimoptions(); } -/// Gets the option information for one option +/// Gets the option information for one option from arbitrary buffer or window /// /// Resulting dictionary has keys: /// - name: Name of the option (like 'filetype') @@ -311,15 +311,36 @@ Dictionary nvim_get_all_options_info(Error *err) /// - commalist: List of comma separated values /// - flaglist: List of single char flags /// +/// When {scope} is not provided, the last set information applies to the local +/// value in the current buffer or window if it is available, otherwise the +/// global value information is returned. This behavior can be disabled by +/// explicitly specifying {scope} in the {opts} table. /// -/// @param name Option name +/// @param name Option name +/// @param opts Optional parameters +/// - scope: One of "global" or "local". Analogous to +/// |:setglobal| and |:setlocal|, respectively. +/// - win: |window-ID|. Used for getting window local options. +/// - buf: Buffer number. Used for getting buffer local options. +/// Implies {scope} is "local". /// @param[out] err Error details, if any /// @return Option Information -Dictionary nvim_get_option_info(String name, Error *err) - FUNC_API_SINCE(7) +Dictionary nvim_get_option_info2(String name, Dict(option) *opts, Error *err) + FUNC_API_SINCE(11) { - return get_vimoption(name, err); + int scope = 0; + int opt_type = SREQ_GLOBAL; + void *from = NULL; + if (!validate_option_value_args(opts, &scope, &opt_type, &from, NULL, err)) { + return (Dictionary)ARRAY_DICT_INIT; + } + + buf_T *buf = (opt_type == SREQ_BUF) ? (buf_T *)from : curbuf; + win_T *win = (opt_type == SREQ_WIN) ? (win_T *)from : curwin; + + return get_vimoption(name, scope, buf, win, err); } + /// Sets the global value of an option. /// /// @param channel_id -- cgit From 8b7fb668e440f7793564b764bc9a691e3f45382a Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 29 Mar 2023 19:54:12 +0100 Subject: fix(filetype): avoid recursive FileType autocmds (#22813) --- src/nvim/api/options.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 31a2fb3b80..baeb3e88fb 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -111,15 +111,15 @@ static buf_T *do_ft_buf(char *filetype, aco_save_T *aco, Error *err) // Set curwin/curbuf to buf and save a few things. aucmd_prepbuf(aco, ftbuf); - set_option_value("bufhidden", 0L, "hide", OPT_LOCAL); - set_option_value("buftype", 0L, "nofile", OPT_LOCAL); - set_option_value("swapfile", 0L, NULL, OPT_LOCAL); - set_option_value("modeline", 0L, NULL, OPT_LOCAL); // 'nomodeline' - - ftbuf->b_p_ft = xstrdup(filetype); TRY_WRAP(err, { - apply_autocmds(EVENT_FILETYPE, ftbuf->b_p_ft, ftbuf->b_fname, true, ftbuf); + set_option_value("bufhidden", 0L, "hide", OPT_LOCAL); + set_option_value("buftype", 0L, "nofile", OPT_LOCAL); + set_option_value("swapfile", 0L, NULL, OPT_LOCAL); + set_option_value("modeline", 0L, NULL, OPT_LOCAL); // 'nomodeline' + + ftbuf->b_p_ft = xstrdup(filetype); + do_filetype_autocmd(ftbuf, false); }); return ftbuf; -- cgit From b34097fe6d2ea5c84bcec65a834a430d9f58eb64 Mon Sep 17 00:00:00 2001 From: "Sindre T. Strøm" Date: Fri, 31 Mar 2023 12:52:53 +0200 Subject: fix(api): return both link and attributes with nvim_get_hl (#22824) Problem: No way to get the actual highlight attributes for a linked group through |nvim_get_hl()| (not the attributes from the link target). Solution: Return the actual attributes as well as the link target name. --- src/nvim/api/vim.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index ca5dd97020..9812313b7b 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -95,6 +95,9 @@ Integer nvim_get_hl_id_by_name(String name) /// @param[out] err Error details, if any. /// @return Highlight groups as a map from group name to a highlight definition map as in |nvim_set_hl()|, /// or only a single highlight definition map if requested by name or id. +/// +/// @note When the `link` attribute is defined in the highlight definition +/// map, other attributes will not be taking effect (see |:hi-link|). Dictionary nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena *arena, Error *err) FUNC_API_SINCE(11) { @@ -113,6 +116,10 @@ Dictionary nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena *arena, E /// values of the Normal group. If the Normal group has not been defined, /// using these values results in an error. /// +/// +/// @note If `link` is used in combination with other attributes; only the +/// `link` will take effect (see |:hi-link|). +/// /// @param ns_id Namespace id for this highlight |nvim_create_namespace()|. /// Use 0 to set a highlight group globally |:highlight|. /// Highlights from non-global namespaces are not active by default, use -- cgit From 2a10f64e254375e77e1c5a6aeae3cd65cd122afb Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Sat, 25 Mar 2023 02:24:24 +0100 Subject: feat(extmarks): extend nvim_buf_get_extmarks() Problem: Can not get all extmarks in a buffer. Properties are missing from the details array. Solution: Allow getting all extmarks in a buffer by supplying a -1 "ns_id". Add missing properties to the details array. --- src/nvim/api/extmark.c | 131 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 101 insertions(+), 30 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index adc2925b7e..4afbdfa487 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -105,7 +105,16 @@ bool ns_initialized(uint32_t ns) return ns < (uint32_t)next_namespace_id; } -static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict) +static Object hl_group_name(int hl_id, bool hl_name) +{ + if (hl_name) { + return STRING_OBJ(cstr_to_string(syn_id2name(hl_id))); + } else { + return INTEGER_OBJ(hl_id); + } +} + +static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict, bool hl_name) { Array rv = ARRAY_DICT_INIT; if (id) { @@ -117,6 +126,8 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict if (add_dict) { Dictionary dict = ARRAY_DICT_INIT; + PUT(dict, "ns_id", INTEGER_OBJ((Integer)extmark->ns_id)); + PUT(dict, "right_gravity", BOOLEAN_OBJ(extmark->right_gravity)); if (extmark->end_row >= 0) { @@ -127,8 +138,7 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict const 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)); + PUT(dict, "hl_group", hl_group_name(decor->hl_id, hl_name)); PUT(dict, "hl_eol", BOOLEAN_OBJ(decor->hl_eol)); } if (decor->hl_mode) { @@ -142,8 +152,7 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict 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(chunk, hl_group_name(vtc->hl_id, hl_name)); } ADD(chunks, ARRAY_OBJ(chunk)); } @@ -172,8 +181,7 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict VirtTextChunk *vtc = &vt->items[j]; 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(chunk, hl_group_name(vtc->hl_id, hl_name)); } ADD(chunks, ARRAY_OBJ(chunk)); } @@ -184,10 +192,44 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict PUT(dict, "virt_lines_leftcol", BOOLEAN_OBJ(virt_lines_leftcol)); } - if (decor->hl_id || kv_size(decor->virt_text) || decor->ui_watched) { + if (decor->sign_text) { + PUT(dict, "sign_text", STRING_OBJ(cstr_to_string(decor->sign_text))); + } + + // uncrustify:off + + struct { char *name; const int val; } hls[] = { + { "sign_hl_group" , decor->sign_hl_id }, + { "number_hl_group" , decor->number_hl_id }, + { "line_hl_group" , decor->line_hl_id }, + { "cursorline_hl_group", decor->cursorline_hl_id }, + { NULL, 0 }, + }; + + // uncrustify:on + + for (int j = 0; hls[j].name && hls[j].val; j++) { + if (hls[j].val) { + PUT(dict, hls[j].name, hl_group_name(hls[j].val, hl_name)); + } + } + + if (decor->sign_text + || decor->hl_id + || kv_size(decor->virt_text) + || decor->ui_watched) { PUT(dict, "priority", INTEGER_OBJ(decor->priority)); } + if (decor->conceal) { + String name = cstr_to_string((char *)&decor->conceal_char); + PUT(dict, "conceal", STRING_OBJ(name)); + } + + if (decor->spell != kNone) { + PUT(dict, "spell", BOOLEAN_OBJ(decor->spell == kTrue)); + } + if (dict.size) { ADD(rv, DICTIONARY_OBJ(dict)); } @@ -203,6 +245,7 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict /// @param id Extmark id /// @param opts Optional parameters. Keys: /// - details: Whether to include the details dict +/// - hl_name: Whether to include highlight group name instead of id, true if omitted /// @param[out] err Error details, if any /// @return 0-indexed (row, col) tuple or empty list () if extmark id was /// absent @@ -224,18 +267,19 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, }); bool details = false; + bool hl_name = true; for (size_t i = 0; i < opts.size; i++) { String k = opts.items[i].key; Object *v = &opts.items[i].value; if (strequal("details", k.data)) { - if (v->type == kObjectTypeBoolean) { - details = v->data.boolean; - } else if (v->type == kObjectTypeInteger) { - details = v->data.integer; - } else { - VALIDATE_EXP(false, "details", "Boolean or Integer", api_typename(v->type), { - return rv; - }); + details = api_object_to_bool(*v, "details", false, err); + if (ERROR_SET(err)) { + return rv; + } + } else if (strequal("hl_name", k.data)) { + hl_name = api_object_to_bool(*v, "hl_name", false, err); + if (ERROR_SET(err)) { + return rv; } } else { VALIDATE_S(false, "'opts' key", k.data, { @@ -248,7 +292,7 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, if (extmark.row < 0) { return rv; } - return extmark_to_array(&extmark, false, details); + return extmark_to_array(&extmark, false, details, hl_name); } /// Gets |extmarks| in "traversal order" from a |charwise| region defined by @@ -282,14 +326,16 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, /// /// /// @param buffer Buffer handle, or 0 for current buffer -/// @param ns_id Namespace id from |nvim_create_namespace()| +/// @param ns_id Namespace id from |nvim_create_namespace()| or -1 for all namespaces /// @param start Start of range: a 0-indexed (row, col) or valid extmark id /// (whose position defines the bound). |api-indexing| /// @param end End of range (inclusive): a 0-indexed (row, col) or valid /// extmark id (whose position defines the bound). |api-indexing| /// @param opts Optional parameters. Keys: /// - limit: Maximum number of marks to return -/// - details Whether to include the details dict +/// - details: Whether to include the details dict +/// - hl_name: Whether to include highlight group name instead of id, true if omitted +/// - type: Filter marks by type: "highlight", "sign", "virt_text" and "virt_lines" /// @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, @@ -303,12 +349,20 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e return rv; } - VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, { - return rv; - }); + bool all_ns; + if (ns_id == -1) { + all_ns = true; + } else { + VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, { + return rv; + }); + all_ns = false; + } Integer limit = -1; bool details = false; + bool hl_name = true; + ExtmarkType type = kExtmarkNone; for (size_t i = 0; i < opts.size; i++) { String k = opts.items[i].key; @@ -319,12 +373,29 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e }); limit = v->data.integer; } else if (strequal("details", k.data)) { - if (v->type == kObjectTypeBoolean) { - details = v->data.boolean; - } else if (v->type == kObjectTypeInteger) { - details = v->data.integer; + details = api_object_to_bool(*v, "details", false, err); + if (ERROR_SET(err)) { + return rv; + } + } else if (strequal("hl_name", k.data)) { + hl_name = api_object_to_bool(*v, "hl_name", false, err); + if (ERROR_SET(err)) { + return rv; + } + } else if (strequal("type", k.data)) { + VALIDATE_EXP(v->type == kObjectTypeString, "type", "String", api_typename(v->type), { + return rv; + }); + if (strequal(v->data.string.data, "sign")) { + type = kExtmarkSign; + } else if (strequal(v->data.string.data, "virt_text")) { + type = kExtmarkVirtText; + } else if (strequal(v->data.string.data, "virt_lines")) { + type = kExtmarkVirtLines; + } else if (strequal(v->data.string.data, "highlight")) { + type = kExtmarkHighlight; } else { - VALIDATE_EXP(false, "details", "Boolean or Integer", api_typename(v->type), { + VALIDATE_EXP(false, "type", "sign, virt_text, virt_lines or highlight", v->data.string.data, { return rv; }); } @@ -359,11 +430,11 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e reverse = true; } - ExtmarkInfoArray marks = extmark_get(buf, (uint32_t)ns_id, l_row, l_col, - u_row, u_col, (int64_t)limit, reverse); + ExtmarkInfoArray marks = extmark_get(buf, (uint32_t)ns_id, l_row, l_col, u_row, + u_col, (int64_t)limit, reverse, all_ns, type); for (size_t i = 0; i < kv_size(marks); i++) { - ADD(rv, ARRAY_OBJ(extmark_to_array(&kv_A(marks, i), true, (bool)details))); + ADD(rv, ARRAY_OBJ(extmark_to_array(&kv_A(marks, i), true, (bool)details, hl_name))); } kv_destroy(marks); -- cgit From 7c8c1550737b34fabb3e4cecbc6b6bf3581b2235 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 4 Apr 2023 08:59:11 +0800 Subject: fix(api): avoid double hit-enter prompt with nvim_err_writeln (#22879) --- src/nvim/api/vim.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 9812313b7b..343c3b6e40 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -737,7 +737,7 @@ error: void nvim_out_write(String str) FUNC_API_SINCE(1) { - write_msg(str, false); + write_msg(str, false, false); } /// Writes a message to the Vim error buffer. Does not append "\n", the @@ -747,7 +747,7 @@ void nvim_out_write(String str) void nvim_err_write(String str) FUNC_API_SINCE(1) { - write_msg(str, true); + write_msg(str, true, false); } /// Writes a message to the Vim error buffer. Appends "\n", so the buffer is @@ -758,8 +758,7 @@ void nvim_err_write(String str) void nvim_err_writeln(String str) FUNC_API_SINCE(1) { - nvim_err_write(str); - nvim_err_write((String) { .data = "\n", .size = 1 }); + write_msg(str, true, true); } /// Gets the current list of buffer handles @@ -1672,23 +1671,24 @@ theend: /// /// @param message Message to write /// @param to_err true: message is an error (uses `emsg` instead of `msg`) -static void write_msg(String message, bool to_err) +/// @param writeln Append a trailing newline +static void write_msg(String message, bool to_err, bool writeln) { static StringBuilder out_line_buf = KV_INITIAL_VALUE; static StringBuilder err_line_buf = KV_INITIAL_VALUE; -#define PUSH_CHAR(i, line_buf, msg) \ +#define PUSH_CHAR(c, line_buf, msg) \ if (kv_max(line_buf) == 0) { \ kv_resize(line_buf, LINE_BUFFER_MIN_SIZE); \ } \ - if (message.data[i] == NL) { \ + if (c == NL) { \ kv_push(line_buf, NUL); \ msg(line_buf.items); \ kv_drop(line_buf, kv_size(line_buf)); \ kv_resize(line_buf, LINE_BUFFER_MIN_SIZE); \ - continue; \ - } \ - kv_push(line_buf, message.data[i]); + } else { \ + kv_push(line_buf, c); \ + } no_wait_return++; for (uint32_t i = 0; i < message.size; i++) { @@ -1696,9 +1696,16 @@ static void write_msg(String message, bool to_err) break; } if (to_err) { - PUSH_CHAR(i, err_line_buf, emsg); + PUSH_CHAR(message.data[i], err_line_buf, emsg); + } else { + PUSH_CHAR(message.data[i], out_line_buf, msg); + } + } + if (writeln) { + if (to_err) { + PUSH_CHAR(NL, err_line_buf, emsg); } else { - PUSH_CHAR(i, out_line_buf, msg); + PUSH_CHAR(NL, out_line_buf, msg); } } no_wait_return--; -- cgit From f0ac91c58b42ed4f38dea7352d89fd39a88142f4 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Sat, 1 Apr 2023 14:58:52 +0200 Subject: feat(api): evaluate 'statuscolumn' with nvim_eval_statusline() --- src/nvim/api/keysets.lua | 1 + src/nvim/api/private/helpers.c | 4 ++- src/nvim/api/vim.c | 59 +++++++++++++++++++++++++++++++++++------- 3 files changed, 54 insertions(+), 10 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua index ce29001787..26e87bccec 100644 --- a/src/nvim/api/keysets.lua +++ b/src/nvim/api/keysets.lua @@ -97,6 +97,7 @@ return { "highlights"; "use_winbar"; "use_tabline"; + "use_statuscol"; }}; { 'option', { "scope"; diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index c996e19eb9..02060a8950 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -959,12 +959,14 @@ bool set_mark(buf_T *buf, String name, Integer line, Integer col, Error *err) } /// Get default statusline highlight for window -const char *get_default_stl_hl(win_T *wp, bool use_winbar) +const char *get_default_stl_hl(win_T *wp, bool use_winbar, int stc_hl_id) { if (wp == NULL) { return "TabLineFill"; } else if (use_winbar) { return (wp == curwin) ? "WinBar" : "WinBarNC"; + } else if (stc_hl_id > 0) { + return syn_id2name(stc_hl_id); } else { return (wp == curwin) ? "StatusLine" : "StatusLineNC"; } diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 343c3b6e40..383953a676 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -25,6 +25,7 @@ #include "nvim/buffer.h" #include "nvim/channel.h" #include "nvim/context.h" +#include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" @@ -59,6 +60,7 @@ #include "nvim/popupmenu.h" #include "nvim/pos.h" #include "nvim/runtime.h" +#include "nvim/sign.h" #include "nvim/state.h" #include "nvim/statusline.h" #include "nvim/strings.h" @@ -2054,6 +2056,7 @@ Array nvim_get_mark(String name, Dictionary opts, Error *err) /// - use_winbar: (boolean) Evaluate winbar instead of statusline. /// - use_tabline: (boolean) Evaluate tabline instead of statusline. When true, {winid} /// is ignored. Mutually exclusive with {use_winbar}. +/// - use_statuscol: (boolean) Evaluate statuscolumn instead of statusline. /// /// @param[out] err Error details, if any. /// @return Dictionary containing statusline information, with these keys: @@ -2071,9 +2074,11 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * int maxwidth; int fillchar = 0; + int use_bools = 0; Window window = 0; bool use_winbar = false; bool use_tabline = false; + bool use_statuscol = false; bool highlights = false; if (str.size < 2 || memcmp(str.data, "%!", 2) != 0) { @@ -2111,23 +2116,34 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * } if (HAS_KEY(opts->use_winbar)) { use_winbar = api_object_to_bool(opts->use_winbar, "use_winbar", false, err); - + use_bools++; if (ERROR_SET(err)) { return result; } } if (HAS_KEY(opts->use_tabline)) { use_tabline = api_object_to_bool(opts->use_tabline, "use_tabline", false, err); - + use_bools++; if (ERROR_SET(err)) { return result; } } - VALIDATE(!(use_winbar && use_tabline), "%s", "Cannot use both 'use_winbar' and 'use_tabline'", { + if (HAS_KEY(opts->use_statuscol)) { + use_statuscol = api_object_to_bool(opts->use_statuscol, "use_statuscol", false, err); + use_bools++; + if (ERROR_SET(err)) { + return result; + } + } + VALIDATE(use_bools <= 1, "%s", + "Can only use one of 'use_winbar', 'use_tabline' and 'use_statuscol'", { return result; }); win_T *wp, *ewp; + int stc_hl_id = 0; + statuscol_T statuscol = { 0 }; + SignTextAttrs sattrs[SIGN_SHOW_MAX] = { 0 }; if (use_tabline) { wp = NULL; @@ -2149,6 +2165,31 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * fillchar = fillchar_status(&attr, wp); } } + if (use_statuscol) { + HlPriId line = { 0 }; + HlPriId cul = { 0 }; + HlPriId num = { 0 }; + linenr_T lnum = (linenr_T)get_vim_var_nr(VV_LNUM); + int num_signs = buf_get_signattrs(wp->w_buffer, lnum, sattrs, &num, &line, &cul); + decor_redraw_signs(wp->w_buffer, lnum - 1, &num_signs, sattrs, &num, &line, &cul); + + statuscol.sattrs = sattrs; + statuscol.foldinfo = fold_info(wp, lnum); + statuscol.use_cul = wp->w_p_cul && lnum == wp->w_cursorline + && (wp->w_p_culopt_flags & CULOPT_NBR); + statuscol.sign_cul_id = statuscol.use_cul ? cul.hl_id : 0; + if (num.hl_id) { + stc_hl_id = num.hl_id; + } else if (statuscol.use_cul) { + stc_hl_id = HLF_CLN + 1; + } else if (wp->w_p_rnu) { + stc_hl_id = (lnum < wp->w_cursor.lnum ? HLF_LNA : HLF_LNB) + 1; + } else { + stc_hl_id = HLF_N + 1; + } + set_vim_var_nr(VV_RELNUM, labs(get_cursor_rel_lnum(wp, lnum))); + set_vim_var_nr(VV_VIRTNUM, 0); + } } if (HAS_KEY(opts->maxwidth)) { @@ -2158,12 +2199,12 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * maxwidth = (int)opts->maxwidth.data.integer; } else { - maxwidth = (use_tabline || (!use_winbar && global_stl_height() > 0)) ? Columns : wp->w_width; + maxwidth = use_statuscol ? win_col_off(wp) + : (use_tabline || (!use_winbar && global_stl_height() > 0)) ? Columns : wp->w_width; } char buf[MAXPATHL]; stl_hlrec_t *hltab; - stl_hlrec_t **hltab_ptr = highlights ? &hltab : NULL; // Temporarily reset 'cursorbind' to prevent side effects from moving the cursor away and back. int p_crb_save = ewp->w_p_crb; @@ -2177,9 +2218,9 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * 0, fillchar, maxwidth, - hltab_ptr, + highlights ? &hltab : NULL, NULL, - NULL); + use_statuscol ? &statuscol : NULL); PUT(result, "width", INTEGER_OBJ(width)); @@ -2195,7 +2236,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * // add the default highlight at the beginning of the highlight list if (hltab->start == NULL || (hltab->start - buf) != 0) { Dictionary hl_info = ARRAY_DICT_INIT; - grpname = get_default_stl_hl(wp, use_winbar); + grpname = get_default_stl_hl(wp, use_winbar, stc_hl_id); PUT(hl_info, "start", INTEGER_OBJ(0)); PUT(hl_info, "group", CSTR_TO_OBJ(grpname)); @@ -2209,7 +2250,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * PUT(hl_info, "start", INTEGER_OBJ(sp->start - buf)); if (sp->userhl == 0) { - grpname = get_default_stl_hl(wp, use_winbar); + grpname = get_default_stl_hl(wp, use_winbar, stc_hl_id); } else if (sp->userhl < 0) { grpname = syn_id2name(-sp->userhl); } else { -- cgit From 34ac75b32927328a0c691c5bda987c0fdb5ce9eb Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 5 Apr 2023 17:19:53 +0100 Subject: refactor: rename local API alias from a to api Problem: Codebase inconsistently binds vim.api onto a or api. Solution: Use api everywhere. a as an identifier is too short to have at the module level. --- src/nvim/api/extmark.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 4afbdfa487..fc17b9d0cc 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -311,17 +311,17 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, /// /// Example: ///
lua
-///   local a   = vim.api
-///   local pos = a.nvim_win_get_cursor(0)
-///   local ns  = a.nvim_create_namespace('my-plugin')
+///   local api = vim.api
+///   local pos = api.nvim_win_get_cursor(0)
+///   local ns  = api.nvim_create_namespace('my-plugin')
 ///   -- Create new extmark at line 1, column 1.
-///   local m1  = a.nvim_buf_set_extmark(0, ns, 0, 0, {})
+///   local m1  = api.nvim_buf_set_extmark(0, ns, 0, 0, {})
 ///   -- Create new extmark at line 3, column 1.
-///   local m2  = a.nvim_buf_set_extmark(0, ns, 2, 0, {})
+///   local m2  = api.nvim_buf_set_extmark(0, ns, 2, 0, {})
 ///   -- Get extmarks only from line 3.
-///   local ms  = a.nvim_buf_get_extmarks(0, ns, {2,0}, {2,0}, {})
+///   local ms  = api.nvim_buf_get_extmarks(0, ns, {2,0}, {2,0}, {})
 ///   -- Get all marks in this buffer + namespace.
-///   local all = a.nvim_buf_get_extmarks(0, ns, 0, -1, {})
+///   local all = api.nvim_buf_get_extmarks(0, ns, 0, -1, {})
 ///   print(vim.inspect(ms))
 /// 
/// -- cgit From 371823d407d7d7519735131bcad4670c62a731a7 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Wed, 5 Apr 2023 21:13:53 +0200 Subject: refactor: make error message definitions const message.c functions now take const char * as a format. Error message definitions can be made const. --- src/nvim/api/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index baeb3e88fb..3e7f7e8781 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -559,7 +559,7 @@ static getoption_T access_option_value(char *key, long *numval, char **stringval if (get) { return get_option_value(key, numval, stringval, NULL, opt_flags); } else { - char *errmsg; + const char *errmsg; if ((errmsg = set_option_value(key, *numval, *stringval, opt_flags))) { if (try_end(err)) { return 0; -- cgit From 0f42aa1f2a860ce6d72a825b397fe09c875613b5 Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 6 Apr 2023 10:03:37 +0200 Subject: fix(highlight): use winhl=Foo:Bar even when Bar is empty fixes #22906 --- src/nvim/api/options.c | 4 ++-- src/nvim/api/private/validate.h | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index baeb3e88fb..3e6466626f 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -53,7 +53,7 @@ static int validate_option_value_args(Dict(option) *opts, int *scope, int *opt_t } if (HAS_KEY(opts->win)) { - VALIDATE_T("win", kObjectTypeInteger, opts->win.type, { + VALIDATE_T_HANDLE("win", kObjectTypeWindow, opts->win.type, { return FAIL; }); @@ -65,7 +65,7 @@ static int validate_option_value_args(Dict(option) *opts, int *scope, int *opt_t } if (HAS_KEY(opts->buf)) { - VALIDATE_T("buf", kObjectTypeInteger, opts->buf.type, { + VALIDATE_T_HANDLE("buf", kObjectTypeBuffer, opts->buf.type, { return FAIL; }); diff --git a/src/nvim/api/private/validate.h b/src/nvim/api/private/validate.h index 91a92c2762..a3e77ea838 100644 --- a/src/nvim/api/private/validate.h +++ b/src/nvim/api/private/validate.h @@ -67,6 +67,15 @@ } \ } while (0) +/// Checks that actual_t is either the correct handle type or a type erased handle (integer) +#define VALIDATE_T_HANDLE(name, expected_t, actual_t, code) \ + do { \ + if (expected_t != actual_t && kObjectTypeInteger != actual_t) { \ + api_err_exp(err, name, api_typename(expected_t), api_typename(actual_t)); \ + code; \ + } \ + } while (0) + #define VALIDATE_RANGE(cond, name, code) \ do { \ if (!(cond)) { \ -- cgit From 7190dba017e3aac0409c73ff1c954d18858cb3c9 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Thu, 6 Apr 2023 22:39:50 +0200 Subject: refactor: remove use of reserved c++ keywords libnvim couldn't be easily used in C++ due to the use of reserved keywords. Additionally, add explicit casts to *alloc function calls used in inline functions, as C++ doesn't allow implicit casts from void pointers. --- src/nvim/api/command.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 26ee9205b2..7c01dc0e54 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -1015,7 +1015,7 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict( uint32_t argt = 0; int64_t def = -1; cmd_addr_T addr_type_arg = ADDR_NONE; - int compl = EXPAND_NOTHING; + int context = EXPAND_NOTHING; char *compl_arg = NULL; const char *rep = NULL; LuaRef luaref = LUA_NOREF; @@ -1161,11 +1161,11 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict( } if (opts->complete.type == kObjectTypeLuaRef) { - compl = EXPAND_USER_LUA; + context = EXPAND_USER_LUA; compl_luaref = api_new_luaref(opts->complete.data.luaref); } else if (opts->complete.type == kObjectTypeString) { VALIDATE_S(OK == parse_compl_arg(opts->complete.data.string.data, - (int)opts->complete.data.string.size, &compl, &argt, + (int)opts->complete.data.string.size, &context, &argt, &compl_arg), "complete", opts->complete.data.string.data, { goto err; @@ -1204,8 +1204,8 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict( } WITH_SCRIPT_CONTEXT(channel_id, { - if (uc_add_command(name.data, name.size, rep, argt, def, flags, compl, compl_arg, compl_luaref, - preview_luaref, addr_type_arg, luaref, force) != OK) { + if (uc_add_command(name.data, name.size, rep, argt, def, flags, context, compl_arg, + compl_luaref, preview_luaref, addr_type_arg, luaref, force) != OK) { api_set_error(err, kErrorTypeException, "Failed to create user command"); // Do not goto err, since uc_add_command now owns luaref, compl_luaref, and compl_arg } -- cgit From 25dfed6e0148771cdb659df8c616df3860583c47 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Thu, 6 Apr 2023 03:33:57 +0200 Subject: feat(api): set statuscolumn line number in nvim_eval_statusline() Having the user set `v:lnum` before calling `nvim_eval_statusline()` is unnecesarily fragile. Redraws inbetween setting `v:lnum` and the `nvim_eval_statusline()` call will overwrite `v:lnum`. --- src/nvim/api/keysets.lua | 2 +- src/nvim/api/vim.c | 74 +++++++++++++++++++++++++++--------------------- 2 files changed, 43 insertions(+), 33 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua index 26e87bccec..01f5a8b860 100644 --- a/src/nvim/api/keysets.lua +++ b/src/nvim/api/keysets.lua @@ -97,7 +97,7 @@ return { "highlights"; "use_winbar"; "use_tabline"; - "use_statuscol"; + "use_statuscol_lnum"; }}; { 'option', { "scope"; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 383953a676..b62521290d 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2056,7 +2056,7 @@ Array nvim_get_mark(String name, Dictionary opts, Error *err) /// - use_winbar: (boolean) Evaluate winbar instead of statusline. /// - use_tabline: (boolean) Evaluate tabline instead of statusline. When true, {winid} /// is ignored. Mutually exclusive with {use_winbar}. -/// - use_statuscol: (boolean) Evaluate statuscolumn instead of statusline. +/// - use_statuscol_lnum: (number) Evaluate statuscolumn for this line number instead of statusline. /// /// @param[out] err Error details, if any. /// @return Dictionary containing statusline information, with these keys: @@ -2075,10 +2075,10 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * int maxwidth; int fillchar = 0; int use_bools = 0; + int statuscol_lnum = 0; Window window = 0; bool use_winbar = false; bool use_tabline = false; - bool use_statuscol = false; bool highlights = false; if (str.size < 2 || memcmp(str.data, "%!", 2) != 0) { @@ -2116,47 +2116,48 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * } if (HAS_KEY(opts->use_winbar)) { use_winbar = api_object_to_bool(opts->use_winbar, "use_winbar", false, err); - use_bools++; if (ERROR_SET(err)) { return result; } + use_bools++; } if (HAS_KEY(opts->use_tabline)) { use_tabline = api_object_to_bool(opts->use_tabline, "use_tabline", false, err); - use_bools++; if (ERROR_SET(err)) { return result; } - } - if (HAS_KEY(opts->use_statuscol)) { - use_statuscol = api_object_to_bool(opts->use_statuscol, "use_statuscol", false, err); use_bools++; - if (ERROR_SET(err)) { + } + + win_T *wp = use_tabline ? curwin : find_window_by_handle(window, err); + if (wp == NULL) { + api_set_error(err, kErrorTypeException, "unknown winid %d", window); + return result; + } + + if (HAS_KEY(opts->use_statuscol_lnum)) { + VALIDATE_T("use_statuscol_lnum", kObjectTypeInteger, opts->use_statuscol_lnum.type, { return result; - } + }); + statuscol_lnum = (int)opts->use_statuscol_lnum.data.integer; + VALIDATE_RANGE(statuscol_lnum > 0 && statuscol_lnum <= wp->w_buffer->b_ml.ml_line_count, + "use_statuscol_lnum", { + return result; + }); + use_bools++; } VALIDATE(use_bools <= 1, "%s", - "Can only use one of 'use_winbar', 'use_tabline' and 'use_statuscol'", { + "Can only use one of 'use_winbar', 'use_tabline' and 'use_statuscol_lnum'", { return result; }); - win_T *wp, *ewp; int stc_hl_id = 0; statuscol_T statuscol = { 0 }; SignTextAttrs sattrs[SIGN_SHOW_MAX] = { 0 }; if (use_tabline) { - wp = NULL; - ewp = curwin; fillchar = ' '; } else { - wp = find_window_by_handle(window, err); - if (wp == NULL) { - api_set_error(err, kErrorTypeException, "unknown winid %d", window); - return result; - } - ewp = wp; - if (fillchar == 0) { if (use_winbar) { fillchar = wp->w_p_fcs_chars.wbr; @@ -2165,18 +2166,25 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * fillchar = fillchar_status(&attr, wp); } } - if (use_statuscol) { + if (statuscol_lnum) { HlPriId line = { 0 }; HlPriId cul = { 0 }; HlPriId num = { 0 }; - linenr_T lnum = (linenr_T)get_vim_var_nr(VV_LNUM); + linenr_T lnum = statuscol_lnum; int num_signs = buf_get_signattrs(wp->w_buffer, lnum, sattrs, &num, &line, &cul); decor_redraw_signs(wp->w_buffer, lnum - 1, &num_signs, sattrs, &num, &line, &cul); statuscol.sattrs = sattrs; statuscol.foldinfo = fold_info(wp, lnum); - statuscol.use_cul = wp->w_p_cul && lnum == wp->w_cursorline - && (wp->w_p_culopt_flags & CULOPT_NBR); + wp->w_cursorline = win_cursorline_standout(wp) ? wp->w_cursor.lnum : 0; + + if (wp->w_p_cul) { + if (statuscol.foldinfo.fi_level > 0 && statuscol.foldinfo.fi_lines > 0) { + wp->w_cursorline = statuscol.foldinfo.fi_lnum; + } + statuscol.use_cul = lnum == wp->w_cursorline && (wp->w_p_culopt_flags & CULOPT_NBR); + } + statuscol.sign_cul_id = statuscol.use_cul ? cul.hl_id : 0; if (num.hl_id) { stc_hl_id = num.hl_id; @@ -2187,6 +2195,8 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * } else { stc_hl_id = HLF_N + 1; } + + set_vim_var_nr(VV_LNUM, lnum); set_vim_var_nr(VV_RELNUM, labs(get_cursor_rel_lnum(wp, lnum))); set_vim_var_nr(VV_VIRTNUM, 0); } @@ -2199,7 +2209,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * maxwidth = (int)opts->maxwidth.data.integer; } else { - maxwidth = use_statuscol ? win_col_off(wp) + maxwidth = statuscol_lnum ? win_col_off(wp) : (use_tabline || (!use_winbar && global_stl_height() > 0)) ? Columns : wp->w_width; } @@ -2207,10 +2217,10 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * stl_hlrec_t *hltab; // Temporarily reset 'cursorbind' to prevent side effects from moving the cursor away and back. - int p_crb_save = ewp->w_p_crb; - ewp->w_p_crb = false; + int p_crb_save = wp->w_p_crb; + wp->w_p_crb = false; - int width = build_stl_str_hl(ewp, + int width = build_stl_str_hl(wp, buf, sizeof(buf), str.data, @@ -2220,12 +2230,12 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * maxwidth, highlights ? &hltab : NULL, NULL, - use_statuscol ? &statuscol : NULL); + statuscol_lnum ? &statuscol : NULL); PUT(result, "width", INTEGER_OBJ(width)); // Restore original value of 'cursorbind' - ewp->w_p_crb = p_crb_save; + wp->w_p_crb = p_crb_save; if (highlights) { Array hl_values = ARRAY_DICT_INIT; @@ -2236,7 +2246,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * // add the default highlight at the beginning of the highlight list if (hltab->start == NULL || (hltab->start - buf) != 0) { Dictionary hl_info = ARRAY_DICT_INIT; - grpname = get_default_stl_hl(wp, use_winbar, stc_hl_id); + grpname = get_default_stl_hl(use_tabline ? NULL : wp, use_winbar, stc_hl_id); PUT(hl_info, "start", INTEGER_OBJ(0)); PUT(hl_info, "group", CSTR_TO_OBJ(grpname)); @@ -2250,7 +2260,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * PUT(hl_info, "start", INTEGER_OBJ(sp->start - buf)); if (sp->userhl == 0) { - grpname = get_default_stl_hl(wp, use_winbar, stc_hl_id); + grpname = get_default_stl_hl(use_tabline ? NULL : wp, use_winbar, stc_hl_id); } else if (sp->userhl < 0) { grpname = syn_id2name(-sp->userhl); } else { -- cgit From 9408f2dcf7cade2631688300e9b58eed6bc5219a Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Fri, 7 Apr 2023 19:40:57 +0200 Subject: refactor: remove redundant const char * casts --- src/nvim/api/private/converter.c | 2 +- src/nvim/api/ui.c | 4 ++-- src/nvim/api/win_config.c | 9 ++++----- 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index 58ff552ab7..7d04d883f5 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -49,7 +49,7 @@ typedef struct { #define TYPVAL_ENCODE_CONV_STRING(tv, str, len) \ do { \ const size_t len_ = (size_t)(len); \ - const char *const str_ = (const char *)(str); \ + const char *const str_ = (str); \ assert(len_ == 0 || str_ != NULL); \ kvi_push(edata->stack, STRING_OBJ(cbuf_to_string((len_?str_:""), len_))); \ } while (0) diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 5dd858a6a9..edf13b073c 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -843,7 +843,7 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int uint32_t csize = (repeat > 1) ? 3 : ((attrs[i] != last_hl) ? 2 : 1); nelem++; mpack_array(buf, csize); - mpack_str(buf, (const char *)chunk[i]); + mpack_str(buf, chunk[i]); if (csize >= 2) { mpack_uint(buf, (uint32_t)attrs[i]); if (csize >= 3) { @@ -873,7 +873,7 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int for (int i = 0; i < endcol - startcol; i++) { remote_ui_cursor_goto(ui, row, startcol + i); remote_ui_highlight_set(ui, attrs[i]); - remote_ui_put(ui, (const char *)chunk[i]); + remote_ui_put(ui, chunk[i]); if (utf_ambiguous_width(utf_ptr2char((char *)chunk[i]))) { data->client_col = -1; // force cursor update } diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 0ffeac1bff..23bd5d2f48 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -275,13 +275,13 @@ Dictionary nvim_win_get_config(Window window, Error *err) for (size_t i = 0; i < 8; i++) { Array tuple = ARRAY_DICT_INIT; - String s = cstrn_to_string((const char *)config->border_chars[i], sizeof(schar_T)); + String s = cstrn_to_string(config->border_chars[i], sizeof(schar_T)); int hi_id = config->border_hl_ids[i]; char *hi_name = syn_id2name(hi_id); if (hi_name[0]) { ADD(tuple, STRING_OBJ(s)); - ADD(tuple, STRING_OBJ(cstr_to_string((const char *)hi_name))); + ADD(tuple, STRING_OBJ(cstr_to_string(hi_name))); ADD(border, ARRAY_OBJ(tuple)); } else { ADD(border, STRING_OBJ(s)); @@ -293,10 +293,9 @@ Dictionary nvim_win_get_config(Window window, Error *err) VirtText title_datas = config->title_chunks; for (size_t i = 0; i < title_datas.size; i++) { Array tuple = ARRAY_DICT_INIT; - ADD(tuple, CSTR_TO_OBJ((const char *)title_datas.items[i].text)); + ADD(tuple, CSTR_TO_OBJ(title_datas.items[i].text)); if (title_datas.items[i].hl_id > 0) { - ADD(tuple, - STRING_OBJ(cstr_to_string((const char *)syn_id2name(title_datas.items[i].hl_id)))); + ADD(tuple, STRING_OBJ(cstr_to_string(syn_id2name(title_datas.items[i].hl_id)))); } ADD(titles, ARRAY_OBJ(tuple)); } -- cgit From efb0896f21e03f64e3a14e7c09994e81956f47b9 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 3 Apr 2023 15:21:24 +0200 Subject: refactor(api): make typed dicts appear as types in the source code problem: can we have Serde? solution: we have Serde at home This by itself is just a change of notation, that could be quickly merged to avoid messy merge conflicts, but upcoming changes are planned: - keysets no longer need to be defined in one single file. `keysets.h` is just the initial automatic conversion of the previous `keysets.lua`. keysets just used in a single api/{scope}.h can be moved to that file, later on. - Typed dicts will have more specific types than Object. this will enable most of the existing manual typechecking boilerplate to be eliminated. We will need some annotation for missing value, i e a boolean will need to be represented as a TriState (none/false/true) in some cases. - Eventually: optional parameters in form of a `Dict opts` final parameter will get added in some form to metadata. this will require a discussion/desicion about type forward compatibility. --- src/nvim/api/autocmd.h | 1 + src/nvim/api/buffer.h | 1 + src/nvim/api/command.c | 1 + src/nvim/api/command.h | 1 + src/nvim/api/extmark.h | 1 + src/nvim/api/keysets.h | 270 ++++++++++++++++++++++++++++++++++++++++ src/nvim/api/keysets.lua | 239 ----------------------------------- src/nvim/api/options.h | 2 + src/nvim/api/private/defs.h | 4 - src/nvim/api/private/dispatch.h | 1 + src/nvim/api/private/helpers.h | 1 - src/nvim/api/vim.h | 1 + src/nvim/api/vimscript.h | 1 + src/nvim/api/win_config.h | 1 + 14 files changed, 281 insertions(+), 244 deletions(-) create mode 100644 src/nvim/api/keysets.h delete mode 100644 src/nvim/api/keysets.lua (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.h b/src/nvim/api/autocmd.h index f9432830d9..3273ca5759 100644 --- a/src/nvim/api/autocmd.h +++ b/src/nvim/api/autocmd.h @@ -3,6 +3,7 @@ #include +#include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/buffer.h b/src/nvim/api/buffer.h index 0814da63cd..db58239af8 100644 --- a/src/nvim/api/buffer.h +++ b/src/nvim/api/buffer.h @@ -3,6 +3,7 @@ #include +#include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" #include "nvim/buffer_defs.h" diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 7c01dc0e54..3df80e3fed 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -10,6 +10,7 @@ #include "lauxlib.h" #include "nvim/api/command.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/ascii.h" diff --git a/src/nvim/api/command.h b/src/nvim/api/command.h index b1c9230551..f16bd0acde 100644 --- a/src/nvim/api/command.h +++ b/src/nvim/api/command.h @@ -1,6 +1,7 @@ #ifndef NVIM_API_COMMAND_H #define NVIM_API_COMMAND_H +#include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" #include "nvim/decoration.h" #include "nvim/ex_cmds.h" diff --git a/src/nvim/api/extmark.h b/src/nvim/api/extmark.h index 0a627a889c..a6586e3031 100644 --- a/src/nvim/api/extmark.h +++ b/src/nvim/api/extmark.h @@ -1,6 +1,7 @@ #ifndef NVIM_API_EXTMARK_H #define NVIM_API_EXTMARK_H +#include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" #include "nvim/decoration.h" #include "nvim/macros.h" diff --git a/src/nvim/api/keysets.h b/src/nvim/api/keysets.h new file mode 100644 index 0000000000..333b90d7fd --- /dev/null +++ b/src/nvim/api/keysets.h @@ -0,0 +1,270 @@ +#ifndef NVIM_API_KEYSETS_H +#define NVIM_API_KEYSETS_H + +#include "nvim/api/private/defs.h" + +typedef struct { + Object types; +} Dict(context); + +typedef struct { + Object on_start; + Object on_buf; + Object on_win; + Object on_line; + Object on_end; + Object _on_hl_def; + Object _on_spell_nav; +} Dict(set_decoration_provider); + +typedef struct { + Object id; + Object end_line; + Object end_row; + Object end_col; + Object hl_group; + Object virt_text; + Object virt_text_pos; + Object virt_text_win_col; + Object virt_text_hide; + Object hl_eol; + Object hl_mode; + Object ephemeral; + Object priority; + Object right_gravity; + Object end_right_gravity; + Object virt_lines; + Object virt_lines_above; + Object virt_lines_leftcol; + Object strict; + Object sign_text; + Object sign_hl_group; + Object number_hl_group; + Object line_hl_group; + Object cursorline_hl_group; + Object conceal; + Object spell; + Object ui_watched; +} Dict(set_extmark); + +typedef struct { + Object noremap; + Object nowait; + Object silent; + Object script; + Object expr; + Object unique; + Object callback; + Object desc; + Object replace_keycodes; +} Dict(keymap); + +typedef struct { + Object builtin; +} Dict(get_commands); + +typedef struct { + Object addr; + Object bang; + Object bar; + Object complete; + Object count; + Object desc; + Object force; + Object keepscript; + Object nargs; + Object preview; + Object range; + Object register_; +} Dict(user_command); + +typedef struct { + Object row; + Object col; + Object width; + Object height; + Object anchor; + Object relative; + Object win; + Object bufpos; + Object external; + Object focusable; + Object zindex; + Object border; + Object title; + Object title_pos; + Object style; + Object noautocmd; +} Dict(float_config); + +typedef struct { + Object is_lua; + Object do_source; +} Dict(runtime); + +typedef struct { + Object winid; + Object maxwidth; + Object fillchar; + Object highlights; + Object use_winbar; + Object use_tabline; + Object use_statuscol_lnum; +} Dict(eval_statusline); + +typedef struct { + Object scope; + Object win; + Object buf; + Object filetype; +} Dict(option); + +typedef struct { + Object bold; + Object standout; + Object strikethrough; + Object underline; + Object undercurl; + Object underdouble; + Object underdotted; + Object underdashed; + Object italic; + Object reverse; + Object altfont; + Object nocombine; + Object default_; + Object cterm; + Object foreground; + Object fg; + Object background; + Object bg; + Object ctermfg; + Object ctermbg; + Object special; + Object sp; + Object link; + Object global_link; + Object fallback; + Object blend; + Object fg_indexed; + Object bg_indexed; +} Dict(highlight); + +typedef struct { + Object bold; + Object standout; + Object strikethrough; + Object underline; + Object undercurl; + Object underdouble; + Object underdotted; + Object underdashed; + Object italic; + Object reverse; + Object altfont; + Object nocombine; +} Dict(highlight_cterm); + +typedef struct { + Object id; + Object name; + Object link; +} Dict(get_highlight); + +typedef struct { + Object buffer; + Object event; + Object group; + Object pattern; +} Dict(clear_autocmds); + +typedef struct { + Object buffer; + Object callback; + Object command; + Object desc; + Object group; + Object nested; + Object once; + Object pattern; +} Dict(create_autocmd); + +typedef struct { + Object buffer; + Object group; + Object modeline; + Object pattern; + Object data; +} Dict(exec_autocmds); + +typedef struct { + Object event; + Object group; + Object pattern; + Object buffer; +} Dict(get_autocmds); + +typedef struct { + Object clear; +} Dict(create_augroup); + +typedef struct { + Object cmd; + Object range; + Object count; + Object reg; + Object bang; + Object args; + Object magic; + Object mods; + Object nargs; + Object addr; + Object nextcmd; +} Dict(cmd); + +typedef struct { + Object file; + Object bar; +} Dict(cmd_magic); + +typedef struct { + Object silent; + Object emsg_silent; + Object unsilent; + Object filter; + Object sandbox; + Object noautocmd; + Object browse; + Object confirm; + Object hide; + Object horizontal; + Object keepalt; + Object keepjumps; + Object keepmarks; + Object keeppatterns; + Object lockmarks; + Object noswapfile; + Object tab; + Object verbose; + Object vertical; + Object split; +} Dict(cmd_mods); + +typedef struct { + Object pattern; + Object force; +} Dict(cmd_mods_filter); + +typedef struct { + Object output; +} Dict(cmd_opts); + +typedef struct { + Object verbose; +} Dict(echo_opts); + +typedef struct { + Object output; +} Dict(exec_opts); + +#endif // NVIM_API_KEYSETS_H diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua deleted file mode 100644 index 01f5a8b860..0000000000 --- a/src/nvim/api/keysets.lua +++ /dev/null @@ -1,239 +0,0 @@ -return { - { 'context', { - "types"; - }}; - { 'set_decoration_provider', { - "on_start"; - "on_buf"; - "on_win"; - "on_line"; - "on_end"; - "_on_hl_def"; - "_on_spell_nav"; - }}; - { 'set_extmark', { - "id"; - "end_line"; - "end_row"; - "end_col"; - "hl_group"; - "virt_text"; - "virt_text_pos"; - "virt_text_win_col"; - "virt_text_hide"; - "hl_eol"; - "hl_mode"; - "ephemeral"; - "priority"; - "right_gravity"; - "end_right_gravity"; - "virt_lines"; - "virt_lines_above"; - "virt_lines_leftcol"; - "strict"; - "sign_text"; - "sign_hl_group"; - "number_hl_group"; - "line_hl_group"; - "cursorline_hl_group"; - "conceal"; - "spell"; - "ui_watched"; - }}; - { 'keymap', { - "noremap"; - "nowait"; - "silent"; - "script"; - "expr"; - "unique"; - "callback"; - "desc"; - "replace_keycodes"; - }}; - { 'get_commands', { - "builtin"; - }}; - { 'user_command', { - "addr"; - "bang"; - "bar"; - "complete"; - "count"; - "desc"; - "force"; - "keepscript"; - "nargs"; - "preview"; - "range"; - "register"; - }}; - { 'float_config', { - "row"; - "col"; - "width"; - "height"; - "anchor"; - "relative"; - "win"; - "bufpos"; - "external"; - "focusable"; - "zindex"; - "border"; - "title"; - "title_pos"; - "style"; - "noautocmd"; - }}; - { 'runtime', { - "is_lua"; - "do_source"; - }}; - { 'eval_statusline', { - "winid"; - "maxwidth"; - "fillchar"; - "highlights"; - "use_winbar"; - "use_tabline"; - "use_statuscol_lnum"; - }}; - { 'option', { - "scope"; - "win"; - "buf"; - "filetype"; - }}; - { 'highlight', { - "bold"; - "standout"; - "strikethrough"; - "underline"; - "undercurl"; - "underdouble"; - "underdotted"; - "underdashed"; - "italic"; - "reverse"; - "altfont"; - "nocombine"; - "default"; - "cterm"; - "foreground"; "fg"; - "background"; "bg"; - "ctermfg"; - "ctermbg"; - "special"; "sp"; - "link"; - "global_link"; - "fallback"; - "blend"; - "fg_indexed"; - "bg_indexed"; - }}; - { 'highlight_cterm', { - "bold"; - "standout"; - "strikethrough"; - "underline"; - "undercurl"; - "underdouble"; - "underdotted"; - "underdashed"; - "italic"; - "reverse"; - "altfont"; - "nocombine"; - }}; - { 'get_highlight', { - "id"; - "name"; - "link"; - }}; - -- Autocmds - { 'clear_autocmds', { - "buffer"; - "event"; - "group"; - "pattern"; - }}; - { 'create_autocmd', { - "buffer"; - "callback"; - "command"; - "desc"; - "group"; - "nested"; - "once"; - "pattern"; - }}; - { 'exec_autocmds', { - "buffer"; - "group"; - "modeline"; - "pattern"; - "data"; - }}; - { 'get_autocmds', { - "event"; - "group"; - "pattern"; - "buffer"; - }}; - { 'create_augroup', { - "clear"; - }}; - { 'cmd', { - "cmd"; - "range"; - "count"; - "reg"; - "bang"; - "args"; - "magic"; - "mods"; - "nargs"; - "addr"; - "nextcmd"; - }}; - { 'cmd_magic', { - "file"; - "bar"; - }}; - { 'cmd_mods', { - "silent"; - "emsg_silent"; - "unsilent"; - "filter"; - "sandbox"; - "noautocmd"; - "browse"; - "confirm"; - "hide"; - "horizontal"; - "keepalt"; - "keepjumps"; - "keepmarks"; - "keeppatterns"; - "lockmarks"; - "noswapfile"; - "tab"; - "verbose"; - "vertical"; - "split"; - }}; - { 'cmd_mods_filter', { - "pattern"; - "force"; - }}; - { 'cmd_opts', { - "output"; - }}; - { 'echo_opts', { - "verbose"; - }}; - { 'exec_opts', { - "output"; - }}; -} diff --git a/src/nvim/api/options.h b/src/nvim/api/options.h index efbfec3a6c..869826e443 100644 --- a/src/nvim/api/options.h +++ b/src/nvim/api/options.h @@ -1,7 +1,9 @@ #ifndef NVIM_API_OPTIONS_H #define NVIM_API_OPTIONS_H +#include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/options.h.generated.h" #endif diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index 8acbf0d9de..7c5559f096 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -130,8 +130,4 @@ typedef struct { size_t ptr_off; } KeySetLink; -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "keysets_defs.generated.h" -#endif - #endif // NVIM_API_PRIVATE_DEFS_H diff --git a/src/nvim/api/private/dispatch.h b/src/nvim/api/private/dispatch.h index 4ae61b2bfb..78fcf88d7b 100644 --- a/src/nvim/api/private/dispatch.h +++ b/src/nvim/api/private/dispatch.h @@ -28,6 +28,7 @@ extern const MsgpackRpcRequestHandler method_handlers[]; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/dispatch.h.generated.h" # include "api/private/dispatch_wrappers.h.generated.h" +# include "keysets_defs.generated.h" #endif #endif // NVIM_API_PRIVATE_DISPATCH_H diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index eef97cccb2..2623c97c9d 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -181,7 +181,6 @@ typedef struct { #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/helpers.h.generated.h" -# include "keysets.h.generated.h" #endif #define WITH_SCRIPT_CONTEXT(channel_id, code) \ diff --git a/src/nvim/api/vim.h b/src/nvim/api/vim.h index de56c67665..c305749ba0 100644 --- a/src/nvim/api/vim.h +++ b/src/nvim/api/vim.h @@ -1,6 +1,7 @@ #ifndef NVIM_API_VIM_H #define NVIM_API_VIM_H +#include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/vimscript.h b/src/nvim/api/vimscript.h index be808b6b25..99ef43454b 100644 --- a/src/nvim/api/vimscript.h +++ b/src/nvim/api/vimscript.h @@ -1,6 +1,7 @@ #ifndef NVIM_API_VIMSCRIPT_H #define NVIM_API_VIMSCRIPT_H +#include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/win_config.h b/src/nvim/api/win_config.h index d3e5ede5e9..a4614f02ce 100644 --- a/src/nvim/api/win_config.h +++ b/src/nvim/api/win_config.h @@ -1,6 +1,7 @@ #ifndef NVIM_API_WIN_CONFIG_H #define NVIM_API_WIN_CONFIG_H +#include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS -- cgit From 2d78e656b715119ca11d131a1a932f22f1b4ad36 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Fri, 7 Apr 2023 21:43:00 +0200 Subject: refactor: remove redundant casts --- src/nvim/api/autocmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 620a295788..6a267103b4 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -608,7 +608,7 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err) FOR_ALL_AUEVENTS(event) { FOREACH_ITEM(patterns, pat_object, { char *pat = pat_object.data.string.data; - if (!clear_autocmd(event, (char *)pat, au_group, err)) { + if (!clear_autocmd(event, pat, au_group, err)) { goto cleanup; } }); @@ -619,7 +619,7 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err) FOREACH_ITEM(patterns, pat_object, { char *pat = pat_object.data.string.data; - if (!clear_autocmd(event_nr, (char *)pat, au_group, err)) { + if (!clear_autocmd(event_nr, pat, au_group, err)) { goto cleanup; } }); -- cgit From d3ea9a04bc737d4b52cd7abf69b75c5563b39741 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Sun, 9 Apr 2023 00:41:50 +0200 Subject: fix(api): update "w_scwidth" in nvim_eval_statusline() Problem: `w_scwidth` may be outdated in `nvim_eval_status()`, causing `build_stl_str_hl()` to return an empty `%s` sign segment. Solution: Update `w_scwidth` for `'statuscolumn'` evaluation. --- src/nvim/api/vim.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index b62521290d..c8bb22b33c 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2173,6 +2173,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * linenr_T lnum = statuscol_lnum; int num_signs = buf_get_signattrs(wp->w_buffer, lnum, sattrs, &num, &line, &cul); decor_redraw_signs(wp->w_buffer, lnum - 1, &num_signs, sattrs, &num, &line, &cul); + wp->w_scwidth = win_signcol_count(wp); statuscol.sattrs = sattrs; statuscol.foldinfo = fold_info(wp, lnum); -- cgit From da979ae04b7a8c56586ed0233957600ad6af99f0 Mon Sep 17 00:00:00 2001 From: Munif Tanjim Date: Sun, 2 Apr 2023 23:01:10 +0600 Subject: fix(api): do not re-apply win_config.style when missing --- src/nvim/api/win_config.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 0ffeac1bff..b2b2b51005 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -108,8 +108,8 @@ /// The default value for floats are 50. In general, values below 100 are /// recommended, unless there is a good reason to overshadow builtin /// elements. -/// - style: Configure the appearance of the window. Currently only takes -/// one non-empty value: +/// - style: (optional) Configure the appearance of the window. Currently +/// only supports one value: /// - "minimal" Nvim will display the window with many UI options /// disabled. This is useful when displaying a temporary /// float where the text should not be edited. Disables @@ -222,9 +222,11 @@ void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err) win_config_float(win, fconfig); win->w_pos_changed = true; } - if (fconfig.style == kWinStyleMinimal) { - win_set_minimal_style(win); - didset_window_options(win, true); + if (HAS_KEY(config->style)) { + if (fconfig.style == kWinStyleMinimal) { + win_set_minimal_style(win); + didset_window_options(win, true); + } } } -- cgit From 8f69c5ed450337b9f77c50f9ee0d3eb32f649ca6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 07:11:59 +0800 Subject: vim-patch:8.2.{0695,0725,0734,0753,0818,0819,0822} (#23075) vim-patch:8.2.0695: Vim9: cannot define a function inside a function Problem: Vim9: cannot define a function inside a function. Solution: Initial support for :def inside :def. https://github.com/vim/vim/commit/04b12697838b232b8b17c553ccc74cf1f1bdb81c vim-patch:8.2.0725: Vim9: cannot call a function declared later in Vim9 script Problem: Vim9: cannot call a function declared later in Vim9 script. Solution: Make two passes through the script file. https://github.com/vim/vim/commit/09689a02840be40fa7bb10b1921fb5bc5b2908f1 vim-patch:8.2.0734: Vim9: leaking memory when using :finish Problem: Vim9: leaking memory when using :finish. Solution: Do not check for next line in third pass. https://github.com/vim/vim/commit/04816717dfea6e2469ff4c9d40f68b59aaf03724 vim-patch:8.2.0753: Vim9: expressions are evaluated in the discovery phase Problem: Vim9: expressions are evaluated in the discovery phase. Solution: Bail out if an expression is not a constant. Require a type for declared constants. https://github.com/vim/vim/commit/32e351179eacfc84f64cd5029e221582d400bb38 vim-patch:8.2.0818: Vim9: using a discovery phase doesn't work well Problem: Vim9: using a discovery phase doesn't work well. Solution: Remove the discovery phase, instead compile a function only when it is used. Add :defcompile to compile def functions earlier. https://github.com/vim/vim/commit/822ba24743af9ee1b5e7f656a7a61a38f3638bca vim-patch:8.2.0819: compiler warning for unused variable Problem: Compiler warning for unused variable. Solution: Remove the variable. https://github.com/vim/vim/commit/f40e51a880a95f94dbbbecc9476559506c2cc345 vim-patch:8.2.0822: Vim9: code left over from discovery phase Problem: Vim9: code left over from discovery phase. Solution: Remove the dead code. https://github.com/vim/vim/commit/2eec37926db6d31beb36f162ac00357a30c093c8 Co-authored-by: Bram Moolenaar --- src/nvim/api/vimscript.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 2438a5cf1d..1740429ef6 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -172,7 +172,7 @@ Object nvim_eval(String expr, Error *err) int ok; TRY_WRAP(err, { - ok = eval0(expr.data, &rettv, NULL, true); + ok = eval0(expr.data, &rettv, NULL, EVAL_EVALUATE); }); if (!ERROR_SET(err)) { @@ -290,7 +290,7 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err) switch (dict.type) { case kObjectTypeString: try_start(); - if (eval0(dict.data.string.data, &rettv, NULL, true) == FAIL) { + if (eval0(dict.data.string.data, &rettv, NULL, EVAL_EVALUATE) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to evaluate dict expression"); } -- cgit From bd83b587b18bb6f2ac555a992fa5b7d907de7e79 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 07:22:01 +0800 Subject: vim-patch:8.2.1047: Vim9: script cannot use line continuation like :def function Problem: Vim9: script cannot use line continuation like in a :def function. Solution: Pass the getline function pointer to the eval() functions. Use it for addition and multiplication operators. https://github.com/vim/vim/commit/5409f5d8c95007216ae1190565a7a8ee9ebd7100 Omit source_nextline() and eval_next_non_blank(): Vim9 script only. N/A patches for version.c: vim-patch:8.2.1048: build failure without the eval feature Problem: Build failure without the eval feature. Solution: Add dummy typedef. https://github.com/vim/vim/commit/9d40c63c7dc8c3eb3886c58dcd334bc7f37eceba vim-patch:8.2.1052: build failure with older compilers Problem: Build failure with older compilers. Solution: Move declaration to start of block. https://github.com/vim/vim/commit/7acde51832f383f9a6d2e740cd0420b433ea841a Co-authored-by: Bram Moolenaar --- src/nvim/api/vimscript.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 1740429ef6..d2e18f08f3 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -172,7 +172,7 @@ Object nvim_eval(String expr, Error *err) int ok; TRY_WRAP(err, { - ok = eval0(expr.data, &rettv, NULL, EVAL_EVALUATE); + ok = eval0(expr.data, &rettv, NULL, &EVALARG_EVALUATE); }); if (!ERROR_SET(err)) { @@ -290,7 +290,7 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err) switch (dict.type) { case kObjectTypeString: try_start(); - if (eval0(dict.data.string.data, &rettv, NULL, EVAL_EVALUATE) == FAIL) { + if (eval0(dict.data.string.data, &rettv, NULL, &EVALARG_EVALUATE) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to evaluate dict expression"); } -- cgit From 8729c41f44de3b164ad8d01bb3558c6400e27952 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Apr 2023 13:49:28 +0800 Subject: vim-patch:8.2.1080: Vim9: no line break allowed in a for loop Problem: Vim9: no line break allowed in a for loop. Solution: Skip line breaks in for command. https://github.com/vim/vim/commit/b7a78f7a6713f07d2fcad0b27dea22925c7b1cdf Omit *_break_count and skip_for_lines(): Vim9 script only. Co-authored-by: Bram Moolenaar --- src/nvim/api/vimscript.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index d2e18f08f3..208aa165c9 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -173,6 +173,7 @@ Object nvim_eval(String expr, Error *err) TRY_WRAP(err, { ok = eval0(expr.data, &rettv, NULL, &EVALARG_EVALUATE); + clear_evalarg(&EVALARG_EVALUATE, NULL); }); if (!ERROR_SET(err)) { @@ -294,6 +295,7 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err) api_set_error(err, kErrorTypeException, "Failed to evaluate dict expression"); } + clear_evalarg(&EVALARG_EVALUATE, NULL); if (try_end(err)) { return rv; } -- cgit From 59fed8bb6457eb6c5204dc39a49d7ea0e1781482 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Tue, 18 Apr 2023 15:07:37 +0200 Subject: fix(api): extmark highlight groups not always included in details (#23179) Problem: Erroneous for loop condition. Solution: Remove for loop condition. --- src/nvim/api/extmark.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index fc17b9d0cc..eb49587d03 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -208,7 +208,7 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict // uncrustify:on - for (int j = 0; hls[j].name && hls[j].val; j++) { + for (int j = 0; hls[j].name; j++) { if (hls[j].val) { PUT(dict, hls[j].name, hl_group_name(hls[j].val, hl_name)); } -- cgit From 706f871014b46300180156590ff269ee38473989 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 19 Apr 2023 17:04:00 +0100 Subject: build: update uncrustify to 0.76 --- src/nvim/api/ui.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index edf13b073c..bd3482c85f 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -254,7 +254,8 @@ void nvim_ui_detach(uint64_t channel_id, Error *err) // TODO(bfredl): use me to detach a specific ui from the server void remote_ui_stop(UI *ui) -{} +{ +} void nvim_ui_try_resize(uint64_t channel_id, Integer width, Integer height, Error *err) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY -- cgit From ef7ae66eef4e36e15b5248b926b4b020387d8101 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Fri, 21 Apr 2023 10:55:36 +0200 Subject: fix(api): avoid integer truncation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gsrc/nvim/api/vim.c: In function ‘nvim_eval_statusline’: gsrc/nvim/api/vim.c:2268:55: warning: ‘%d’ directive output may be truncated writing between 1 and 10 bytes into a region of size 2 [-Wformat-tru ncation=] 2268 | snprintf(user_group, sizeof(user_group), "User%d", sp->userhl); | ^~ gsrc/nvim/api/vim.c:2268:50: note: directive argument in the range [1, 2147483647] 2268 | snprintf(user_group, sizeof(user_group), "User%d", sp->userhl); | ^~~~~~~~ In file included from /usr/include/stdio.h:906, from gsrc/nvim/api/vim.c:9: In function ‘snprintf’, inlined from ‘nvim_eval_statusline’ at gsrc/nvim/api/vim.c:2268:9: /usr/include/bits/stdio2.h:54:10: note: ‘__builtin___snprintf_chk’ output between 6 and 15 bytes into a destination of size 6 54 | return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 55 | __glibc_objsize (__s), __fmt, | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 56 | __va_arg_pack ()); | ~~~~~~~~~~~~~~~~~ --- src/nvim/api/vim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index c8bb22b33c..d47f47e638 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2241,7 +2241,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * if (highlights) { Array hl_values = ARRAY_DICT_INIT; const char *grpname; - char user_group[6]; + char user_group[15]; // strlen("User") + strlen("2147483647") + NUL // If first character doesn't have a defined highlight, // add the default highlight at the beginning of the highlight list -- cgit From 3ac952d4e27f4e2454332a730310316fe13fd4a3 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Sun, 23 Apr 2023 06:53:25 +0530 Subject: fix(api): avoid assertion when autocmd group id is 0 (#23210) --- src/nvim/api/autocmd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 6a267103b4..e606322f24 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -114,7 +114,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) break; case kObjectTypeInteger: group = (int)opts->group.data.integer; - char *name = augroup_name(group); + char *name = group == 0 ? NULL : augroup_name(group); VALIDATE_INT(augroup_exists(name), "group", opts->group.data.integer, { goto cleanup; }); @@ -684,7 +684,7 @@ void nvim_del_augroup_by_id(Integer id, Error *err) FUNC_API_SINCE(9) { TRY_WRAP(err, { - char *name = augroup_name((int)id); + char *name = id == 0 ? NULL : augroup_name((int)id); augroup_del(name, false); }); } @@ -746,7 +746,7 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err) break; case kObjectTypeInteger: au_group = (int)opts->group.data.integer; - char *name = augroup_name(au_group); + char *name = au_group == 0 ? NULL : augroup_name(au_group); VALIDATE_INT(augroup_exists(name), "group", (int64_t)au_group, { goto cleanup; }); @@ -840,7 +840,7 @@ static int get_augroup_from_object(Object group, Error *err) return au_group; case kObjectTypeInteger: au_group = (int)group.data.integer; - char *name = augroup_name(au_group); + char *name = au_group == 0 ? NULL : augroup_name(au_group); VALIDATE_INT(augroup_exists(name), "group", (int64_t)au_group, { return AUGROUP_ERROR; }); -- cgit From a1b045f60a22d366e255dfff1c54ed42ebe49284 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Wed, 26 Apr 2023 18:28:49 +0200 Subject: refactor(clang-tidy): remove redundant casts --- src/nvim/api/buffer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index ca3cf76388..10c684941c 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -404,7 +404,7 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ // If the size of the range is reducing (ie, new_len < old_len) we // need to delete some old_len. We do this at the start, by // repeatedly deleting line "start". - size_t to_delete = (new_len < old_len) ? (size_t)(old_len - new_len) : 0; + size_t to_delete = (new_len < old_len) ? old_len - new_len : 0; for (size_t i = 0; i < to_delete; i++) { if (ml_delete((linenr_T)start, false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to delete line"); @@ -648,7 +648,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In // If the size of the range is reducing (ie, new_len < old_len) we // need to delete some old_len. We do this at the start, by // repeatedly deleting line "start". - size_t to_delete = (new_len < old_len) ? (size_t)(old_len - new_len) : 0; + size_t to_delete = (new_len < old_len) ? old_len - new_len : 0; for (size_t i = 0; i < to_delete; i++) { if (ml_delete((linenr_T)start_row, false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to delete line"); -- cgit From 3b0df1780e2c8526bda5dead18ee7cc45925caba Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Wed, 26 Apr 2023 23:23:44 +0200 Subject: refactor: uncrustify Notable changes: replace all infinite loops to `while(true)` and remove `int` from `unsigned int`. --- src/nvim/api/extmark.c | 2 +- src/nvim/api/options.c | 2 +- src/nvim/api/private/converter.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index eb49587d03..b781da1dc3 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -1168,7 +1168,7 @@ static bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, in Integer pos_row = pos.items[0].data.integer; Integer pos_col = pos.items[1].data.integer; - *row = (int)(pos_row >= 0 ? pos_row : MAXLNUM); + *row = (int)(pos_row >= 0 ? pos_row : MAXLNUM); *col = (colnr_T)(pos_col >= 0 ? pos_col : MAXCOL); return true; } else { diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 467a4720a6..2d1b170d2d 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -546,7 +546,7 @@ void set_option_to(uint64_t channel_id, void *to, int type, String name, Object // For global-win-local options -> setlocal // For win-local options -> setglobal and setlocal (opt_flags == 0) const int opt_flags = (type == SREQ_WIN && !(flags & SOPT_GLOBAL)) ? 0 : - (type == SREQ_GLOBAL) ? OPT_GLOBAL : OPT_LOCAL; + (type == SREQ_GLOBAL) ? OPT_GLOBAL : OPT_LOCAL; WITH_SCRIPT_CONTEXT(channel_id, { access_option_value_for(name.data, &numval, &stringval, opt_flags, type, to, false, err); diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index 7d04d883f5..a62f975cfd 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -51,7 +51,7 @@ typedef struct { const size_t len_ = (size_t)(len); \ const char *const str_ = (str); \ assert(len_ == 0 || str_ != NULL); \ - kvi_push(edata->stack, STRING_OBJ(cbuf_to_string((len_?str_:""), len_))); \ + kvi_push(edata->stack, STRING_OBJ(cbuf_to_string((len_ ? str_ : ""), len_))); \ } while (0) #define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING @@ -275,7 +275,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) case kObjectTypeBoolean: tv->v_type = VAR_BOOL; - tv->vval.v_bool = obj.data.boolean? kBoolVarTrue: kBoolVarFalse; + tv->vval.v_bool = obj.data.boolean ? kBoolVarTrue : kBoolVarFalse; break; case kObjectTypeBuffer: -- cgit From eb4676c67f5dd54bcda473783315901a3444b40b Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 27 Apr 2023 17:30:22 +0100 Subject: fix: disallow removing extmarks in on_lines callbacks (#23219) fix(extmarks): disallow removing extmarks in on_lines callbacks decor_redraw_start (which runs before decor_providers_invoke_lines) gets references for the extmarks on a specific line. If these extmarks are deleted in on_lines callbacks then this results in a heap-use-after-free error. Fixes #22801 --- src/nvim/api/deprecated.c | 2 +- src/nvim/api/extmark.c | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 5937b2f635..0ca505e7b2 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -172,7 +172,7 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A decor.priority = 0; extmark_set(buf, ns_id, NULL, (int)line, 0, -1, -1, &decor, true, - false, kExtmarkNoUndo); + false, kExtmarkNoUndo, NULL); return src_id; } diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index b781da1dc3..87232a8a93 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -874,7 +874,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer extmark_set(buf, (uint32_t)ns_id, &id, (int)line, (colnr_T)col, line2, col2, has_decor ? &decor : NULL, right_gravity, end_right_gravity, - kExtmarkNoUndo); + kExtmarkNoUndo, err); + if (ERROR_SET(err)) { + goto error; + } } return (Integer)id; @@ -903,6 +906,11 @@ Boolean nvim_buf_del_extmark(Buffer buffer, Integer ns_id, Integer id, Error *er return false; }); + if (decor_state.running_on_lines) { + api_set_error(err, kErrorTypeValidation, "Cannot remove extmarks during on_line callbacks"); + return false; + } + return extmark_del(buf, (uint32_t)ns_id, (uint32_t)id); } @@ -993,7 +1001,7 @@ Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, In extmark_set(buf, ns, NULL, (int)line, (colnr_T)col_start, end_line, (colnr_T)col_end, - &decor, true, false, kExtmarkNoUndo); + &decor, true, false, kExtmarkNoUndo, NULL); return ns_id; } @@ -1022,6 +1030,11 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, return; }); + if (decor_state.running_on_lines) { + api_set_error(err, kErrorTypeValidation, "Cannot remove extmarks during on_line callbacks"); + return; + } + if (line_end < 0 || line_end > MAXLNUM) { line_end = MAXLNUM; } @@ -1051,11 +1064,13 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, /// for the extmarks set/modified inside the callback anyway. /// /// Note: doing anything other than setting extmarks is considered experimental. -/// Doing things like changing options are not expliticly forbidden, but is +/// Doing things like changing options are not explicitly forbidden, but is /// likely to have unexpected consequences (such as 100% CPU consumption). /// doing `vim.rpcnotify` should be OK, but `vim.rpcrequest` is quite dubious /// for the moment. /// +/// Note: It is not allowed to remove or update extmarks in 'on_line' callbacks. +/// /// @param ns_id Namespace id from |nvim_create_namespace()| /// @param opts Table of callbacks: /// - on_start: called first on each screen redraw -- cgit From 1cb60405548e79f1ec63921540e1c3ebb3ddcc01 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Thu, 27 Apr 2023 19:25:08 +0200 Subject: perf(events): store autocommands in flat vectors (#23256) Instead of nested linked lists, store autocommands in a flat, contiguous kvec_t, with one kvec_t per event type. Previously patterns were stored in each node of the outer linked list, so they can be matched only once on repeating patterns. They are now reference counted and referenced in each autocommand, and matching is skipped if the pattern repeats. Speeds up creation and deletion, execution is not affected. Co-authored-by: ii14 --- src/nvim/api/autocmd.c | 151 ++++++++++++++++++++++--------------------------- 1 file changed, 69 insertions(+), 82 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index e606322f24..6ecbff2606 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -225,8 +225,12 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) continue; } - for (AutoPat *ap = au_get_autopat_for_event(event); ap != NULL; ap = ap->next) { - if (ap->cmds == NULL) { + AutoCmdVec *acs = au_get_autocmds_for_event(event); + for (size_t i = 0; i < kv_size(*acs); i++) { + AutoCmd *const ac = &kv_A(*acs, i); + AutoPat *const ap = ac->pat; + + if (ap == NULL) { continue; } @@ -238,19 +242,16 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) // Skip 'pattern' from invalid patterns if passed. if (pattern_filter_count > 0) { bool passed = false; - for (int i = 0; i < pattern_filter_count; i++) { - assert(i < AUCMD_MAX_PATTERNS); - assert(pattern_filters[i]); + for (int j = 0; j < pattern_filter_count; j++) { + assert(j < AUCMD_MAX_PATTERNS); + assert(pattern_filters[j]); - char *pat = pattern_filters[i]; + char *pat = pattern_filters[j]; int patlen = (int)strlen(pat); if (aupat_is_buflocal(pat, patlen)) { - aupat_normalize_buflocal_pat(pattern_buflocal, - pat, - patlen, + aupat_normalize_buflocal_pat(pattern_buflocal, pat, patlen, aupat_get_buflocal_nr(pat, patlen)); - pat = pattern_buflocal; } @@ -265,85 +266,71 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) } } - for (AutoCmd *ac = ap->cmds; ac != NULL; ac = ac->next) { - if (aucmd_exec_is_deleted(ac->exec)) { - continue; - } - - Dictionary autocmd_info = ARRAY_DICT_INIT; + Dictionary autocmd_info = ARRAY_DICT_INIT; - if (ap->group != AUGROUP_DEFAULT) { - PUT(autocmd_info, "group", INTEGER_OBJ(ap->group)); - PUT(autocmd_info, "group_name", CSTR_TO_OBJ(augroup_name(ap->group))); - } + if (ap->group != AUGROUP_DEFAULT) { + PUT(autocmd_info, "group", INTEGER_OBJ(ap->group)); + PUT(autocmd_info, "group_name", CSTR_TO_OBJ(augroup_name(ap->group))); + } - if (ac->id > 0) { - PUT(autocmd_info, "id", INTEGER_OBJ(ac->id)); - } + if (ac->id > 0) { + PUT(autocmd_info, "id", INTEGER_OBJ(ac->id)); + } - if (ac->desc != NULL) { - PUT(autocmd_info, "desc", CSTR_TO_OBJ(ac->desc)); - } + if (ac->desc != NULL) { + PUT(autocmd_info, "desc", CSTR_TO_OBJ(ac->desc)); + } - if (ac->exec.type == CALLABLE_CB) { - PUT(autocmd_info, "command", STRING_OBJ(STRING_INIT)); + if (ac->exec.type == CALLABLE_CB) { + PUT(autocmd_info, "command", STRING_OBJ(STRING_INIT)); - Callback *cb = &ac->exec.callable.cb; - switch (cb->type) { - case kCallbackLua: - if (nlua_ref_is_function(cb->data.luaref)) { - PUT(autocmd_info, "callback", LUAREF_OBJ(api_new_luaref(cb->data.luaref))); - } - break; - case kCallbackFuncref: - case kCallbackPartial: - PUT(autocmd_info, "callback", STRING_OBJ(cstr_as_string(callback_to_string(cb)))); - break; - default: - abort(); + Callback *cb = &ac->exec.callable.cb; + switch (cb->type) { + case kCallbackLua: + if (nlua_ref_is_function(cb->data.luaref)) { + PUT(autocmd_info, "callback", LUAREF_OBJ(api_new_luaref(cb->data.luaref))); } - } else { - PUT(autocmd_info, - "command", - STRING_OBJ(cstr_as_string(xstrdup(ac->exec.callable.cmd)))); + break; + case kCallbackFuncref: + case kCallbackPartial: + PUT(autocmd_info, "callback", STRING_OBJ(cstr_as_string(callback_to_string(cb)))); + break; + default: + abort(); } + } else { + PUT(autocmd_info, "command", STRING_OBJ(cstr_as_string(xstrdup(ac->exec.callable.cmd)))); + } - PUT(autocmd_info, - "pattern", - STRING_OBJ(cstr_to_string(ap->pat))); - - PUT(autocmd_info, - "event", - STRING_OBJ(cstr_to_string((char *)event_nr2name(event)))); - - PUT(autocmd_info, "once", BOOLEAN_OBJ(ac->once)); - - if (ap->buflocal_nr) { - PUT(autocmd_info, "buflocal", BOOLEAN_OBJ(true)); - PUT(autocmd_info, "buffer", INTEGER_OBJ(ap->buflocal_nr)); - } else { - PUT(autocmd_info, "buflocal", BOOLEAN_OBJ(false)); - } + PUT(autocmd_info, "pattern", STRING_OBJ(cstr_to_string(ap->pat))); + PUT(autocmd_info, "event", STRING_OBJ(cstr_to_string(event_nr2name(event)))); + PUT(autocmd_info, "once", BOOLEAN_OBJ(ac->once)); - // TODO(sctx): It would be good to unify script_ctx to actually work with lua - // right now it's just super weird, and never really gives you the info that - // you would expect from this. - // - // I think we should be able to get the line number, filename, etc. from lua - // when we're executing something, and it should be easy to then save that - // info here. - // - // I think it's a big loss not getting line numbers of where options, autocmds, - // etc. are set (just getting "Sourced (lua)" or something is not that helpful. - // - // Once we do that, we can put these into the autocmd_info, but I don't think it's - // useful to do that at this time. - // - // PUT(autocmd_info, "sid", INTEGER_OBJ(ac->script_ctx.sc_sid)); - // PUT(autocmd_info, "lnum", INTEGER_OBJ(ac->script_ctx.sc_lnum)); - - ADD(autocmd_list, DICTIONARY_OBJ(autocmd_info)); + if (ap->buflocal_nr) { + PUT(autocmd_info, "buflocal", BOOLEAN_OBJ(true)); + PUT(autocmd_info, "buffer", INTEGER_OBJ(ap->buflocal_nr)); + } else { + PUT(autocmd_info, "buflocal", BOOLEAN_OBJ(false)); } + + // TODO(sctx): It would be good to unify script_ctx to actually work with lua + // right now it's just super weird, and never really gives you the info that + // you would expect from this. + // + // I think we should be able to get the line number, filename, etc. from lua + // when we're executing something, and it should be easy to then save that + // info here. + // + // I think it's a big loss not getting line numbers of where options, autocmds, + // etc. are set (just getting "Sourced (lua)" or something is not that helpful. + // + // Once we do that, we can put these into the autocmd_info, but I don't think it's + // useful to do that at this time. + // + // PUT(autocmd_info, "sid", INTEGER_OBJ(ac->script_ctx.sc_sid)); + // PUT(autocmd_info, "lnum", INTEGER_OBJ(ac->script_ctx.sc_lnum)); + + ADD(autocmd_list, DICTIONARY_OBJ(autocmd_info)); } } @@ -663,7 +650,7 @@ Integer nvim_create_augroup(uint64_t channel_id, String name, Dict(create_augrou if (clear_autocmds) { FOR_ALL_AUEVENTS(event) { - aupat_del_for_event_and_group(event, augroup); + aucmd_del_for_event_and_group(event, augroup); } } }); @@ -866,7 +853,7 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob Object *v = &pattern; if (v->type == kObjectTypeString) { - char *pat = v->data.string.data; + const char *pat = v->data.string.data; size_t patlen = aucmd_pattern_length(pat); while (patlen) { ADD(*patterns, STRING_OBJ(cbuf_to_string(pat, patlen))); @@ -881,7 +868,7 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob Array array = v->data.array; FOREACH_ITEM(array, entry, { - char *pat = entry.data.string.data; + const char *pat = entry.data.string.data; size_t patlen = aucmd_pattern_length(pat); while (patlen) { ADD(*patterns, STRING_OBJ(cbuf_to_string(pat, patlen))); -- cgit From 6a273af10517d1f7e4ea85635f1d25a9158adeb5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 13 May 2023 10:40:53 +0800 Subject: refactor: remove typval.h from most header files (#23601) Because typval_defs.h is enough for most of them. --- src/nvim/api/private/converter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/private/converter.h b/src/nvim/api/private/converter.h index 80ee640295..28ae71983b 100644 --- a/src/nvim/api/private/converter.h +++ b/src/nvim/api/private/converter.h @@ -2,7 +2,7 @@ #define NVIM_API_PRIVATE_CONVERTER_H #include "nvim/api/private/defs.h" -#include "nvim/eval/typval.h" +#include "nvim/eval/typval_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/converter.h.generated.h" -- cgit From 08991b078267e5de0a19a136d00d4f71ad651a32 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 13 May 2023 21:33:22 +0200 Subject: docs: small fixes Co-authored-by: Christian Clason Co-authored-by: Gregory Anders Co-authored-by: HiPhish Co-authored-by: Julio B Co-authored-by: T727 <74924917+T-727@users.noreply.github.com> Co-authored-by: camoz Co-authored-by: champignoom <66909116+champignoom@users.noreply.github.com> --- src/nvim/api/command.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 3df80e3fed..b1603c5d6e 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -916,6 +916,7 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin /// - args: (string) The args passed to the command, if any || /// - fargs: (table) The args split by unescaped whitespace (when more than one /// argument is allowed), if any || +/// - nargs: (string) Number of arguments |:command-nargs| /// - bang: (boolean) "true" if the command was executed with a ! modifier || /// - line1: (number) The starting line of the command range || /// - line2: (number) The final line of the command range || -- cgit From e2fdd53d8c015913e8be4ff708fc3488558c8906 Mon Sep 17 00:00:00 2001 From: bfredl Date: Sun, 14 May 2023 18:45:56 +0200 Subject: refactor(map): avoid duplicated khash_t types for values This reduces the total number of khash_t instantiations from 22 to 8. Make the khash internal functions take the size of values as a runtime parameter. This is abstracted with typesafe Map containers which are still specialized for both key, value type. Introduce `Set(key)` type for when there is no value. Refactor shada.c to use Map/Set instead of khash directly. This requires `map_ref` operation to be more flexible. Return pointers to both key and value, plus an indicator for new_item. As a bonus, `map_key` is now redundant. Instead of Map(cstr_t, FileMarks), use a pointer map as the FileMarks struct is humongous. Make `event_strings` actually work like an intern pool instead of wtf it was doing before. --- src/nvim/api/extmark.c | 10 ++++------ src/nvim/api/extmark.h | 1 - src/nvim/api/private/helpers.h | 12 ++++++------ src/nvim/api/ui.c | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 87232a8a93..d6f0288f94 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -33,12 +33,10 @@ void api_extmark_free_all_mem(void) { String name; - handle_T id; - map_foreach(&namespace_ids, name, id, { - (void)id; + map_foreach_key(&namespace_ids, name, { xfree(name.data); }) - map_destroy(String, handle_T)(&namespace_ids); + map_destroy(String, &namespace_ids); } /// Creates a new namespace or gets an existing one. \*namespace\* @@ -77,7 +75,7 @@ Dictionary nvim_get_namespaces(void) String name; handle_T id; - map_foreach(&namespace_ids, name, id, { + map_foreach(handle_T, &namespace_ids, name, id, { PUT(retval, name.data, INTEGER_OBJ(id)); }) @@ -88,7 +86,7 @@ const char *describe_ns(NS ns_id) { String name; handle_T id; - map_foreach(&namespace_ids, name, id, { + map_foreach(handle_T, &namespace_ids, name, id, { if ((NS)id == ns_id && name.size) { return name.data; } diff --git a/src/nvim/api/extmark.h b/src/nvim/api/extmark.h index a6586e3031..3c979fa4f6 100644 --- a/src/nvim/api/extmark.h +++ b/src/nvim/api/extmark.h @@ -6,7 +6,6 @@ #include "nvim/decoration.h" #include "nvim/macros.h" #include "nvim/map.h" -#include "nvim/map_defs.h" #include "nvim/types.h" EXTERN Map(String, handle_T) namespace_ids INIT(= MAP_INIT); diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 2623c97c9d..bac501ed62 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -122,13 +122,13 @@ #define api_free_window(value) #define api_free_tabpage(value) -EXTERN PMap(handle_T) buffer_handles INIT(= MAP_INIT); -EXTERN PMap(handle_T) window_handles INIT(= MAP_INIT); -EXTERN PMap(handle_T) tabpage_handles INIT(= MAP_INIT); +EXTERN PMap(int) buffer_handles INIT(= MAP_INIT); +EXTERN PMap(int) window_handles INIT(= MAP_INIT); +EXTERN PMap(int) tabpage_handles INIT(= MAP_INIT); -#define handle_get_buffer(h) pmap_get(handle_T)(&buffer_handles, (h)) -#define handle_get_window(h) pmap_get(handle_T)(&window_handles, (h)) -#define handle_get_tabpage(h) pmap_get(handle_T)(&tabpage_handles, (h)) +#define handle_get_buffer(h) pmap_get(int)(&buffer_handles, (h)) +#define handle_get_window(h) pmap_get(int)(&window_handles, (h)) +#define handle_get_tabpage(h) pmap_get(int)(&tabpage_handles, (h)) /// Structure used for saving state for :try /// diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index bd3482c85f..532c3054ab 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -111,7 +111,7 @@ void remote_ui_disconnect(uint64_t channel_id) } UIData *data = ui->data; kv_destroy(data->call_buf); - pmap_del(uint64_t)(&connected_uis, channel_id); + pmap_del(uint64_t)(&connected_uis, channel_id, NULL); ui_detach_impl(ui, channel_id); // Destroy `ui`. -- cgit From 1fe1bb084d0099fc4f9bfdc11189485d0f74b75a Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 19 Dec 2022 16:37:45 +0000 Subject: refactor(options): deprecate nvim[_buf|_win]_[gs]et_option Co-authored-by: zeertzjq Co-authored-by: famiu --- src/nvim/api/deprecated.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++ src/nvim/api/options.c | 216 +-------------------------------------------- src/nvim/api/options.h | 1 + 3 files changed, 223 insertions(+), 214 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 0ca505e7b2..a7e5b32d49 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -8,6 +8,7 @@ #include "nvim/api/buffer.h" #include "nvim/api/deprecated.h" #include "nvim/api/extmark.h" +#include "nvim/api/options.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/api/private/validate.h" @@ -522,3 +523,222 @@ Dictionary nvim_get_option_info(String name, Error *err) { return get_vimoption(name, OPT_GLOBAL, curbuf, curwin, err); } + +/// Sets the global value of an option. +/// +/// @deprecated +/// @param channel_id +/// @param name Option name +/// @param value New option value +/// @param[out] err Error details, if any +void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err) + FUNC_API_SINCE(1) +{ + set_option_to(channel_id, NULL, SREQ_GLOBAL, name, value, err); +} + +/// Gets the global value of an option. +/// +/// @deprecated +/// @param name Option name +/// @param[out] err Error details, if any +/// @return Option value (global) +Object nvim_get_option(String name, Arena *arena, Error *err) + FUNC_API_SINCE(1) +{ + return get_option_from(NULL, SREQ_GLOBAL, name, err); +} + +/// Gets a buffer option value +/// +/// @deprecated +/// @param buffer Buffer handle, or 0 for current buffer +/// @param name Option name +/// @param[out] err Error details, if any +/// @return Option value +Object nvim_buf_get_option(Buffer buffer, String name, Arena *arena, Error *err) + FUNC_API_SINCE(1) +{ + buf_T *buf = find_buffer_by_handle(buffer, err); + + if (!buf) { + return (Object)OBJECT_INIT; + } + + return get_option_from(buf, SREQ_BUF, name, err); +} + +/// Sets a buffer option value. Passing `nil` as value deletes the option (only +/// works if there's a global fallback) +/// +/// @deprecated +/// @param channel_id +/// @param buffer Buffer handle, or 0 for current buffer +/// @param name Option name +/// @param value Option value +/// @param[out] err Error details, if any +void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, String name, Object value, Error *err) + FUNC_API_SINCE(1) +{ + buf_T *buf = find_buffer_by_handle(buffer, err); + + if (!buf) { + return; + } + + set_option_to(channel_id, buf, SREQ_BUF, name, value, err); +} + +/// Gets a window option value +/// +/// @deprecated +/// @param window Window handle, or 0 for current window +/// @param name Option name +/// @param[out] err Error details, if any +/// @return Option value +Object nvim_win_get_option(Window window, String name, Arena *arena, Error *err) + FUNC_API_SINCE(1) +{ + win_T *win = find_window_by_handle(window, err); + + if (!win) { + return (Object)OBJECT_INIT; + } + + return get_option_from(win, SREQ_WIN, name, err); +} + +/// Sets a window option value. Passing `nil` as value deletes the option (only +/// works if there's a global fallback) +/// +/// @deprecated +/// @param channel_id +/// @param window Window handle, or 0 for current window +/// @param name Option name +/// @param value Option value +/// @param[out] err Error details, if any +void nvim_win_set_option(uint64_t channel_id, Window window, String name, Object value, Error *err) + FUNC_API_SINCE(1) +{ + win_T *win = find_window_by_handle(window, err); + + if (!win) { + return; + } + + set_option_to(channel_id, win, SREQ_WIN, name, value, err); +} + +/// Gets the value of a global or local (buffer, window) option. +/// +/// @param from If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer +/// to the window or buffer. +/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF` +/// @param name The option name +/// @param[out] err Details of an error that may have occurred +/// @return the option value +static Object get_option_from(void *from, int type, String name, Error *err) +{ + Object rv = OBJECT_INIT; + + VALIDATE_S(name.size > 0, "option name", "", { + return rv; + }); + + // Return values + int64_t numval; + char *stringval = NULL; + + int flags = get_option_value_strict(name.data, &numval, &stringval, type, from); + VALIDATE_S(flags != 0, "option name", name.data, { + return rv; + }); + + if (flags & SOPT_BOOL) { + rv.type = kObjectTypeBoolean; + rv.data.boolean = numval ? true : false; + } else if (flags & SOPT_NUM) { + rv.type = kObjectTypeInteger; + rv.data.integer = numval; + } else if (flags & SOPT_STRING) { + if (!stringval) { + api_set_error(err, kErrorTypeException, "Failed to get option '%s'", name.data); + return rv; + } + rv.type = kObjectTypeString; + rv.data.string.data = stringval; + rv.data.string.size = strlen(stringval); + } else { + api_set_error(err, kErrorTypeException, "Unknown type for option '%s'", name.data); + } + + return rv; +} + +/// Sets the value of a global or local (buffer, window) option. +/// +/// @param to If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer +/// to the window or buffer. +/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF` +/// @param name The option name +/// @param[out] err Details of an error that may have occurred +static void set_option_to(uint64_t channel_id, void *to, int type, String name, Object value, + Error *err) +{ + VALIDATE_S(name.size > 0, "option name", "", { + return; + }); + + int flags = get_option_value_strict(name.data, NULL, NULL, type, to); + VALIDATE_S(flags != 0, "option name", name.data, { + return; + }); + + if (value.type == kObjectTypeNil) { + if (type == SREQ_GLOBAL) { + api_set_error(err, kErrorTypeException, "Cannot unset option '%s'", name.data); + return; + } else if (!(flags & SOPT_GLOBAL)) { + api_set_error(err, kErrorTypeException, + "Cannot unset option '%s' because it doesn't have a global value", + name.data); + return; + } else { + unset_global_local_option(name.data, to); + return; + } + } + + long numval = 0; + char *stringval = NULL; + + if (flags & SOPT_BOOL) { + VALIDATE(value.type == kObjectTypeBoolean, "Option '%s' value must be Boolean", name.data, { + return; + }); + numval = value.data.boolean; + } else if (flags & SOPT_NUM) { + VALIDATE(value.type == kObjectTypeInteger, "Option '%s' value must be Integer", name.data, { + return; + }); + VALIDATE((value.data.integer <= INT_MAX && value.data.integer >= INT_MIN), + "Option '%s' value is out of range", name.data, { + return; + }); + numval = (int)value.data.integer; + } else { + VALIDATE(value.type == kObjectTypeString, "Option '%s' value must be String", name.data, { + return; + }); + stringval = value.data.string.data; + } + + // For global-win-local options -> setlocal + // For win-local options -> setglobal and setlocal (opt_flags == 0) + const int opt_flags = (type == SREQ_WIN && !(flags & SOPT_GLOBAL)) ? 0 : + (type == SREQ_GLOBAL) ? OPT_GLOBAL : OPT_LOCAL; + + WITH_SCRIPT_CONTEXT(channel_id, { + access_option_value_for(name.data, &numval, &stringval, opt_flags, type, to, false, err); + }); +} diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 2d1b170d2d..6193a5c75b 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -341,218 +341,6 @@ Dictionary nvim_get_option_info2(String name, Dict(option) *opts, Error *err) return get_vimoption(name, scope, buf, win, err); } -/// Sets the global value of an option. -/// -/// @param channel_id -/// @param name Option name -/// @param value New option value -/// @param[out] err Error details, if any -void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err) - FUNC_API_SINCE(1) -{ - set_option_to(channel_id, NULL, SREQ_GLOBAL, name, value, err); -} - -/// Gets the global value of an option. -/// -/// @param name Option name -/// @param[out] err Error details, if any -/// @return Option value (global) -Object nvim_get_option(String name, Arena *arena, Error *err) - FUNC_API_SINCE(1) -{ - return get_option_from(NULL, SREQ_GLOBAL, name, err); -} - -/// Gets a buffer option value -/// -/// @param buffer Buffer handle, or 0 for current buffer -/// @param name Option name -/// @param[out] err Error details, if any -/// @return Option value -Object nvim_buf_get_option(Buffer buffer, String name, Arena *arena, Error *err) - FUNC_API_SINCE(1) -{ - buf_T *buf = find_buffer_by_handle(buffer, err); - - if (!buf) { - return (Object)OBJECT_INIT; - } - - return get_option_from(buf, SREQ_BUF, name, err); -} - -/// Sets a buffer option value. Passing `nil` as value deletes the option (only -/// works if there's a global fallback) -/// -/// @param channel_id -/// @param buffer Buffer handle, or 0 for current buffer -/// @param name Option name -/// @param value Option value -/// @param[out] err Error details, if any -void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, String name, Object value, Error *err) - FUNC_API_SINCE(1) -{ - buf_T *buf = find_buffer_by_handle(buffer, err); - - if (!buf) { - return; - } - - set_option_to(channel_id, buf, SREQ_BUF, name, value, err); -} - -/// Gets a window option value -/// -/// @param window Window handle, or 0 for current window -/// @param name Option name -/// @param[out] err Error details, if any -/// @return Option value -Object nvim_win_get_option(Window window, String name, Arena *arena, Error *err) - FUNC_API_SINCE(1) -{ - win_T *win = find_window_by_handle(window, err); - - if (!win) { - return (Object)OBJECT_INIT; - } - - return get_option_from(win, SREQ_WIN, name, err); -} - -/// Sets a window option value. Passing `nil` as value deletes the option (only -/// works if there's a global fallback) -/// -/// @param channel_id -/// @param window Window handle, or 0 for current window -/// @param name Option name -/// @param value Option value -/// @param[out] err Error details, if any -void nvim_win_set_option(uint64_t channel_id, Window window, String name, Object value, Error *err) - FUNC_API_SINCE(1) -{ - win_T *win = find_window_by_handle(window, err); - - if (!win) { - return; - } - - set_option_to(channel_id, win, SREQ_WIN, name, value, err); -} - -/// Gets the value of a global or local (buffer, window) option. -/// -/// @param from If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer -/// to the window or buffer. -/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF` -/// @param name The option name -/// @param[out] err Details of an error that may have occurred -/// @return the option value -static Object get_option_from(void *from, int type, String name, Error *err) -{ - Object rv = OBJECT_INIT; - - VALIDATE_S(name.size > 0, "option name", "", { - return rv; - }); - - // Return values - int64_t numval; - char *stringval = NULL; - - int flags = get_option_value_strict(name.data, &numval, &stringval, type, from); - VALIDATE_S(flags != 0, "option name", name.data, { - return rv; - }); - - if (flags & SOPT_BOOL) { - rv.type = kObjectTypeBoolean; - rv.data.boolean = numval ? true : false; - } else if (flags & SOPT_NUM) { - rv.type = kObjectTypeInteger; - rv.data.integer = numval; - } else if (flags & SOPT_STRING) { - if (!stringval) { - api_set_error(err, kErrorTypeException, "Failed to get option '%s'", name.data); - return rv; - } - rv.type = kObjectTypeString; - rv.data.string.data = stringval; - rv.data.string.size = strlen(stringval); - } else { - api_set_error(err, kErrorTypeException, "Unknown type for option '%s'", name.data); - } - - return rv; -} - -/// Sets the value of a global or local (buffer, window) option. -/// -/// @param to If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer -/// to the window or buffer. -/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF` -/// @param name The option name -/// @param[out] err Details of an error that may have occurred -void set_option_to(uint64_t channel_id, void *to, int type, String name, Object value, Error *err) -{ - VALIDATE_S(name.size > 0, "option name", "", { - return; - }); - - int flags = get_option_value_strict(name.data, NULL, NULL, type, to); - VALIDATE_S(flags != 0, "option name", name.data, { - return; - }); - - if (value.type == kObjectTypeNil) { - if (type == SREQ_GLOBAL) { - api_set_error(err, kErrorTypeException, "Cannot unset option '%s'", name.data); - return; - } else if (!(flags & SOPT_GLOBAL)) { - api_set_error(err, kErrorTypeException, - "Cannot unset option '%s' because it doesn't have a global value", - name.data); - return; - } else { - unset_global_local_option(name.data, to); - return; - } - } - - long numval = 0; - char *stringval = NULL; - - if (flags & SOPT_BOOL) { - VALIDATE(value.type == kObjectTypeBoolean, "Option '%s' value must be Boolean", name.data, { - return; - }); - numval = value.data.boolean; - } else if (flags & SOPT_NUM) { - VALIDATE(value.type == kObjectTypeInteger, "Option '%s' value must be Integer", name.data, { - return; - }); - VALIDATE((value.data.integer <= INT_MAX && value.data.integer >= INT_MIN), - "Option '%s' value is out of range", name.data, { - return; - }); - numval = (int)value.data.integer; - } else { - VALIDATE(value.type == kObjectTypeString, "Option '%s' value must be String", name.data, { - return; - }); - stringval = value.data.string.data; - } - - // For global-win-local options -> setlocal - // For win-local options -> setglobal and setlocal (opt_flags == 0) - const int opt_flags = (type == SREQ_WIN && !(flags & SOPT_GLOBAL)) ? 0 : - (type == SREQ_GLOBAL) ? OPT_GLOBAL : OPT_LOCAL; - - WITH_SCRIPT_CONTEXT(channel_id, { - access_option_value_for(name.data, &numval, &stringval, opt_flags, type, to, false, err); - }); -} - static getoption_T access_option_value(char *key, long *numval, char **stringval, int opt_flags, bool get, Error *err) { @@ -571,8 +359,8 @@ static getoption_T access_option_value(char *key, long *numval, char **stringval } } -static getoption_T access_option_value_for(char *key, long *numval, char **stringval, int opt_flags, - int opt_type, void *from, bool get, Error *err) +getoption_T access_option_value_for(char *key, long *numval, char **stringval, int opt_flags, + int opt_type, void *from, bool get, Error *err) { bool need_switch = false; switchwin_T switchwin; diff --git a/src/nvim/api/options.h b/src/nvim/api/options.h index 869826e443..7be72d3708 100644 --- a/src/nvim/api/options.h +++ b/src/nvim/api/options.h @@ -3,6 +3,7 @@ #include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" +#include "nvim/option.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/options.h.generated.h" -- cgit From efa9b299a7cb68909e9bcd290e4d12bcb6d0bb03 Mon Sep 17 00:00:00 2001 From: Ibby <33922797+SleepySwords@users.noreply.github.com> Date: Sun, 19 Mar 2023 16:31:08 +1100 Subject: feat(ui): inline virtual text vim-patch:9.0.0067: cannot show virtual text Problem: Cannot show virtual text. Solution: Initial changes for virtual text support, using text properties. https://github.com/vim/vim/commit/7f9969c559b51446632ac7e8f76cde07e7d0078d vim-patch:9.0.0116: virtual text not displayed if 'signcolumn' is "yes" Problem: Virtual text not displayed if 'signcolumn' is "yes". Solution: Set c_extra and c_final to NUL. https://github.com/vim/vim/commit/711483cd1381a4ed848d783ae0a6792d5b04447b Co-authored-by: bfredl --- src/nvim/api/extmark.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index d6f0288f94..dd256a54f0 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -477,6 +477,8 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// - "overlay": display over the specified column, without /// shifting the underlying text. /// - "right_align": display right aligned in the window. +/// - "inline": display at the specified column, and +/// shift the buffer text to the right as needed /// - virt_text_win_col : position the virtual text at a fixed /// window column (starting from the first /// text column) @@ -695,6 +697,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer decor.virt_text_pos = kVTOverlay; } else if (strequal("right_align", str.data)) { decor.virt_text_pos = kVTRightAlign; + } else if (strequal("inline", str.data)) { + decor.virt_text_pos = kVTInline; } else { VALIDATE_S(false, "virt_text_pos", "", { goto error; -- cgit From cfd4fdfea4d0e68ea50ad412b88b5289ded6fd6f Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Tue, 23 May 2023 14:25:10 +0600 Subject: refactor(api): new helper macros Adds new API helper macros `CSTR_AS_OBJ()`, `STATIC_CSTR_AS_OBJ()`, and `STATIC_CSTR_TO_OBJ()`, which cleans up a lot of the current code. These macros will also be used extensively in the upcoming option refactor PRs because then API Objects will be used to get/set options. This PR also modifies pre-existing code to use old API helper macros like `CSTR_TO_OBJ()` to make them cleaner. --- src/nvim/api/autocmd.c | 16 ++++++++-------- src/nvim/api/buffer.c | 2 +- src/nvim/api/command.c | 4 ++-- src/nvim/api/extmark.c | 12 ++++++------ src/nvim/api/options.c | 2 +- src/nvim/api/private/helpers.c | 10 +++++----- src/nvim/api/private/helpers.h | 4 ++++ src/nvim/api/ui.c | 2 +- src/nvim/api/vim.c | 8 ++++---- src/nvim/api/vimscript.c | 10 +++++----- src/nvim/api/win_config.c | 8 ++++---- 11 files changed, 41 insertions(+), 37 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 6ecbff2606..14937cfd8f 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -293,17 +293,17 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) break; case kCallbackFuncref: case kCallbackPartial: - PUT(autocmd_info, "callback", STRING_OBJ(cstr_as_string(callback_to_string(cb)))); + PUT(autocmd_info, "callback", CSTR_AS_OBJ(callback_to_string(cb))); break; default: abort(); } } else { - PUT(autocmd_info, "command", STRING_OBJ(cstr_as_string(xstrdup(ac->exec.callable.cmd)))); + PUT(autocmd_info, "command", CSTR_TO_OBJ(ac->exec.callable.cmd)); } - PUT(autocmd_info, "pattern", STRING_OBJ(cstr_to_string(ap->pat))); - PUT(autocmd_info, "event", STRING_OBJ(cstr_to_string(event_nr2name(event)))); + PUT(autocmd_info, "pattern", CSTR_TO_OBJ(ap->pat)); + PUT(autocmd_info, "event", CSTR_TO_OBJ(event_nr2name(event))); PUT(autocmd_info, "once", BOOLEAN_OBJ(ac->once)); if (ap->buflocal_nr) { @@ -475,7 +475,7 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc } if (patterns.size == 0) { - ADD(patterns, STRING_OBJ(STATIC_CSTR_TO_STRING("*"))); + ADD(patterns, STATIC_CSTR_TO_OBJ("*")); } VALIDATE_R((event_array.size > 0), "event", { @@ -587,7 +587,7 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err) // When we create the autocmds, we want to say that they are all matched, so that's * // but when we clear them, we want to say that we didn't pass a pattern, so that's NUL if (patterns.size == 0) { - ADD(patterns, STRING_OBJ(STATIC_CSTR_TO_STRING(""))); + ADD(patterns, STATIC_CSTR_TO_OBJ("")); } // If we didn't pass any events, that means clear all events. @@ -763,7 +763,7 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err) } if (patterns.size == 0) { - ADD(patterns, STRING_OBJ(STATIC_CSTR_TO_STRING(""))); + ADD(patterns, STATIC_CSTR_TO_OBJ("")); } if (HAS_KEY(opts->data)) { @@ -894,7 +894,7 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob } snprintf((char *)pattern_buflocal, BUFLOCAL_PAT_LEN, "", (int)buf->handle); - ADD(*patterns, STRING_OBJ(cstr_to_string(pattern_buflocal))); + ADD(*patterns, CSTR_TO_OBJ(pattern_buflocal)); } return true; diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 10c684941c..82a62c3192 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -518,7 +518,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In { MAXSIZE_TEMP_ARRAY(scratch, 1); if (replacement.size == 0) { - ADD_C(scratch, STRING_OBJ(STATIC_CSTR_AS_STRING(""))); + ADD_C(scratch, STATIC_CSTR_AS_OBJ("")); replacement = scratch; } diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index b1603c5d6e..6d715bcf46 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -245,7 +245,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) Dictionary filter = ARRAY_DICT_INIT; PUT(filter, "pattern", cmdinfo.cmdmod.cmod_filter_pat ? CSTR_TO_OBJ(cmdinfo.cmdmod.cmod_filter_pat) - : STRING_OBJ(STATIC_CSTR_TO_STRING(""))); + : STATIC_CSTR_TO_OBJ("")); PUT(filter, "force", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_filter_force)); PUT(mods, "filter", DICTIONARY_OBJ(filter)); @@ -438,7 +438,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error break; } - ADD(args, STRING_OBJ(cstr_as_string(data_str))); + ADD(args, CSTR_AS_OBJ(data_str)); } bool argc_valid; diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index d6f0288f94..21b0b811b6 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -106,7 +106,7 @@ bool ns_initialized(uint32_t ns) static Object hl_group_name(int hl_id, bool hl_name) { if (hl_name) { - return STRING_OBJ(cstr_to_string(syn_id2name(hl_id))); + return CSTR_TO_OBJ(syn_id2name(hl_id)); } else { return INTEGER_OBJ(hl_id); } @@ -140,7 +140,7 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict PUT(dict, "hl_eol", BOOLEAN_OBJ(decor->hl_eol)); } if (decor->hl_mode) { - PUT(dict, "hl_mode", STRING_OBJ(cstr_to_string(hl_mode_str[decor->hl_mode]))); + PUT(dict, "hl_mode", CSTR_TO_OBJ(hl_mode_str[decor->hl_mode])); } if (kv_size(decor->virt_text)) { @@ -148,7 +148,7 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict 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))); + ADD(chunk, CSTR_TO_OBJ(vtc->text)); if (vtc->hl_id > 0) { ADD(chunk, hl_group_name(vtc->hl_id, hl_name)); } @@ -160,7 +160,7 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict PUT(dict, "virt_text_win_col", INTEGER_OBJ(decor->col)); } PUT(dict, "virt_text_pos", - STRING_OBJ(cstr_to_string(virt_text_pos_str[decor->virt_text_pos]))); + CSTR_TO_OBJ(virt_text_pos_str[decor->virt_text_pos])); } if (decor->ui_watched) { @@ -177,7 +177,7 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict for (size_t j = 0; j < vt->size; j++) { Array chunk = ARRAY_DICT_INIT; VirtTextChunk *vtc = &vt->items[j]; - ADD(chunk, STRING_OBJ(cstr_to_string(vtc->text))); + ADD(chunk, CSTR_TO_OBJ(vtc->text)); if (vtc->hl_id > 0) { ADD(chunk, hl_group_name(vtc->hl_id, hl_name)); } @@ -191,7 +191,7 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict } if (decor->sign_text) { - PUT(dict, "sign_text", STRING_OBJ(cstr_to_string(decor->sign_text))); + PUT(dict, "sign_text", CSTR_TO_OBJ(decor->sign_text)); } // uncrustify:off diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 6193a5c75b..e18312a6dc 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -188,7 +188,7 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) switch (result) { case gov_string: - rv = STRING_OBJ(cstr_as_string(stringval)); + rv = CSTR_AS_OBJ(stringval); break; case gov_number: rv = INTEGER_OBJ(numval); diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 02060a8950..2544809553 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -660,10 +660,10 @@ static void init_ui_event_metadata(Dictionary *metadata) msgpack_unpacked_destroy(&unpacked); PUT(*metadata, "ui_events", ui_events); Array ui_options = ARRAY_DICT_INIT; - ADD(ui_options, STRING_OBJ(cstr_to_string("rgb"))); + ADD(ui_options, CSTR_TO_OBJ("rgb")); for (UIExtension i = 0; i < kUIExtCount; i++) { if (ui_ext_names[i][0] != '_') { - ADD(ui_options, STRING_OBJ(cstr_to_string(ui_ext_names[i]))); + ADD(ui_options, CSTR_TO_OBJ(ui_ext_names[i])); } } PUT(*metadata, "ui_options", ARRAY_OBJ(ui_options)); @@ -692,17 +692,17 @@ static void init_type_metadata(Dictionary *metadata) Dictionary buffer_metadata = ARRAY_DICT_INIT; PUT(buffer_metadata, "id", INTEGER_OBJ(kObjectTypeBuffer - EXT_OBJECT_TYPE_SHIFT)); - PUT(buffer_metadata, "prefix", STRING_OBJ(cstr_to_string("nvim_buf_"))); + PUT(buffer_metadata, "prefix", CSTR_TO_OBJ("nvim_buf_")); Dictionary window_metadata = ARRAY_DICT_INIT; PUT(window_metadata, "id", INTEGER_OBJ(kObjectTypeWindow - EXT_OBJECT_TYPE_SHIFT)); - PUT(window_metadata, "prefix", STRING_OBJ(cstr_to_string("nvim_win_"))); + PUT(window_metadata, "prefix", CSTR_TO_OBJ("nvim_win_")); Dictionary tabpage_metadata = ARRAY_DICT_INIT; PUT(tabpage_metadata, "id", INTEGER_OBJ(kObjectTypeTabpage - EXT_OBJECT_TYPE_SHIFT)); - PUT(tabpage_metadata, "prefix", STRING_OBJ(cstr_to_string("nvim_tabpage_"))); + PUT(tabpage_metadata, "prefix", CSTR_TO_OBJ("nvim_tabpage_")); PUT(types, "Buffer", DICTIONARY_OBJ(buffer_metadata)); PUT(types, "Window", DICTIONARY_OBJ(window_metadata)); diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index bac501ed62..a9cfaeae22 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -34,6 +34,7 @@ .type = kObjectTypeString, \ .data.string = s }) +#define CSTR_AS_OBJ(s) STRING_OBJ(cstr_as_string(s)) #define CSTR_TO_OBJ(s) STRING_OBJ(cstr_to_string(s)) #define BUFFER_OBJ(s) ((Object) { \ @@ -103,6 +104,9 @@ .data = xmemdupz(s, sizeof(s) - 1), \ .size = sizeof(s) - 1 }) +#define STATIC_CSTR_AS_OBJ(s) STRING_OBJ(STATIC_CSTR_AS_STRING(s)) +#define STATIC_CSTR_TO_OBJ(s) STRING_OBJ(STATIC_CSTR_TO_STRING(s)) + // Helpers used by the generated msgpack-rpc api wrappers #define api_init_boolean #define api_init_integer diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 532c3054ab..e98c589189 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -795,7 +795,7 @@ void remote_ui_put(UI *ui, const char *cell) UIData *data = ui->data; data->client_col++; Array args = data->call_buf; - ADD_C(args, STRING_OBJ(cstr_as_string((char *)cell))); + ADD_C(args, CSTR_AS_OBJ((char *)cell)); push_call(ui, "put", args); } diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index d47f47e638..36163859eb 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -531,7 +531,7 @@ static void find_runtime_cb(char *fname, void *cookie) { Array *rv = (Array *)cookie; if (fname != NULL) { - ADD(*rv, STRING_OBJ(cstr_to_string(fname))); + ADD(*rv, CSTR_TO_OBJ(fname)); } } @@ -1383,7 +1383,7 @@ Dictionary nvim_get_mode(void) get_mode(modestr); bool blocked = input_blocking(); - PUT(rv, "mode", STRING_OBJ(cstr_to_string(modestr))); + PUT(rv, "mode", CSTR_TO_OBJ(modestr)); PUT(rv, "blocking", BOOLEAN_OBJ(blocked)); return rv; @@ -1926,7 +1926,7 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Arena *arena, E } ret = arena_array(arena, 3); size_t off = g->line_offset[(size_t)row] + (size_t)col; - ADD_C(ret, STRING_OBJ(cstr_as_string((char *)g->chars[off]))); + ADD_C(ret, CSTR_AS_OBJ((char *)g->chars[off])); int attr = g->attrs[off]; ADD_C(ret, DICTIONARY_OBJ(hl_get_attr_by_id(attr, true, arena, err))); // will not work first time @@ -2035,7 +2035,7 @@ Array nvim_get_mark(String name, Dictionary opts, Error *err) ADD(rv, INTEGER_OBJ(row)); ADD(rv, INTEGER_OBJ(col)); ADD(rv, INTEGER_OBJ(bufnr)); - ADD(rv, STRING_OBJ(cstr_to_string(filename))); + ADD(rv, CSTR_TO_OBJ(filename)); if (allocated) { xfree(filename); diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 208aa165c9..1a67be8860 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -502,7 +502,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E }; err_dict.items[0] = (KeyValuePair) { .key = STATIC_CSTR_TO_STRING("message"), - .value = STRING_OBJ(cstr_to_string(east.err.msg)), + .value = CSTR_TO_OBJ(east.err.msg), }; if (east.err.arg == NULL) { err_dict.items[1] = (KeyValuePair) { @@ -539,7 +539,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E chunk_arr.items[0] = INTEGER_OBJ((Integer)chunk.start.line); chunk_arr.items[1] = INTEGER_OBJ((Integer)chunk.start.col); chunk_arr.items[2] = INTEGER_OBJ((Integer)chunk.end_col); - chunk_arr.items[3] = STRING_OBJ(cstr_to_string(chunk.group)); + chunk_arr.items[3] = CSTR_TO_OBJ(chunk.group); hl.items[i] = ARRAY_OBJ(chunk_arr); } ret.items[ret.size++] = (KeyValuePair) { @@ -616,7 +616,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E kv_drop(ast_conv_stack, 1); ret_node->items[ret_node->size++] = (KeyValuePair) { .key = STATIC_CSTR_TO_STRING("type"), - .value = STRING_OBJ(cstr_to_string(east_node_type_tab[node->type])), + .value = CSTR_TO_OBJ(east_node_type_tab[node->type]), }; Array start_array = { .items = xmalloc(2 * sizeof(start_array.items[0])), @@ -701,11 +701,11 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E case kExprNodeComparison: ret_node->items[ret_node->size++] = (KeyValuePair) { .key = STATIC_CSTR_TO_STRING("cmp_type"), - .value = STRING_OBJ(cstr_to_string(eltkn_cmp_type_tab[node->data.cmp.type])), + .value = CSTR_TO_OBJ(eltkn_cmp_type_tab[node->data.cmp.type]), }; ret_node->items[ret_node->size++] = (KeyValuePair) { .key = STATIC_CSTR_TO_STRING("ccs_strategy"), - .value = STRING_OBJ(cstr_to_string(ccs_tab[node->data.cmp.ccs])), + .value = CSTR_TO_OBJ(ccs_tab[node->data.cmp.ccs]), }; ret_node->items[ret_node->size++] = (KeyValuePair) { .key = STATIC_CSTR_TO_STRING("invert"), diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index c267fee39a..8e4fbb6779 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -267,7 +267,7 @@ Dictionary nvim_win_get_config(Window window, Error *err) PUT(rv, "bufpos", ARRAY_OBJ(pos)); } } - PUT(rv, "anchor", STRING_OBJ(cstr_to_string(float_anchor_str[config->anchor]))); + PUT(rv, "anchor", CSTR_TO_OBJ(float_anchor_str[config->anchor])); PUT(rv, "row", FLOAT_OBJ(config->row)); PUT(rv, "col", FLOAT_OBJ(config->col)); PUT(rv, "zindex", INTEGER_OBJ(config->zindex)); @@ -283,7 +283,7 @@ Dictionary nvim_win_get_config(Window window, Error *err) char *hi_name = syn_id2name(hi_id); if (hi_name[0]) { ADD(tuple, STRING_OBJ(s)); - ADD(tuple, STRING_OBJ(cstr_to_string(hi_name))); + ADD(tuple, CSTR_TO_OBJ(hi_name)); ADD(border, ARRAY_OBJ(tuple)); } else { ADD(border, STRING_OBJ(s)); @@ -297,7 +297,7 @@ Dictionary nvim_win_get_config(Window window, Error *err) Array tuple = ARRAY_DICT_INIT; ADD(tuple, CSTR_TO_OBJ(title_datas.items[i].text)); if (title_datas.items[i].hl_id > 0) { - ADD(tuple, STRING_OBJ(cstr_to_string(syn_id2name(title_datas.items[i].hl_id)))); + ADD(tuple, CSTR_TO_OBJ(syn_id2name(title_datas.items[i].hl_id))); } ADD(titles, ARRAY_OBJ(tuple)); } @@ -317,7 +317,7 @@ Dictionary nvim_win_get_config(Window window, Error *err) const char *rel = (wp->w_floating && !config->external ? float_relative_str[config->relative] : ""); - PUT(rv, "relative", STRING_OBJ(cstr_to_string(rel))); + PUT(rv, "relative", CSTR_TO_OBJ(rel)); return rv; } -- cgit From e41b2e34b46a806b0fc59914263f8f4af9ac62f1 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 28 May 2023 11:09:25 +0800 Subject: test(extmarks): add test for virt_text_hide with 'smoothscroll' (#23791) --- src/nvim/api/extmark.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 299413e510..aca290494b 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -483,8 +483,9 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// window column (starting from the first /// text column) /// - virt_text_hide : hide the virtual text when the background -/// text is selected or hidden due to -/// horizontal scroll 'nowrap' +/// text is selected or hidden because of +/// scrolling with 'nowrap' or 'smoothscroll'. +/// Currently only affects "overlay" virt_text. /// - hl_mode : control how highlights are combined with the /// highlights of the text. Currently only affects /// virt_text highlights, but might affect `hl_group` -- cgit From a3751f5de22f7780d25cca77b23e690915a789a9 Mon Sep 17 00:00:00 2001 From: Folke Lemaitre Date: Thu, 1 Jun 2023 11:44:08 +0200 Subject: fix(api): dont change curwin for nvim_win_set_height --- src/nvim/api/window.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index abe11e6b72..bc6d40acc3 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -167,13 +167,8 @@ void nvim_win_set_height(Window window, Integer height, Error *err) return; } - win_T *savewin = curwin; - curwin = win; - curbuf = curwin->w_buffer; try_start(); - win_setheight((int)height); - curwin = savewin; - curbuf = curwin->w_buffer; + win_setheight_win((int)height, win); try_end(err); } -- cgit From 1ff4562502e146d6da051b1adae925197b418493 Mon Sep 17 00:00:00 2001 From: Folke Lemaitre Date: Thu, 1 Jun 2023 12:42:06 +0200 Subject: fix(api): dont change curwin for nvim_win_set_width --- src/nvim/api/window.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index bc6d40acc3..c021fec220 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -209,13 +209,8 @@ void nvim_win_set_width(Window window, Integer width, Error *err) return; } - win_T *savewin = curwin; - curwin = win; - curbuf = curwin->w_buffer; try_start(); - win_setwidth((int)width); - curwin = savewin; - curbuf = curwin->w_buffer; + win_setwidth_win((int)width, win); try_end(err); } -- cgit From aa130d0c7ea69a05330d0b054b414cc3a15dac45 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:59:58 +0200 Subject: docs: small fixes (#23619) Co-authored-by: Evgeni Chasnovski Co-authored-by: Gustavo Ferreira Co-authored-by: Kai Moschcau Co-authored-by: Lampros --- src/nvim/api/autocmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 14937cfd8f..0e06594663 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -347,7 +347,7 @@ cleanup: /// vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, { /// pattern = {"*.c", "*.h"}, /// callback = function(ev) -/// print(string.format('event fired: %s', vim.inspect(ev))) +/// print(string.format('event fired: \%s', vim.inspect(ev))) /// end /// }) /// -- cgit From 0e01e815520ead73b13277b68306cf03a2196ca5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 3 Jun 2023 18:44:08 +0800 Subject: fix(folds): allow overlay virtual text on folded line (#23892) Also always check for fi_level before fi_lines. --- src/nvim/api/vim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 36163859eb..4722195fe4 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2180,7 +2180,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * wp->w_cursorline = win_cursorline_standout(wp) ? wp->w_cursor.lnum : 0; if (wp->w_p_cul) { - if (statuscol.foldinfo.fi_level > 0 && statuscol.foldinfo.fi_lines > 0) { + if (statuscol.foldinfo.fi_level != 0 && statuscol.foldinfo.fi_lines > 0) { wp->w_cursorline = statuscol.foldinfo.fi_lnum; } statuscol.use_cul = lnum == wp->w_cursorline && (wp->w_p_culopt_flags & CULOPT_NBR); -- cgit From 981acc2922ce9a5f214ba14acbb1e444748855f2 Mon Sep 17 00:00:00 2001 From: Ricky Zhou Date: Thu, 1 Jun 2023 02:15:14 -0700 Subject: fix(ui): propagate line wrapping state on grid_line events This fixes the TUI's line-wrapping behavior, which was broken with the migration to the msgpack-based UI protocol (see https://github.com/neovim/neovim/issues/7369#issuecomment-1571812273). --- src/nvim/api/ui.c | 17 +++++++++++++---- src/nvim/api/ui_events.in.h | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index e98c589189..861ce100cd 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -73,6 +73,11 @@ static void mpack_uint(char **buf, uint32_t val) } } +static void mpack_bool(char **buf, bool val) +{ + mpack_w(buf, 0xc2 | val); +} + static void mpack_array(char **buf, uint32_t len) { if (len < 0x10) { @@ -809,7 +814,7 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int data->ncalls++; char **buf = &data->buf_wptr; - mpack_array(buf, 4); + mpack_array(buf, 5); mpack_uint(buf, (uint32_t)grid); mpack_uint(buf, (uint32_t)row); mpack_uint(buf, (uint32_t)startcol); @@ -823,17 +828,20 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int repeat++; if (i == ncells - 1 || attrs[i] != attrs[i + 1] || strcmp(chunk[i], chunk[i + 1]) != 0) { - if (UI_BUF_SIZE - BUF_POS(data) < 2 * (1 + 2 + sizeof(schar_T) + 5 + 5)) { + if (UI_BUF_SIZE - BUF_POS(data) < 2 * (1 + 2 + sizeof(schar_T) + 5 + 5) + 1) { // close to overflowing the redraw buffer. finish this event, // flush, and start a new "grid_line" event at the current position. // For simplicity leave place for the final "clear" element // as well, hence the factor of 2 in the check. mpack_w2(&lenpos, nelem); + + // We only ever set the wrap field on the final "grid_line" event for the line. + mpack_bool(buf, false); remote_ui_flush_buf(ui); prepare_call(ui, "grid_line"); data->ncalls++; - mpack_array(buf, 4); + mpack_array(buf, 5); mpack_uint(buf, (uint32_t)grid); mpack_uint(buf, (uint32_t)row); mpack_uint(buf, (uint32_t)startcol + (uint32_t)i - repeat + 1); @@ -865,9 +873,10 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int mpack_uint(buf, (uint32_t)(clearcol - endcol)); } mpack_w2(&lenpos, nelem); + mpack_bool(buf, flags & kLineFlagWrap); if (data->ncells_pending > 500) { - // pass of cells to UI to let it start processing them + // pass off cells to UI to let it start processing them remote_ui_flush_buf(ui); } } else { diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index b93f521ca3..fc70215352 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -82,7 +82,7 @@ void grid_clear(Integer grid) FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL; void grid_cursor_goto(Integer grid, Integer row, Integer col) FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_COMPOSITOR_IMPL; -void grid_line(Integer grid, Integer row, Integer col_start, Array data) +void grid_line(Integer grid, Integer row, Integer col_start, Array data, Boolean wrap) FUNC_API_SINCE(5) FUNC_API_REMOTE_ONLY FUNC_API_CLIENT_IMPL; void grid_scroll(Integer grid, Integer top, Integer bot, Integer left, Integer right, Integer rows, Integer cols) -- cgit From 175e5c8b96fe0756040fcb31f46d9c97b3957776 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Tue, 6 Jun 2023 20:18:55 +0600 Subject: refactor(api): remove `BOOL` macro #23936 Remove redundant `BOOL` macro that does the same thing as `BOOLEAN_OBJ`. --- src/nvim/api/private/helpers.h | 1 - 1 file changed, 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index a9cfaeae22..8410251514 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -20,7 +20,6 @@ #define BOOLEAN_OBJ(b) ((Object) { \ .type = kObjectTypeBoolean, \ .data.boolean = b }) -#define BOOL(b) BOOLEAN_OBJ(b) #define INTEGER_OBJ(i) ((Object) { \ .type = kObjectTypeInteger, \ -- cgit From b3d5138fd0066fda26ef7724a542ae45eb42fc84 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Wed, 7 Jun 2023 06:05:16 +0600 Subject: refactor(options): remove `getoption_T` and introduce `OptVal` (#23850) Removes the `getoption_T` struct and also introduces the `OptVal` struct to unify the methods of getting/setting different option value types. This is the first of many PRs to reduce code duplication in the Vim option code as well as to make options easier to maintain. It also increases the flexibility and extensibility of options. Which opens the door for things like Array and Dictionary options. --- src/nvim/api/deprecated.c | 11 +- src/nvim/api/options.c | 278 ++++++++++++++++++++++++++--------------- src/nvim/api/private/helpers.h | 2 +- src/nvim/api/vim.c | 8 +- 4 files changed, 189 insertions(+), 110 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index a7e5b32d49..83c33db5d3 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -709,14 +709,13 @@ static void set_option_to(uint64_t channel_id, void *to, int type, String name, } } - long numval = 0; - char *stringval = NULL; + OptVal optval = NIL_OPTVAL; if (flags & SOPT_BOOL) { VALIDATE(value.type == kObjectTypeBoolean, "Option '%s' value must be Boolean", name.data, { return; }); - numval = value.data.boolean; + optval = BOOLEAN_OPTVAL(value.data.boolean); } else if (flags & SOPT_NUM) { VALIDATE(value.type == kObjectTypeInteger, "Option '%s' value must be Integer", name.data, { return; @@ -725,12 +724,12 @@ static void set_option_to(uint64_t channel_id, void *to, int type, String name, "Option '%s' value is out of range", name.data, { return; }); - numval = (int)value.data.integer; + optval = NUMBER_OPTVAL(value.data.integer); } else { VALIDATE(value.type == kObjectTypeString, "Option '%s' value must be String", name.data, { return; }); - stringval = value.data.string.data; + optval = STRING_OPTVAL(value.data.string); } // For global-win-local options -> setlocal @@ -739,6 +738,6 @@ static void set_option_to(uint64_t channel_id, void *to, int type, String name, (type == SREQ_GLOBAL) ? OPT_GLOBAL : OPT_LOCAL; WITH_SCRIPT_CONTEXT(channel_id, { - access_option_value_for(name.data, &numval, &stringval, opt_flags, type, to, false, err); + set_option_value_for(name.data, optval, opt_flags, type, to, err); }); } diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index e18312a6dc..ed13e51e90 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -113,10 +113,10 @@ static buf_T *do_ft_buf(char *filetype, aco_save_T *aco, Error *err) aucmd_prepbuf(aco, ftbuf); TRY_WRAP(err, { - set_option_value("bufhidden", 0L, "hide", OPT_LOCAL); - set_option_value("buftype", 0L, "nofile", OPT_LOCAL); - set_option_value("swapfile", 0L, NULL, OPT_LOCAL); - set_option_value("modeline", 0L, NULL, OPT_LOCAL); // 'nomodeline' + set_option_value("bufhidden", STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL); + set_option_value("buftype", STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL); + set_option_value("swapfile", BOOLEAN_OPTVAL(false), OPT_LOCAL); + set_option_value("modeline", BOOLEAN_OPTVAL(false), OPT_LOCAL); // 'nomodeline' ftbuf->b_p_ft = xstrdup(filetype); do_filetype_autocmd(ftbuf, false); @@ -125,6 +125,54 @@ static buf_T *do_ft_buf(char *filetype, aco_save_T *aco, Error *err) return ftbuf; } +/// Consume an OptVal and convert it to an API Object. +static Object optval_as_object(OptVal o) +{ + switch (o.type) { + case kOptValTypeNil: + return NIL; + case kOptValTypeBoolean: + switch (o.data.boolean) { + case kFalse: + case kTrue: + return BOOLEAN_OBJ(o.data.boolean); + case kNone: + return NIL; + default: + abort(); + } + case kOptValTypeNumber: + return INTEGER_OBJ(o.data.number); + case kOptValTypeString: + return STRING_OBJ(o.data.string); + default: + abort(); + } +} + +/// Consume an API Object and convert it to an OptVal. +static OptVal object_as_optval(Object o, Error *err) +{ + switch (o.type) { + case kObjectTypeNil: + return NIL_OPTVAL; + break; + case kObjectTypeBoolean: + return BOOLEAN_OPTVAL(o.data.boolean); + break; + case kObjectTypeInteger: + return NUMBER_OPTVAL(o.data.integer); + break; + case kObjectTypeString: + return STRING_OPTVAL(o.data.string); + break; + default: + // Some Object types don't have an OptVal equivalent. Error out in those cases. + api_set_error(err, kErrorTypeException, "Invalid option value"); + return NIL_OPTVAL; + } +} + /// Gets the value of an option. The behavior of this function matches that of /// |:set|: the local value of an option is returned if it exists; otherwise, /// the global value is returned. Local values always correspond to the current @@ -147,6 +195,7 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) FUNC_API_SINCE(9) { Object rv = OBJECT_INIT; + OptVal value = NIL_OPTVAL; int scope = 0; int opt_type = SREQ_GLOBAL; @@ -154,14 +203,14 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) char *filetype = NULL; if (!validate_option_value_args(opts, &scope, &opt_type, &from, &filetype, err)) { - return rv; + goto err; } aco_save_T aco; buf_T *ftbuf = do_ft_buf(filetype, &aco, err); if (ERROR_SET(err)) { - return rv; + goto err; } if (ftbuf != NULL) { @@ -169,10 +218,8 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) from = ftbuf; } - long numval = 0; - char *stringval = NULL; - getoption_T result = access_option_value_for(name.data, &numval, &stringval, scope, opt_type, - from, true, err); + bool hidden; + value = get_option_value_for(name.data, NULL, scope, &hidden, opt_type, from, err); if (ftbuf != NULL) { // restore curwin/curbuf and a few other things @@ -183,35 +230,16 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) } if (ERROR_SET(err)) { - return rv; + goto err; } - switch (result) { - case gov_string: - rv = CSTR_AS_OBJ(stringval); - break; - case gov_number: - rv = INTEGER_OBJ(numval); - break; - case gov_bool: - switch (numval) { - case 0: - case 1: - rv = BOOLEAN_OBJ(numval); - break; - default: - // Boolean options that return something other than 0 or 1 should return nil. Currently this - // only applies to 'autoread' which uses -1 as a local value to indicate "unset" - rv = NIL; - break; - } - break; - default: - VALIDATE_S(false, "option", name.data, { - return rv; - }); - } + VALIDATE_S(!hidden && value.type != kOptValTypeNil, "option", name.data, { + goto err; + }); + return optval_as_object(value); +err: + optval_free(value); return rv; } @@ -253,30 +281,19 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict( } } - long numval = 0; - char *stringval = NULL; + OptVal optval = object_as_optval(value, err); + + // Handle invalid option value type. + if (ERROR_SET(err)) { + api_clear_error(err); - switch (value.type) { - case kObjectTypeInteger: - numval = (long)value.data.integer; - break; - case kObjectTypeBoolean: - numval = value.data.boolean ? 1 : 0; - break; - case kObjectTypeString: - stringval = value.data.string.data; - break; - case kObjectTypeNil: - scope |= OPT_CLEAR; - break; - default: VALIDATE_EXP(false, name.data, "Integer/Boolean/String", api_typename(value.type), { return; }); } WITH_SCRIPT_CONTEXT(channel_id, { - access_option_value_for(name.data, &numval, &stringval, scope, opt_type, to, false, err); + set_option_value_for(name.data, optval, scope, opt_type, to, err); }); } @@ -341,72 +358,135 @@ Dictionary nvim_get_option_info2(String name, Dict(option) *opts, Error *err) return get_vimoption(name, scope, buf, win, err); } -static getoption_T access_option_value(char *key, long *numval, char **stringval, int opt_flags, - bool get, Error *err) +/// Switch current context to get/set option value for window/buffer. +/// +/// @param[out] ctx Current context. switchwin_T for window and aco_save_T for buffer. +/// @param[in] opt_type Option type. See SREQ_* in option_defs.h. +/// @param[in] from Target buffer/window. +/// @param[out] err Error message, if any. +/// +/// @return true if context was switched, false otherwise. +static bool switch_option_context(void *const ctx, int opt_type, void *const from, Error *err) { - if (get) { - return get_option_value(key, numval, stringval, NULL, opt_flags); - } else { - const char *errmsg; - if ((errmsg = set_option_value(key, *numval, *stringval, opt_flags))) { + switch (opt_type) { + case SREQ_WIN: { + win_T *const win = (win_T *)from; + switchwin_T *const switchwin = (switchwin_T *)ctx; + + if (win == curwin) { + return false; + } + + if (switch_win_noblock(switchwin, win, win_find_tabpage(win), true) + == FAIL) { + restore_win_noblock(switchwin, true); + if (try_end(err)) { - return 0; + return false; } + api_set_error(err, kErrorTypeException, "Problem while switching windows"); + return false; + } + return true; + } + case SREQ_BUF: { + buf_T *const buf = (buf_T *)from; + aco_save_T *const aco = (aco_save_T *)ctx; - api_set_error(err, kErrorTypeException, "%s", errmsg); + if (buf == curbuf) { + return false; } - return 0; + aucmd_prepbuf(aco, buf); + return true; + } + case SREQ_GLOBAL: + return false; + default: + abort(); // This should never happen. } } -getoption_T access_option_value_for(char *key, long *numval, char **stringval, int opt_flags, - int opt_type, void *from, bool get, Error *err) +/// Restore context after getting/setting option for window/buffer. See switch_option_context() for +/// params. +static void restore_option_context(void *const ctx, const int opt_type) { - bool need_switch = false; - switchwin_T switchwin; - aco_save_T aco; - getoption_T result = 0; - - try_start(); switch (opt_type) { case SREQ_WIN: - need_switch = (win_T *)from != curwin; - if (need_switch) { - if (switch_win_noblock(&switchwin, (win_T *)from, win_find_tabpage((win_T *)from), true) - == FAIL) { - restore_win_noblock(&switchwin, true); - if (try_end(err)) { - return result; - } - api_set_error(err, kErrorTypeException, "Problem while switching windows"); - return result; - } - } - result = access_option_value(key, numval, stringval, opt_flags, get, err); - if (need_switch) { - restore_win_noblock(&switchwin, true); - } + restore_win_noblock((switchwin_T *)ctx, true); break; case SREQ_BUF: - need_switch = (buf_T *)from != curbuf; - if (need_switch) { - aucmd_prepbuf(&aco, (buf_T *)from); - } - result = access_option_value(key, numval, stringval, opt_flags, get, err); - if (need_switch) { - aucmd_restbuf(&aco); - } + aucmd_restbuf((aco_save_T *)ctx); break; case SREQ_GLOBAL: - result = access_option_value(key, numval, stringval, opt_flags, get, err); break; + default: + abort(); // This should never happen. + } +} + +/// Get option value for buffer / window. +/// +/// @param[in] name Option name. +/// @param[out] flagsp Set to the option flags (P_xxxx) (if not NULL). +/// @param[in] scope Option scope (can be OPT_LOCAL, OPT_GLOBAL or a combination). +/// @param[out] hidden Whether option is hidden. +/// @param[in] opt_type Option type. See SREQ_* in option_defs.h. +/// @param[in] from Target buffer/window. +/// @param[out] err Error message, if any. +/// +/// @return Option value. Must be freed by caller. +OptVal get_option_value_for(const char *const name, uint32_t *flagsp, int scope, bool *hidden, + const int opt_type, void *const from, Error *err) +{ + switchwin_T switchwin; + aco_save_T aco; + void *ctx = opt_type == SREQ_WIN ? (void *)&switchwin + : (opt_type == SREQ_BUF ? (void *)&aco : NULL); + + bool switched = switch_option_context(ctx, opt_type, from, err); + if (ERROR_SET(err)) { + return NIL_OPTVAL; + } + + OptVal retv = get_option_value(name, flagsp, scope, hidden); + + if (switched) { + restore_option_context(ctx, opt_type); } + return retv; +} + +/// Set option value for buffer / window. +/// +/// @param[in] name Option name. +/// @param[in] value Option value. +/// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both). +/// If OPT_CLEAR is set, the value of the option +/// is cleared (the exact semantics of this depend +/// on the option). +/// @param[in] opt_type Option type. See SREQ_* in option_defs.h. +/// @param[in] from Target buffer/window. +/// @param[out] err Error message, if any. +void set_option_value_for(const char *const name, OptVal value, const int opt_flags, + const int opt_type, void *const from, Error *err) +{ + switchwin_T switchwin; + aco_save_T aco; + void *ctx = opt_type == SREQ_WIN ? (void *)&switchwin + : (opt_type == SREQ_BUF ? (void *)&aco : NULL); + + bool switched = switch_option_context(ctx, opt_type, from, err); if (ERROR_SET(err)) { - return result; + return; } - try_end(err); + const char *const errmsg = set_option_value(name, value, opt_flags); + if (errmsg) { + api_set_error(err, kErrorTypeException, "%s", errmsg); + } - return result; + if (switched) { + restore_option_context(ctx, opt_type); + } } diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 8410251514..3887a11dd1 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -94,7 +94,7 @@ #define cbuf_as_string(d, s) ((String) { .data = d, .size = s }) -#define STATIC_CSTR_AS_STRING(s) ((String) { .data = s, .size = sizeof(s) - 1 }) +#define STATIC_CSTR_AS_STRING(s) ((String) { .data = s, .size = sizeof("" s) - 1 }) /// Create a new String instance, putting data in allocated memory /// diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 4722195fe4..d93af6a2a4 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -910,10 +910,10 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err) if (scratch) { aco_save_T aco; aucmd_prepbuf(&aco, buf); - set_option_value("bufhidden", 0L, "hide", OPT_LOCAL); - set_option_value("buftype", 0L, "nofile", OPT_LOCAL); - set_option_value("swapfile", 0L, NULL, OPT_LOCAL); - set_option_value("modeline", 0L, NULL, OPT_LOCAL); // 'nomodeline' + set_option_value("bufhidden", STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL); + set_option_value("buftype", STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL); + set_option_value("swapfile", BOOLEAN_OPTVAL(false), OPT_LOCAL); + set_option_value("modeline", BOOLEAN_OPTVAL(false), OPT_LOCAL); // 'nomodeline' aucmd_restbuf(&aco); } return buf->b_fnum; -- cgit From 0e0a166a0cc5a2dc199136e313e58c27bfb91977 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 7 Jun 2023 09:00:55 +0800 Subject: refactor(api): adjust errors for setting options (#23942) --- src/nvim/api/options.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index ed13e51e90..b9a41adc3b 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -151,24 +151,19 @@ static Object optval_as_object(OptVal o) } /// Consume an API Object and convert it to an OptVal. -static OptVal object_as_optval(Object o, Error *err) +static OptVal object_as_optval(Object o, bool *error) { switch (o.type) { case kObjectTypeNil: return NIL_OPTVAL; - break; case kObjectTypeBoolean: return BOOLEAN_OPTVAL(o.data.boolean); - break; case kObjectTypeInteger: return NUMBER_OPTVAL(o.data.integer); - break; case kObjectTypeString: return STRING_OPTVAL(o.data.string); - break; default: - // Some Object types don't have an OptVal equivalent. Error out in those cases. - api_set_error(err, kErrorTypeException, "Invalid option value"); + *error = true; return NIL_OPTVAL; } } @@ -281,13 +276,13 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict( } } - OptVal optval = object_as_optval(value, err); + bool error = false; + OptVal optval = object_as_optval(value, &error); // Handle invalid option value type. - if (ERROR_SET(err)) { - api_clear_error(err); - - VALIDATE_EXP(false, name.data, "Integer/Boolean/String", api_typename(value.type), { + if (error) { + // Don't use `name` in the error message here, because `name` can be any String. + VALIDATE_EXP(false, "value", "Integer/Boolean/String", api_typename(value.type), { return; }); } -- cgit From 42bbc4fabcf948ac6b8798b8992bcba1fc1d3e59 Mon Sep 17 00:00:00 2001 From: bfredl Date: Sun, 28 May 2023 12:09:52 +0200 Subject: feat(api): support abbreviations in nvim_set_keymap closes #19198 --- src/nvim/api/vim.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index d93af6a2a4..4bbbf644a8 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1420,6 +1420,7 @@ ArrayOf(Dictionary) nvim_get_keymap(String mode) /// @param channel_id /// @param mode Mode short-name (map command prefix: "n", "i", "v", "x", …) /// or "!" for |:map!|, or empty string for |:map|. +/// "ia", "ca" or "!a" for abbreviation in insert mode, cmdline mode, or both, respectively /// @param lhs Left-hand-side |{lhs}| of the mapping. /// @param rhs Right-hand-side |{rhs}| of the mapping. /// @param opts Optional parameters map: Accepts all |:map-arguments| as keys except ||, -- cgit From b6d2f49b4536f89cf2428d1f214468aa5fb21788 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 10 Jun 2023 10:44:31 +0800 Subject: test: more tests for nvim_{set,del}_keymap with abbreviation (#23970) --- src/nvim/api/vim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 4bbbf644a8..62b4fd9764 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1420,7 +1420,7 @@ ArrayOf(Dictionary) nvim_get_keymap(String mode) /// @param channel_id /// @param mode Mode short-name (map command prefix: "n", "i", "v", "x", …) /// or "!" for |:map!|, or empty string for |:map|. -/// "ia", "ca" or "!a" for abbreviation in insert mode, cmdline mode, or both, respectively +/// "ia", "ca" or "!a" for abbreviation in Insert mode, Cmdline mode, or both, respectively /// @param lhs Left-hand-side |{lhs}| of the mapping. /// @param rhs Right-hand-side |{rhs}| of the mapping. /// @param opts Optional parameters map: Accepts all |:map-arguments| as keys except ||, -- cgit From 0eb02ea90a5a7c2e35bfcf99b701a28ff2901b4b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 12 Jun 2023 20:08:08 +0800 Subject: docs: various clarifications (#23999) Close #18907 Close #20314 Close #23749 --- src/nvim/api/vim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 62b4fd9764..368bb866d7 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1427,7 +1427,7 @@ ArrayOf(Dictionary) nvim_get_keymap(String mode) /// values are booleans (default false). Also: /// - "noremap" non-recursive mapping |:noremap| /// - "desc" human-readable description. -/// - "callback" Lua function called when the mapping is executed. +/// - "callback" Lua function called in place of {rhs}. /// - "replace_keycodes" (boolean) When "expr" is true, replace keycodes in the /// resulting string (see |nvim_replace_termcodes()|). Returning nil from the Lua /// "callback" is equivalent to returning an empty string. -- cgit From cee981bf09c81ab4b2fe6facf45076ea4bac46a5 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 19 Jun 2023 02:24:44 -0700 Subject: docs #22363 Co-authored by: zeertzjq Co-authored by: Steven Todd McIntyre II <114119064+stmii@users.noreply.github.com> Co-authored by: nobe4 - docs: mention --luadev-mod to run with lua runtime files When changing a lua file in the ./runtime folder, a new contributor might expect changes to be applied to the built Neovim binary. --- src/nvim/api/window.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index c021fec220..97bf0f377a 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -57,6 +57,8 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err) /// (different windows showing the same buffer have independent cursor /// positions). |api-indexing| /// +/// @see |getcurpos()| +/// /// @param window Window handle, or 0 for current window /// @param[out] err Error details, if any /// @return (row, col) tuple -- cgit From 0d149bb186390c3e40fb693050d0c30cddc8c7c5 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 19 Jun 2023 14:40:53 +0200 Subject: fix(docs): the runtimepath is not the runtime path --- src/nvim/api/vim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 368bb866d7..a6f98a1915 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -487,7 +487,7 @@ Integer nvim_strwidth(String text, Error *err) return (Integer)mb_string2cells(text.data); } -/// Gets the paths contained in 'runtimepath'. +/// Gets the paths contained in |runtime-search-path|. /// /// @return List of paths ArrayOf(String) nvim_list_runtime_paths(Error *err) -- cgit From a9cd8467cbd54035e7814b862054c828467c2ce2 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 22 Jun 2023 13:59:57 +0800 Subject: fix(api): wrong nvim_buf_set_extmark error for invalid hl_mode --- src/nvim/api/extmark.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index aca290494b..1946d77846 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -701,7 +701,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } else if (strequal("inline", str.data)) { decor.virt_text_pos = kVTInline; } else { - VALIDATE_S(false, "virt_text_pos", "", { + VALIDATE_S(false, "virt_text_pos", str.data, { goto error; }); } @@ -719,7 +719,11 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer OPTION_TO_BOOL(decor.virt_text_hide, virt_text_hide, false); OPTION_TO_BOOL(decor.hl_eol, hl_eol, false); - if (opts->hl_mode.type == kObjectTypeString) { + 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 (strequal("replace", str.data)) { decor.hl_mode = kHlModeReplace; @@ -728,14 +732,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } else if (strequal("blend", str.data)) { decor.hl_mode = kHlModeBlend; } else { - VALIDATE_S(false, "virt_text_pos", "", { + VALIDATE_S(false, "hl_mode", str.data, { goto error; }); } - } else if (HAS_KEY(opts->hl_mode)) { - VALIDATE_T("hl_mode", kObjectTypeString, opts->hl_mode.type, { - goto error; - }); } bool virt_lines_leftcol = false; -- cgit From 4e6356559c8cd44dbcaa765d1f39e176064526ec Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 22 Jun 2023 03:44:51 -0700 Subject: test: spellcheck :help (vimdoc) files #24109 Enforce consistent terminology (defined in `gen_help_html.lua:spell_dict`) for common misspellings. This does not spellcheck English in general (perhaps a future TODO, though it may be noisy). --- src/nvim/api/buffer.c | 8 ++++---- src/nvim/api/command.c | 2 +- src/nvim/api/extmark.c | 2 +- src/nvim/api/private/converter.c | 4 ++-- src/nvim/api/private/defs.h | 4 ++-- src/nvim/api/private/helpers.c | 8 ++++---- src/nvim/api/private/helpers.h | 4 ++-- src/nvim/api/vim.c | 6 +++--- src/nvim/api/vimscript.c | 26 +++++++++++++------------- src/nvim/api/window.c | 6 +++--- 10 files changed, 35 insertions(+), 35 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 82a62c3192..4c3faf8d8b 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -112,7 +112,7 @@ Integer nvim_buf_line_count(Buffer buffer, Error *err) /// - byte count of previous contents /// - deleted_codepoints (if `utf_sizes` is true) /// - deleted_codeunits (if `utf_sizes` is true) -/// - on_bytes: lua callback invoked on change. +/// - on_bytes: Lua callback invoked on change. /// This callback receives more granular information about the /// change compared to on_lines. /// Return `true` to detach. @@ -1250,11 +1250,11 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err) /// buffer/window currently, like |termopen()|. /// /// @param buffer Buffer handle, or 0 for current buffer -/// @param fun Function to call inside the buffer (currently lua callable +/// @param fun Function to call inside the buffer (currently Lua callable /// only) /// @param[out] err Error details, if any -/// @return Return value of function. NB: will deepcopy lua values -/// currently, use upvalues to send lua references in and out. +/// @return Return value of function. NB: will deepcopy Lua values +/// currently, use upvalues to send Lua references in and out. Object nvim_buf_call(Buffer buffer, LuaRef fun, Error *err) FUNC_API_SINCE(7) FUNC_API_LUA_ONLY diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 6d715bcf46..eba209b424 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -306,7 +306,7 @@ end: /// make their usage simpler with |vim.cmd()|. For example, instead of /// `vim.cmd.bdelete{ count = 2 }`, you may do `vim.cmd.bdelete(2)`. /// -/// On execution error: fails with VimL error, updates v:errmsg. +/// On execution error: fails with Vimscript error, updates v:errmsg. /// /// @see |nvim_exec2()| /// @see |nvim_command()| diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 1946d77846..d79cbf7508 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -1048,7 +1048,7 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, /// Set or change decoration provider for a |namespace| /// -/// This is a very general purpose interface for having lua callbacks +/// This is a very general purpose interface for having Lua callbacks /// being triggered during the redraw code. /// /// The expected usage is to set |extmarks| for the currently diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index a62f975cfd..68939e609c 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -256,7 +256,7 @@ Object vim_to_object(typval_T *obj) return ret; } -/// Converts from type Object to a VimL value. +/// Converts from type Object to a Vimscript value. /// /// @param obj Object to convert from. /// @param tv Conversion result is placed here. On failure member v_type is @@ -283,7 +283,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) case kObjectTypeTabpage: case kObjectTypeInteger: STATIC_ASSERT(sizeof(obj.data.integer) <= sizeof(varnumber_T), - "Integer size must be <= VimL number size"); + "Integer size must be <= Vimscript number size"); tv->v_type = VAR_NUMBER; tv->vval.v_number = (varnumber_T)obj.data.integer; break; diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index 7c5559f096..b1b9e383b0 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -42,10 +42,10 @@ typedef enum { /// Mask for all internal calls #define INTERNAL_CALL_MASK (((uint64_t)1) << (sizeof(uint64_t) * 8 - 1)) -/// Internal call from VimL code +/// Internal call from Vimscript code #define VIML_INTERNAL_CALL INTERNAL_CALL_MASK -/// Internal call from lua code +/// Internal call from Lua code #define LUA_INTERNAL_CALL (VIML_INTERNAL_CALL + 1) static inline bool is_internal_call(uint64_t channel_id) diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 2544809553..f9861c82bf 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -40,10 +40,10 @@ # include "api/private/ui_events_metadata.generated.h" #endif -/// Start block that may cause VimL exceptions while evaluating another code +/// Start block that may cause Vimscript exceptions while evaluating another code /// -/// Used when caller is supposed to be operating when other VimL code is being -/// processed and that “other VimL code” must not be affected. +/// Used when caller is supposed to be operating when other Vimscript code is being +/// processed and that “other Vimscript code” must not be affected. /// /// @param[out] tstate Location where try state should be saved. void try_enter(TryState *const tstate) @@ -806,7 +806,7 @@ bool api_object_to_bool(Object obj, const char *what, bool nil_value, Error *err } else if (obj.type == kObjectTypeInteger) { return obj.data.integer; // C semantics: non-zero int is true } else if (obj.type == kObjectTypeNil) { - return nil_value; // caller decides what NIL (missing retval in lua) means + return nil_value; // caller decides what NIL (missing retval in Lua) means } else { api_set_error(err, kErrorTypeValidation, "%s is not a boolean", what); return false; diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 3887a11dd1..cb74c655cd 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -135,8 +135,8 @@ EXTERN PMap(int) tabpage_handles INIT(= MAP_INIT); /// Structure used for saving state for :try /// -/// Used when caller is supposed to be operating when other VimL code is being -/// processed and that “other VimL code” must not be affected. +/// Used when caller is supposed to be operating when other Vimscript code is being +/// processed and that “other Vimscript code” must not be affected. typedef struct { except_T *current_exception; msglist_T *private_msg_list; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index a6f98a1915..9996dae247 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -544,7 +544,7 @@ String nvim__get_lib_dir(void) /// /// @param pat pattern of files to search for /// @param all whether to return all matches or only the first -/// @param opts is_lua: only search lua subdirs +/// @param opts is_lua: only search Lua subdirs /// @return list of absolute paths to the found files ArrayOf(String) nvim__get_runtime(Array pat, Boolean all, Dict(runtime) *opts, Error *err) FUNC_API_SINCE(8) @@ -941,7 +941,7 @@ fail: /// /// @param buffer the buffer to use (expected to be empty) /// @param opts Optional parameters. -/// - on_input: lua callback for input sent, i e keypresses in terminal +/// - on_input: Lua callback for input sent, i e keypresses in terminal /// mode. Note: keypresses are sent raw as they would be to the pty /// master end. For instance, a carriage return is sent /// as a "\r", not as a "\n". |textlock| applies. It is possible @@ -1009,7 +1009,7 @@ static void term_write(char *buf, size_t size, void *data) // NOLINT(readabilit static void term_resize(uint16_t width, uint16_t height, void *data) { - // TODO(bfredl): lua callback + // TODO(bfredl): Lua callback } static void term_close(void *data) diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 1a67be8860..eb573e2556 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -38,7 +38,7 @@ /// Unlike |nvim_command()| this function supports heredocs, script-scope (s:), /// etc. /// -/// On execution error: fails with VimL error, updates v:errmsg. +/// On execution error: fails with Vimscript error, updates v:errmsg. /// /// @see |execute()| /// @see |nvim_command()| @@ -126,7 +126,7 @@ theend: /// Executes an Ex command. /// -/// On execution error: fails with VimL error, updates v:errmsg. +/// On execution error: fails with Vimscript error, updates v:errmsg. /// /// Prefer using |nvim_cmd()| or |nvim_exec2()| over this. To evaluate multiple lines of Vim script /// or an Ex command directly, use |nvim_exec2()|. To construct an Ex command using a structured @@ -143,12 +143,12 @@ void nvim_command(String command, Error *err) try_end(err); } -/// Evaluates a VimL |expression|. +/// Evaluates a Vimscript |expression|. /// Dictionaries and Lists are recursively expanded. /// -/// On execution error: fails with VimL error, updates v:errmsg. +/// On execution error: fails with Vimscript error, updates v:errmsg. /// -/// @param expr VimL expression string +/// @param expr Vimscript expression string /// @param[out] err Error details, if any /// @return Evaluation result or expanded object Object nvim_eval(String expr, Error *err) @@ -192,7 +192,7 @@ Object nvim_eval(String expr, Error *err) return rv; } -/// Calls a VimL function. +/// Calls a Vimscript function. /// /// @param fn Function name /// @param args Function arguments @@ -258,9 +258,9 @@ free_vim_args: return rv; } -/// Calls a VimL function with the given arguments. +/// Calls a Vimscript function with the given arguments. /// -/// On execution error: fails with VimL error, updates v:errmsg. +/// On execution error: fails with Vimscript error, updates v:errmsg. /// /// @param fn Function to call /// @param args Function arguments packed in an Array @@ -272,12 +272,12 @@ Object nvim_call_function(String fn, Array args, Error *err) return _call_function(fn, args, NULL, err); } -/// Calls a VimL |Dictionary-function| with the given arguments. +/// Calls a Vimscript |Dictionary-function| with the given arguments. /// -/// On execution error: fails with VimL error, updates v:errmsg. +/// On execution error: fails with Vimscript error, updates v:errmsg. /// -/// @param dict Dictionary, or String evaluating to a VimL |self| dict -/// @param fn Name of the function defined on the VimL dict +/// @param dict Dictionary, or String evaluating to a Vimscript |self| dict +/// @param fn Name of the function defined on the Vimscript dict /// @param args Function arguments packed in an Array /// @param[out] err Error details, if any /// @return Result of the function call @@ -363,7 +363,7 @@ typedef struct { typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack; /// @endcond -/// Parse a VimL expression. +/// Parse a Vimscript expression. /// /// @param[in] expr Expression to parse. Always treated as a single line. /// @param[in] flags Flags: diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 97bf0f377a..e5a824fec9 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -412,11 +412,11 @@ void nvim_win_close(Window window, Boolean force, Error *err) /// @see |nvim_buf_call()| /// /// @param window Window handle, or 0 for current window -/// @param fun Function to call inside the window (currently lua callable +/// @param fun Function to call inside the window (currently Lua callable /// only) /// @param[out] err Error details, if any -/// @return Return value of function. NB: will deepcopy lua values -/// currently, use upvalues to send lua references in and out. +/// @return Return value of function. NB: will deepcopy Lua values +/// currently, use upvalues to send Lua references in and out. Object nvim_win_call(Window window, LuaRef fun, Error *err) FUNC_API_SINCE(7) FUNC_API_LUA_ONLY -- cgit From f0884f21fa0cccc576f00bc18895cc80ba906031 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 22 Jun 2023 20:39:35 +0800 Subject: feat(extmarks): support hl_mode "combine" for inline virt_text (#24099) --- src/nvim/api/extmark.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index d79cbf7508..a101e1bbf1 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -478,7 +478,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// shifting the underlying text. /// - "right_align": display right aligned in the window. /// - "inline": display at the specified column, and -/// shift the buffer text to the right as needed +/// shift the buffer text to the right as needed /// - virt_text_win_col : position the virtual text at a fixed /// window column (starting from the first /// text column) @@ -490,10 +490,10 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// highlights of the text. Currently only affects /// virt_text highlights, but might affect `hl_group` /// in later versions. -/// - "replace": only show the virt_text color. This is the -/// default -/// - "combine": combine with background text color +/// - "replace": only show the virt_text color. This is the default. +/// - "combine": combine with background text color. /// - "blend": blend with background text color. +/// Not supported for "inline" virt_text. /// /// - virt_lines : virtual lines to add next to this mark /// This should be an array over lines, where each line in @@ -730,6 +730,11 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } else if (strequal("combine", str.data)) { decor.hl_mode = kHlModeCombine; } else if (strequal("blend", str.data)) { + if (decor.virt_text_pos == kVTInline) { + VALIDATE(false, "%s", "cannot use 'blend' hl_mode with inline virtual text", { + goto error; + }); + } decor.hl_mode = kHlModeBlend; } else { VALIDATE_S(false, "hl_mode", str.data, { -- cgit From 49a7585981cdf7403e76a614558e602a98e64301 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 23 Jun 2023 12:16:55 +0200 Subject: docs: autocmds, misc --- src/nvim/api/buffer.c | 2 +- src/nvim/api/extmark.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 4c3faf8d8b..c1aef53dc0 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -84,7 +84,7 @@ Integer nvim_buf_line_count(Buffer buffer, Error *err) /// Activates buffer-update events on a channel, or as Lua callbacks. /// /// Example (Lua): capture buffer updates in a global `events` variable -/// (use "print(vim.inspect(events))" to see its contents): +/// (use "vim.print(events)" to see its contents): ///
lua
 ///   events = {}
 ///   vim.api.nvim_buf_attach(0, false, {
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index a101e1bbf1..0608a8961d 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -320,7 +320,7 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
 ///   local ms  = api.nvim_buf_get_extmarks(0, ns, {2,0}, {2,0}, {})
 ///   -- Get all marks in this buffer + namespace.
 ///   local all = api.nvim_buf_get_extmarks(0, ns, 0, -1, {})
-///   print(vim.inspect(ms))
+///   vim.print(ms)
 /// 
/// /// @param buffer Buffer handle, or 0 for current buffer -- cgit From b6878f5d6387bad667edf75cf6c70e846c3b0428 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Mon, 26 Jun 2023 11:16:55 +0200 Subject: docs: fix misparsed headings (#24162) Problem: vimdoc parser requires space between column heading and `~`. Solution: Add space to docs (and mention it). Also edit `luaref.txt` headings for consistency. --- src/nvim/api/buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index c1aef53dc0..5bf7295bb3 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -48,7 +48,7 @@ /// /// \brief For more information on buffers, see |buffers| /// -/// Unloaded Buffers:~ +/// Unloaded Buffers: ~ /// /// Buffers may be unloaded by the |:bunload| command or the buffer's /// |'bufhidden'| option. When a buffer is unloaded its file contents are freed -- cgit From e0453d7f5743ad2f515deea76e363d11a7e1fa96 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 28 Jun 2023 04:51:55 -0700 Subject: fix(api): nvim_cmd{cmd="win_getid"} parsed as :winsize #24181 Problem: `:lua vim.cmd.win_getid(30,10)` is interpreted as `:win[size] 30 10`. User intention was to call `vim.fn.win_getid(30,10)`. Solution: Check that the `cmd` actually matches the resolved command. --- src/nvim/api/command.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index eba209b424..3157132256 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -393,6 +393,12 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error VALIDATE(!is_cmd_ni(ea.cmdidx), "Command not implemented: %s", cmdname, { goto end; }); + const char *fullname = IS_USER_CMDIDX(ea.cmdidx) + ? get_user_command_name(ea.useridx, ea.cmdidx) + : get_command_name(NULL, ea.cmdidx); + VALIDATE(strncmp(fullname, cmdname, strlen(cmdname)) == 0, "Invalid command: \"%s\"", cmdname, { + goto end; + }); // Get the command flags so that we can know what type of arguments the command uses. // Not required for a user command since `find_ex_command` already deals with it in that case. -- cgit From 2493815290c4cb5b1fb97b6d010c10bdf2d47a58 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 30 Jun 2023 21:13:08 +0800 Subject: refactor: fix clang/PVS warnings (#24213) --- src/nvim/api/deprecated.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 83c33db5d3..2e3ebd7c39 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -709,7 +709,7 @@ static void set_option_to(uint64_t channel_id, void *to, int type, String name, } } - OptVal optval = NIL_OPTVAL; + OptVal optval; if (flags & SOPT_BOOL) { VALIDATE(value.type == kObjectTypeBoolean, "Option '%s' value must be Boolean", name.data, { -- cgit From a741c7fd0465c949a0016fcbee5f4526b65f8c02 Mon Sep 17 00:00:00 2001 From: Alexandre Teoi Date: Sat, 1 Jul 2023 10:33:51 -0300 Subject: fix(api): nvim_parse_cmd error message in pcall() #23297 Problem: nvim_parse_cmd() in pcall() may show an error message (side-effect): :lua pcall(vim.api.nvim_parse_cmd, vim.fn.getcmdline(), {}) E16: Invalid range Solution: Avoid emsg() in the nvim_parse_cmd() codepath. - refactor(api): add error message output parameter to get_address() - fix: null check emsg() parameter - refactor: remove emsg_off workaround from do_incsearch_highlighting() - refactor: remove emsg_off workaround from cmdpreview_may_show() - refactor: remove remaining calls to emsg() from parse_cmd_address() and get_address() - (refactor): lint set_cmd_dflall_range() - refactor: addr_error() - move output parameter to return value Fix #20339 TODO: These are the functions called by `get_address()`: ``` nvim_parse_cmd() -> parse_cmdline() -> parse_cmd_address() -> get_address() skipwhite() addr_error() qf_get_cur_idx() qf_get_cur_valid_idx() qf_get_size() qf_get_valid_size() mark_get() mark_check() assert() skip_regexp() magic_isset() > do_search() > searchit() ascii_isdigit() getdigits() getdigits_int32() compute_buffer_local_count() hasFolding() ``` From these functions, I found at least two that call emsg directly: - do_search() - seems to be simple to refactor - searchit() - will be more challenging because it may generate multiple error messages, which can't be handled by the current `errormsg` out-parameter. For example, it makes multiple calls to `vim_regexec_multi()` in a loop that possibly generate error messages, and later `searchit()` itself may generate another one: - https://github.com/neovim/neovim/blob/c194acbfc479d8e5839fa629363f93f6550d035c/src/nvim/search.c#L631-L647 - https://github.com/neovim/neovim/blob/c194acbfc479d8e5839fa629363f93f6550d035c/src/nvim/search.c#L939-L954 --------- Co-authored-by: Justin M. Keyes --- src/nvim/api/command.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 3157132256..b254e326f9 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -109,7 +109,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) exarg_T ea; CmdParseInfo cmdinfo; char *cmdline = string_to_cstr(str); - char *errormsg = NULL; + const char *errormsg = NULL; if (!parse_cmdline(cmdline, &ea, &cmdinfo, &errormsg)) { if (errormsg != NULL) { -- cgit From 92760a7f42a95bb252966c2a38423e5bc9d57cc7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 4 Jul 2023 07:19:02 +0800 Subject: fix(api, lua): make blank lines in a message work properly (#24244) --- src/nvim/api/vim.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 9996dae247..8d34a34e8a 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1687,6 +1687,7 @@ static void write_msg(String message, bool to_err, bool writeln) if (c == NL) { \ kv_push(line_buf, NUL); \ msg(line_buf.items); \ + msg_didout = true; \ kv_drop(line_buf, kv_size(line_buf)); \ kv_resize(line_buf, LINE_BUFFER_MIN_SIZE); \ } else { \ -- cgit From 3ecd45ded044c47efa76b74e9e3b720fbe27adc7 Mon Sep 17 00:00:00 2001 From: notomo Date: Tue, 4 Jul 2023 23:07:55 +0900 Subject: fix(api): allow negative column arguments for nvim_buf_set_text (#23501) --- src/nvim/api/buffer.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 5bf7295bb3..8774aee20b 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -547,6 +547,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In // Another call to ml_get_buf() may free the line, so make a copy. str_at_start = xstrdup(ml_get_buf(buf, (linenr_T)start_row, false)); size_t len_at_start = strlen(str_at_start); + start_col = start_col < 0 ? (int64_t)len_at_start + start_col + 1 : start_col; VALIDATE_RANGE((start_col >= 0 && (size_t)start_col <= len_at_start), "start_col", { goto early_end; }); @@ -554,6 +555,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In // Another call to ml_get_buf() may free the line, so make a copy. str_at_end = xstrdup(ml_get_buf(buf, (linenr_T)end_row, false)); size_t len_at_end = strlen(str_at_end); + end_col = end_col < 0 ? (int64_t)len_at_end + end_col + 1 : end_col; VALIDATE_RANGE((end_col >= 0 && (size_t)end_col <= len_at_end), "end_col", { goto early_end; }); -- cgit From 77118d0da8badc4135be430f4cbb15bc95bc760f Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Thu, 20 Apr 2023 21:17:25 +0100 Subject: fix(api): use text_locked() to check textlock Problem: some API functions that check textlock (usually those that can change curwin or curbuf) can break the cmdwin. Solution: make FUNC_API_CHECK_TEXTLOCK call text_locked() instead, which already checks for textlock, cmdwin and `` status. Add FUNC_API_TEXTLOCK_ALLOW_CMDWIN to allow such functions to be usable in the cmdwin if they can work properly there; the opt-in nature of this attribute should hopefully help mitigate future bugs. Also fix a regression in #22634 that made functions checking textlock usable in `` mappings, and rename FUNC_API_CHECK_TEXTLOCK to FUNC_API_TEXTLOCK. --- src/nvim/api/buffer.c | 4 ++-- src/nvim/api/vim.c | 14 +++++++------- src/nvim/api/win_config.c | 2 +- src/nvim/api/window.c | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 8774aee20b..7cd9686544 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -347,7 +347,7 @@ end: void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integer end, Boolean strict_indexing, ArrayOf(String) replacement, Error *err) FUNC_API_SINCE(1) - FUNC_API_CHECK_TEXTLOCK + FUNC_API_TEXTLOCK_ALLOW_CMDWIN { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -1061,7 +1061,7 @@ Boolean nvim_buf_is_loaded(Buffer buffer) /// - unload: Unloaded only, do not delete. See |:bunload| void nvim_buf_delete(Buffer buffer, Dictionary opts, Error *err) FUNC_API_SINCE(7) - FUNC_API_CHECK_TEXTLOCK + FUNC_API_TEXTLOCK { buf_T *buf = find_buffer_by_handle(buffer, err); diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 8d34a34e8a..eacc833c58 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -612,7 +612,7 @@ String nvim_get_current_line(Error *err) /// @param[out] err Error details, if any void nvim_set_current_line(String line, Error *err) FUNC_API_SINCE(1) - FUNC_API_CHECK_TEXTLOCK + FUNC_API_TEXTLOCK_ALLOW_CMDWIN { buffer_set_line(curbuf->handle, curwin->w_cursor.lnum - 1, line, err); } @@ -622,7 +622,7 @@ void nvim_set_current_line(String line, Error *err) /// @param[out] err Error details, if any void nvim_del_current_line(Error *err) FUNC_API_SINCE(1) - FUNC_API_CHECK_TEXTLOCK + FUNC_API_TEXTLOCK_ALLOW_CMDWIN { buffer_del_line(curbuf->handle, curwin->w_cursor.lnum - 1, err); } @@ -803,7 +803,7 @@ Buffer nvim_get_current_buf(void) /// @param[out] err Error details, if any void nvim_set_current_buf(Buffer buffer, Error *err) FUNC_API_SINCE(1) - FUNC_API_CHECK_TEXTLOCK + FUNC_API_TEXTLOCK { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -858,7 +858,7 @@ Window nvim_get_current_win(void) /// @param[out] err Error details, if any void nvim_set_current_win(Window window, Error *err) FUNC_API_SINCE(1) - FUNC_API_CHECK_TEXTLOCK + FUNC_API_TEXTLOCK { win_T *win = find_window_by_handle(window, err); @@ -1084,7 +1084,7 @@ Tabpage nvim_get_current_tabpage(void) /// @param[out] err Error details, if any void nvim_set_current_tabpage(Tabpage tabpage, Error *err) FUNC_API_SINCE(1) - FUNC_API_CHECK_TEXTLOCK + FUNC_API_TEXTLOCK { tabpage_T *tp = find_tab_by_handle(tabpage, err); @@ -1126,7 +1126,7 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err) /// - false: Client must cancel the paste. Boolean nvim_paste(String data, Boolean crlf, Integer phase, Error *err) FUNC_API_SINCE(6) - FUNC_API_CHECK_TEXTLOCK + FUNC_API_TEXTLOCK_ALLOW_CMDWIN { static bool draining = false; bool cancel = false; @@ -1197,7 +1197,7 @@ theend: /// @param[out] err Error details, if any void nvim_put(ArrayOf(String) lines, String type, Boolean after, Boolean follow, Error *err) FUNC_API_SINCE(6) - FUNC_API_CHECK_TEXTLOCK + FUNC_API_TEXTLOCK_ALLOW_CMDWIN { yankreg_T *reg = xcalloc(1, sizeof(yankreg_T)); VALIDATE_S((prepare_yankreg_from_object(reg, type, lines.size)), "type", type.data, { diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 8e4fbb6779..6ca36a0daf 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -158,7 +158,7 @@ /// @return Window handle, or 0 on error Window nvim_open_win(Buffer buffer, Boolean enter, Dict(float_config) *config, Error *err) FUNC_API_SINCE(6) - FUNC_API_CHECK_TEXTLOCK + FUNC_API_TEXTLOCK { FloatConfig fconfig = FLOAT_CONFIG_INIT; if (!parse_float_config(config, &fconfig, false, true, err)) { diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index e5a824fec9..5fb07ecbc8 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -48,7 +48,7 @@ Buffer nvim_win_get_buf(Window window, Error *err) /// @param[out] err Error details, if any void nvim_win_set_buf(Window window, Buffer buffer, Error *err) FUNC_API_SINCE(5) - FUNC_API_CHECK_TEXTLOCK + FUNC_API_TEXTLOCK { win_set_buf(window, buffer, false, err); } @@ -351,7 +351,7 @@ Boolean nvim_win_is_valid(Window window) /// @param[out] err Error details, if any void nvim_win_hide(Window window, Error *err) FUNC_API_SINCE(7) - FUNC_API_CHECK_TEXTLOCK + FUNC_API_TEXTLOCK { win_T *win = find_window_by_handle(window, err); if (!win) { @@ -383,7 +383,7 @@ void nvim_win_hide(Window window, Error *err) /// @param[out] err Error details, if any void nvim_win_close(Window window, Boolean force, Error *err) FUNC_API_SINCE(6) - FUNC_API_CHECK_TEXTLOCK + FUNC_API_TEXTLOCK_ALLOW_CMDWIN { win_T *win = find_window_by_handle(window, err); if (!win) { -- cgit From aa4e47f704c53ab1d825260d2bf34e2872e3ca89 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Fri, 23 Jun 2023 22:32:07 +0100 Subject: fix(api): disallow some more functions during textlock Problem: nvim_buf_set_text(), nvim_open_term() and termopen() all change buffer text, which is forbidden during textlock. Additionally, nvim_open_term() and termopen() may be used to convert the cmdwin buffer into a terminal buffer, which is weird. Solution: Allow nvim_buf_set_text() and nvim_open_term() in the cmdwin, but disallow nvim_open_term() from converting the cmdwin buffer into a terminal buffer. termopen() is not allowed in the cmdwin (as it always operates on curbuf), so just check text_locked(). Also happens to improve the error in #21055: nvim_buf_set_text() was callable during textlock, but happened to check textlock indirectly via u_save(); however, this caused the error to be overwritten by an unhelpful "Failed to save undo information" message when msg_list == NULL (e.g: an `` mapping invoked outside of do_cmdline()). --- src/nvim/api/buffer.c | 1 + src/nvim/api/vim.c | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 7cd9686544..02b97b0ae1 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -515,6 +515,7 @@ end: void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, Integer start_col, Integer end_row, Integer end_col, ArrayOf(String) replacement, Error *err) FUNC_API_SINCE(7) + FUNC_API_TEXTLOCK_ALLOW_CMDWIN { MAXSIZE_TEMP_ARRAY(scratch, 1); if (replacement.size == 0) { diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index eacc833c58..8c40e5ccd7 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -951,12 +951,18 @@ fail: /// @return Channel id, or 0 on error Integer nvim_open_term(Buffer buffer, DictionaryOf(LuaRef) opts, Error *err) FUNC_API_SINCE(7) + FUNC_API_TEXTLOCK_ALLOW_CMDWIN { buf_T *buf = find_buffer_by_handle(buffer, err); if (!buf) { return 0; } + if (cmdwin_type != 0 && buf == curbuf) { + api_set_error(err, kErrorTypeException, "%s", _(e_cmdwin)); + return 0; + } + LuaRef cb = LUA_NOREF; for (size_t i = 0; i < opts.size; i++) { String k = opts.items[i].key; -- cgit From 00d2f4b96eb9c8dcb6b9f67e256bb7faa19354db Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 4 Jul 2023 19:22:04 +0200 Subject: docs: MAINTAIN.md, nvim_get_mark --- src/nvim/api/buffer.c | 5 +++-- src/nvim/api/vim.c | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 02b97b0ae1..a0322556b4 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1192,8 +1192,9 @@ Boolean nvim_buf_set_mark(Buffer buffer, String name, Integer line, Integer col, return res; } -/// Returns a tuple (row,col) representing the position of the named mark. See -/// |mark-motions|. +/// Returns a `(row,col)` tuple representing the position of the named mark. +/// "End of line" column position is returned as |v:maxcol| (big number). +/// See |mark-motions|. /// /// Marks are (1,0)-indexed. |api-indexing| /// diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 8c40e5ccd7..3ffaaab780 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1980,12 +1980,13 @@ Boolean nvim_del_mark(String name, Error *err) return res; } -/// Return a tuple (row, col, buffer, buffername) representing the position of -/// the uppercase/file named mark. See |mark-motions|. +/// Returns a `(row, col, buffer, buffername)` tuple representing the position +/// of the uppercase/file named mark. "End of line" column position is returned +/// as |v:maxcol| (big number). See |mark-motions|. /// /// Marks are (1,0)-indexed. |api-indexing| /// -/// @note fails with error if a lowercase or buffer local named mark is used. +/// @note Lowercase name (or other buffer-local mark) is an error. /// @param name Mark name /// @param opts Optional parameters. Reserved for future use. /// @return 4-tuple (row, col, buffer, buffername), (0, 0, 0, '') if the mark is -- cgit From 3a721820c39b7524a2e6d6a73774498104a38962 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 6 Jul 2023 15:32:39 +0200 Subject: docs: "Return (multiple)" heading Problem: Lua functions that return multiple results are declared by using multiple `@return` docstring directives. But the generated docs don't make it obvious what this represents. Solution: - Generate a "Return (multiple)" heading for multiple-value functions. - Fix `@note` directives randomly placed after `@return`. --- src/nvim/api/vim.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 3ffaaab780..13021f9c57 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -87,6 +87,9 @@ Integer nvim_get_hl_id_by_name(String name) /// Gets all or specific highlight groups in a namespace. /// +/// @note When the `link` attribute is defined in the highlight definition +/// map, other attributes will not be taking effect (see |:hi-link|). +/// /// @param ns_id Get highlight groups for namespace ns_id |nvim_get_namespaces()|. /// Use 0 to get global highlight groups |:highlight|. /// @param opts Options dict: @@ -97,9 +100,6 @@ Integer nvim_get_hl_id_by_name(String name) /// @param[out] err Error details, if any. /// @return Highlight groups as a map from group name to a highlight definition map as in |nvim_set_hl()|, /// or only a single highlight definition map if requested by name or id. -/// -/// @note When the `link` attribute is defined in the highlight definition -/// map, other attributes will not be taking effect (see |:hi-link|). Dictionary nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena *arena, Error *err) FUNC_API_SINCE(11) { -- cgit From d2e44da516816e2616b531886eb9ba7f4c271fb4 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 6 Jul 2023 22:47:27 +0200 Subject: docs: gather @notes items into one section related: 21eacbfef399 --- src/nvim/api/vim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 13021f9c57..c15ec4ce53 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1958,7 +1958,7 @@ Object nvim__unpack(String str, Error *err) /// Deletes an uppercase/file named mark. See |mark-motions|. /// -/// @note fails with error if a lowercase or buffer local named mark is used. +/// @note Lowercase name (or other buffer-local mark) is an error. /// @param name Mark name /// @return true if the mark was deleted, else false. /// @see |nvim_buf_del_mark()| -- cgit From db8fe63a9398efd57c3ff28aa3d93e45fb70ee1a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 11 Jul 2023 07:15:46 +0800 Subject: feat(api): add nvim_win_text_height (#24236) It uses the same code as "scroll_delta" of "win_viewport" UI event to calculate text height, but is more flexible. --- src/nvim/api/buffer.c | 21 --------- src/nvim/api/keysets.h | 7 +++ src/nvim/api/private/helpers.c | 21 +++++++++ src/nvim/api/window.c | 103 +++++++++++++++++++++++++++++++++++++++++ src/nvim/api/window.h | 1 + 5 files changed, 132 insertions(+), 21 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index a0322556b4..3b73237b06 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1334,27 +1334,6 @@ static void fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra) invalidate_botline(); } -// Normalizes 0-based indexes to buffer line numbers -static int64_t normalize_index(buf_T *buf, int64_t index, bool end_exclusive, bool *oob) -{ - assert(buf->b_ml.ml_line_count > 0); - int64_t max_index = buf->b_ml.ml_line_count + (int)end_exclusive - 1; - // Fix if < 0 - index = index < 0 ? max_index + index + 1 : index; - - // Check for oob - if (index > max_index) { - *oob = true; - index = max_index; - } else if (index < 0) { - *oob = true; - index = 0; - } - // Convert the index to a vim line number - index++; - return index; -} - /// Initialise a string array either: /// - on the Lua stack (as a table) (if lstate is not NULL) /// - as an API array object (if lstate is NULL). diff --git a/src/nvim/api/keysets.h b/src/nvim/api/keysets.h index 333b90d7fd..e08186161a 100644 --- a/src/nvim/api/keysets.h +++ b/src/nvim/api/keysets.h @@ -171,6 +171,13 @@ typedef struct { Object link; } Dict(get_highlight); +typedef struct { + Object start_row; + Object end_row; + Object start_vcol; + Object end_vcol; +} Dict(win_text_height); + typedef struct { Object buffer; Object event; diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index f9861c82bf..d0c8ab4dd4 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -478,6 +478,27 @@ Array string_to_array(const String input, bool crlf) return ret; } +/// Normalizes 0-based indexes to buffer line numbers. +int64_t normalize_index(buf_T *buf, int64_t index, bool end_exclusive, bool *oob) +{ + assert(buf->b_ml.ml_line_count > 0); + int64_t max_index = buf->b_ml.ml_line_count + (int)end_exclusive - 1; + // A negative index counts from the bottom. + index = index < 0 ? max_index + index + 1 : index; + + // Check for oob and clamp. + if (index > max_index) { + *oob = true; + index = max_index; + } else if (index < 0) { + *oob = true; + index = 0; + } + // Convert the index to a 1-based line number. + index++; + return index; +} + /// Returns a substring of a buffer line /// /// @param buf Buffer handle diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 5fb07ecbc8..07aad2cd88 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -8,6 +8,7 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/api/window.h" #include "nvim/ascii.h" #include "nvim/buffer_defs.h" @@ -20,6 +21,7 @@ #include "nvim/lua/executor.h" #include "nvim/memline_defs.h" #include "nvim/move.h" +#include "nvim/plines.h" #include "nvim/pos.h" #include "nvim/types.h" #include "nvim/window.h" @@ -462,3 +464,104 @@ void nvim_win_set_hl_ns(Window window, Integer ns_id, Error *err) win->w_hl_needs_update = true; redraw_later(win, UPD_NOT_VALID); } + +/// Computes the number of screen lines occupied by a range of text in a given window. +/// Works for off-screen text and takes folds into account. +/// +/// Diff filler or virtual lines above a line are counted as a part of that line, +/// unless the line is on "start_row" and "start_vcol" is specified. +/// +/// Diff filler or virtual lines below the last buffer line are counted in the result +/// when "end_row" is omitted. +/// +/// Line indexing is similar to |nvim_buf_get_text()|. +/// +/// @param window Window handle, or 0 for current window. +/// @param opts Optional parameters: +/// - start_row: Starting line index, 0-based inclusive. +/// When omitted start at the very top. +/// - end_row: Ending line index, 0-based inclusive. +/// When omitted end at the very bottom. +/// - start_vcol: Starting virtual column index on "start_row", +/// 0-based inclusive, rounded down to full screen lines. +/// When omitted include the whole line. +/// - end_vcol: Ending virtual column index on "end_row", +/// 0-based exclusive, rounded up to full screen lines. +/// When omitted include the whole line. +/// @return The number of screen lines that the range of text occupy. +/// +/// @see |virtcol()| for text width. +Object nvim_win_text_height(Window window, Dict(win_text_height) *opts, Error *err) + FUNC_API_SINCE(12) +{ + win_T *const win = find_window_by_handle(window, err); + if (!win) { + return NIL; + } + buf_T *const buf = win->w_buffer; + const linenr_T line_count = buf->b_ml.ml_line_count; + + linenr_T start_lnum = 1; + linenr_T end_lnum = line_count; + int64_t start_vcol = -1; + int64_t end_vcol = -1; + + bool oob = false; + + if (HAS_KEY(opts->start_row)) { + VALIDATE_T("start_row", kObjectTypeInteger, opts->start_row.type, { + return NIL; + }); + start_lnum = (linenr_T)normalize_index(buf, opts->start_row.data.integer, false, &oob); + } + + if (HAS_KEY(opts->end_row)) { + VALIDATE_T("end_row", kObjectTypeInteger, opts->end_row.type, { + return NIL; + }); + end_lnum = (linenr_T)normalize_index(buf, opts->end_row.data.integer, false, &oob); + } + + VALIDATE(!oob, "%s", "Line index out of bounds", { + return NIL; + }); + VALIDATE((start_lnum <= end_lnum), "%s", "'start_row' is higher than 'end_row'", { + return NIL; + }); + + if (HAS_KEY(opts->start_vcol)) { + VALIDATE(HAS_KEY(opts->start_row), "%s", "'start_vcol' specified without 'start_row'", { + return NIL; + }); + VALIDATE_T("start_vcol", kObjectTypeInteger, opts->start_vcol.type, { + return NIL; + }); + start_vcol = opts->start_vcol.data.integer; + VALIDATE_RANGE((start_vcol >= 0 && start_vcol <= MAXCOL), "start_vcol", { + return NIL; + }); + } + + if (HAS_KEY(opts->end_vcol)) { + VALIDATE(HAS_KEY(opts->end_row), "%s", "'end_vcol' specified without 'end_row'", { + return NIL; + }); + VALIDATE_T("end_vcol", kObjectTypeInteger, opts->end_vcol.type, { + return NIL; + }); + end_vcol = opts->end_vcol.data.integer; + VALIDATE_RANGE((end_vcol >= 0 && end_vcol <= MAXCOL), "end_vcol", { + return NIL; + }); + } + + if (start_lnum == end_lnum && start_vcol >= 0 && end_vcol >= 0) { + VALIDATE((start_vcol <= end_vcol), "%s", "'start_vcol' is higher than 'end_vcol'", { + return NIL; + }); + } + + const int64_t res = win_text_height(win, start_lnum, start_vcol, end_lnum, end_vcol) + + (HAS_KEY(opts->end_row) ? 0 : win_get_fill(win, line_count + 1)); + return INTEGER_OBJ(res); +} diff --git a/src/nvim/api/window.h b/src/nvim/api/window.h index 0f36c12a9f..046d64c1a4 100644 --- a/src/nvim/api/window.h +++ b/src/nvim/api/window.h @@ -1,6 +1,7 @@ #ifndef NVIM_API_WINDOW_H #define NVIM_API_WINDOW_H +#include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS -- cgit From 9359701eae7bd8a59e4a916e085cc686f609d693 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 13 Jul 2023 07:02:06 +0800 Subject: test(extmarks): add test for virt_text_win_col with cpo+=n (#24328) --- src/nvim/api/extmark.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 0608a8961d..d254373eb0 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -473,15 +473,16 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// 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) +/// - "eol": right after eol character (default). /// - "overlay": display over the specified column, without /// shifting the underlying text. /// - "right_align": display right aligned in the window. /// - "inline": display at the specified column, and -/// shift the buffer text to the right as needed +/// shift the buffer text to the right as needed. /// - virt_text_win_col : position the virtual text at a fixed /// window column (starting from the first -/// text column) +/// text column of the screen line) instead +/// of "virt_text_pos". /// - virt_text_hide : hide the virtual text when the background /// text is selected or hidden because of /// scrolling with 'nowrap' or 'smoothscroll'. -- cgit From 516b173780e39de3ce1e4525f0a8f0ff250c992b Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 13 Jul 2023 10:17:19 +0100 Subject: perf(rtp): reduce rtp scans (#24191) * perf(rtp): reduce rtp scans Problem: Scanning the filesystem is expensive and particularly affects startuptime. Solution: Reduce the amount of redundant directory scans by relying less on glob patterns and handle vim and lua sourcing lower down. --- src/nvim/api/vim.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index c15ec4ce53..b1e472aa8c 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -527,12 +527,17 @@ ArrayOf(String) nvim_get_runtime_file(String name, Boolean all, Error *err) return rv; } -static void find_runtime_cb(char *fname, void *cookie) +static bool find_runtime_cb(int num_fnames, char **fnames, bool all, void *cookie) { Array *rv = (Array *)cookie; - if (fname != NULL) { - ADD(*rv, CSTR_TO_OBJ(fname)); + for (int i = 0; i < num_fnames; i++) { + ADD(*rv, CSTR_TO_OBJ(fnames[i])); + if (!all) { + return true; + } } + + return num_fnames > 0; } String nvim__get_lib_dir(void) -- cgit From abe39f2b243dc813456225a779fbeb7ae6affc27 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Jul 2023 18:02:53 +0800 Subject: feat(api)!: change return type of nvim_win_text_height to Dict (#24365) --- src/nvim/api/window.c | 46 +++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 17 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 07aad2cd88..5480584aa5 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -488,15 +488,20 @@ void nvim_win_set_hl_ns(Window window, Integer ns_id, Error *err) /// - end_vcol: Ending virtual column index on "end_row", /// 0-based exclusive, rounded up to full screen lines. /// When omitted include the whole line. -/// @return The number of screen lines that the range of text occupy. +/// @return Dictionary containing text height information, with these keys: +/// - all: The total number of screen lines occupied by the range. +/// - fill: The number of diff filler or virtual lines among them. /// /// @see |virtcol()| for text width. -Object nvim_win_text_height(Window window, Dict(win_text_height) *opts, Error *err) +Dictionary nvim_win_text_height(Window window, Dict(win_text_height) *opts, Arena *arena, + Error *err) FUNC_API_SINCE(12) { + Dictionary rv = arena_dict(arena, 2); + win_T *const win = find_window_by_handle(window, err); if (!win) { - return NIL; + return rv; } buf_T *const buf = win->w_buffer; const linenr_T line_count = buf->b_ml.ml_line_count; @@ -510,58 +515,65 @@ Object nvim_win_text_height(Window window, Dict(win_text_height) *opts, Error *e if (HAS_KEY(opts->start_row)) { VALIDATE_T("start_row", kObjectTypeInteger, opts->start_row.type, { - return NIL; + return rv; }); start_lnum = (linenr_T)normalize_index(buf, opts->start_row.data.integer, false, &oob); } if (HAS_KEY(opts->end_row)) { VALIDATE_T("end_row", kObjectTypeInteger, opts->end_row.type, { - return NIL; + return rv; }); end_lnum = (linenr_T)normalize_index(buf, opts->end_row.data.integer, false, &oob); } VALIDATE(!oob, "%s", "Line index out of bounds", { - return NIL; + return rv; }); VALIDATE((start_lnum <= end_lnum), "%s", "'start_row' is higher than 'end_row'", { - return NIL; + return rv; }); if (HAS_KEY(opts->start_vcol)) { VALIDATE(HAS_KEY(opts->start_row), "%s", "'start_vcol' specified without 'start_row'", { - return NIL; + return rv; }); VALIDATE_T("start_vcol", kObjectTypeInteger, opts->start_vcol.type, { - return NIL; + return rv; }); start_vcol = opts->start_vcol.data.integer; VALIDATE_RANGE((start_vcol >= 0 && start_vcol <= MAXCOL), "start_vcol", { - return NIL; + return rv; }); } if (HAS_KEY(opts->end_vcol)) { VALIDATE(HAS_KEY(opts->end_row), "%s", "'end_vcol' specified without 'end_row'", { - return NIL; + return rv; }); VALIDATE_T("end_vcol", kObjectTypeInteger, opts->end_vcol.type, { - return NIL; + return rv; }); end_vcol = opts->end_vcol.data.integer; VALIDATE_RANGE((end_vcol >= 0 && end_vcol <= MAXCOL), "end_vcol", { - return NIL; + return rv; }); } if (start_lnum == end_lnum && start_vcol >= 0 && end_vcol >= 0) { VALIDATE((start_vcol <= end_vcol), "%s", "'start_vcol' is higher than 'end_vcol'", { - return NIL; + return rv; }); } - const int64_t res = win_text_height(win, start_lnum, start_vcol, end_lnum, end_vcol) - + (HAS_KEY(opts->end_row) ? 0 : win_get_fill(win, line_count + 1)); - return INTEGER_OBJ(res); + int64_t fill = 0; + int64_t all = win_text_height(win, start_lnum, start_vcol, end_lnum, end_vcol, &fill); + if (!HAS_KEY(opts->end_row)) { + const int64_t end_fill = win_get_fill(win, line_count + 1); + fill += end_fill; + all += end_fill; + } + PUT_C(rv, "all", INTEGER_OBJ(all)); + PUT_C(rv, "fill", INTEGER_OBJ(fill)); + return rv; } -- cgit From ca9f4a7cb1fea1ef1f22c011679fd8afa0a5d161 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 21 Jul 2023 16:30:05 +0800 Subject: docs: also change "vimL" and "viml" to "Vimscript" (#24414) --- src/nvim/api/buffer.c | 4 ++-- src/nvim/api/vimscript.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 3b73237b06..e6c91df521 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1250,8 +1250,8 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err) /// Otherwise a temporary scratch window (called the "autocmd window" for /// historical reasons) will be used. /// -/// This is useful e.g. to call vimL functions that only work with the current -/// buffer/window currently, like |termopen()|. +/// This is useful e.g. to call Vimscript functions that only work with the +/// current buffer/window currently, like |termopen()|. /// /// @param buffer Buffer handle, or 0 for current buffer /// @param fun Function to call inside the buffer (currently Lua callable diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index eb573e2556..8a598d86f0 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -402,7 +402,7 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack; /// stringified without "kExprNode" prefix. /// - "start": a pair [line, column] describing where node is "started" /// where "line" is always 0 (will not be 0 if you will be -/// using nvim_parse_viml() on e.g. ":let", but that is not +/// using this API on e.g. ":let", but that is not /// present yet). Both elements are Integers. /// - "len": “length” of the node. This and "start" are there for /// debugging purposes primary (debugging parser and providing -- cgit From 24e3ee9d07e1433cb13b4d96ec20999f5f02b204 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sat, 22 Jul 2023 09:52:13 +0100 Subject: fix(api/options): validate buf and win Fixes #24398 --- src/nvim/api/options.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index b9a41adc3b..858a663b9f 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -23,8 +23,8 @@ # include "api/options.c.generated.h" #endif -static int validate_option_value_args(Dict(option) *opts, int *scope, int *opt_type, void **from, - char **filetype, Error *err) +static int validate_option_value_args(Dict(option) *opts, char *name, int *scope, int *opt_type, + void **from, char **filetype, Error *err) { if (HAS_KEY(opts->scope)) { VALIDATE_T("scope", kObjectTypeString, opts->scope.type, { @@ -92,6 +92,24 @@ static int validate_option_value_args(Dict(option) *opts, int *scope, int *opt_t return FAIL; }); + int flags = get_option_value_strict(name, NULL, NULL, 0, NULL); + if (flags == 0) { + // hidden or unknown option + api_set_error(err, kErrorTypeValidation, "Unknown option '%s'", name); + } else if (*opt_type & (SREQ_BUF | SREQ_WIN)) { + // if 'buf' or 'win' is passed, make sure the option supports it + int req_flags = *opt_type & SREQ_BUF ? SOPT_BUF : SOPT_WIN; + if (!(flags & req_flags)) { + char *tgt = *opt_type & SREQ_BUF ? "buf" : "win"; + char *global = flags & SOPT_GLOBAL ? "global ": ""; + char *req = flags & SOPT_BUF ? "buffer-local " : + flags & SOPT_WIN ? "window-local " : ""; + + api_set_error(err, kErrorTypeValidation, "'%s' cannot be passed for %s%soption '%s'", + tgt, global, req, name); + } + } + return OK; } @@ -197,7 +215,7 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) void *from = NULL; char *filetype = NULL; - if (!validate_option_value_args(opts, &scope, &opt_type, &from, &filetype, err)) { + if (!validate_option_value_args(opts, name.data, &scope, &opt_type, &from, &filetype, err)) { goto err; } @@ -259,7 +277,7 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict( int scope = 0; int opt_type = SREQ_GLOBAL; void *to = NULL; - if (!validate_option_value_args(opts, &scope, &opt_type, &to, NULL, err)) { + if (!validate_option_value_args(opts, name.data, &scope, &opt_type, &to, NULL, err)) { return; } @@ -343,7 +361,7 @@ Dictionary nvim_get_option_info2(String name, Dict(option) *opts, Error *err) int scope = 0; int opt_type = SREQ_GLOBAL; void *from = NULL; - if (!validate_option_value_args(opts, &scope, &opt_type, &from, NULL, err)) { + if (!validate_option_value_args(opts, name.data, &scope, &opt_type, &from, NULL, err)) { return (Dictionary)ARRAY_DICT_INIT; } -- cgit From a8cfdf43bc6226e32679ec59769ea3e48ca26193 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 23 Jul 2023 07:16:41 +0800 Subject: fix(events): trigger VimResume on next UI request (#24426) --- src/nvim/api/ui.c | 6 ++++++ src/nvim/api/vim.c | 3 +++ 2 files changed, 9 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 861ce100cd..9fa5a89407 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -215,6 +215,8 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona pmap_put(uint64_t)(&connected_uis, channel_id, ui); ui_attach_impl(ui, channel_id); + + may_trigger_vim_suspend_resume(false); } /// @deprecated @@ -237,6 +239,10 @@ void nvim_ui_set_focus(uint64_t channel_id, Boolean gained, Error *error) return; } + if (gained) { + may_trigger_vim_suspend_resume(false); + } + do_autocmd_focusgained((bool)gained); } diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index b1e472aa8c..8738b3e38e 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -305,6 +305,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks) Integer nvim_input(String keys) FUNC_API_SINCE(1) FUNC_API_FAST { + may_trigger_vim_suspend_resume(false); return (Integer)input_enqueue(keys); } @@ -334,6 +335,8 @@ void nvim_input_mouse(String button, String action, String modifier, Integer gri Integer col, Error *err) FUNC_API_SINCE(6) FUNC_API_FAST { + may_trigger_vim_suspend_resume(false); + if (button.data == NULL || action.data == NULL) { goto error; } -- cgit From 6b4970f6e0ac36021b2a8bd0533f5078040d31f7 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 23 Jul 2023 19:50:20 +0100 Subject: feat(api): allow open_win/win_set_buf in the cmdwin in some cases Problem: As discussed on Matrix, there was some interest in having `nvim_open_win` again be able to open floats in the cmdwin (e.g: displaying a hover doc related to what's in the cmdwin). After #23228, this was disallowed. Solution: Allow `nvim_open_win` in the cmdwin as long as `!enter` and `buffer != curbuf` (the former can cause all sorts of issues, and the latter can crash Nvim after closing cmdwin). Also allow `nvim_win_set_buf` in a similar fashion. Note that we're not *entirely* sure if this is 100% safe (cmdwin is a global-state-using-main-loop-calling beast), but this seems to work OK..? Also: - Check the buffer argument of `nvim_open_win` earlier, and abort if it's invalid (it used to still open a window in this case). - Untranslate `e_cmdwin` errors in the API (other errors in the API are not translated: although not detailed in the API contract yet, errors are supposed to be stable). --- src/nvim/api/vim.c | 2 +- src/nvim/api/win_config.c | 13 +++++++++++-- src/nvim/api/window.c | 15 ++++++++++++--- 3 files changed, 24 insertions(+), 6 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 8738b3e38e..b4a6fa718b 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -967,7 +967,7 @@ Integer nvim_open_term(Buffer buffer, DictionaryOf(LuaRef) opts, Error *err) } if (cmdwin_type != 0 && buf == curbuf) { - api_set_error(err, kErrorTypeException, "%s", _(e_cmdwin)); + api_set_error(err, kErrorTypeException, "%s", e_cmdwin); return 0; } diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 6ca36a0daf..81a239d913 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -158,8 +158,17 @@ /// @return Window handle, or 0 on error Window nvim_open_win(Buffer buffer, Boolean enter, Dict(float_config) *config, Error *err) FUNC_API_SINCE(6) - FUNC_API_TEXTLOCK + FUNC_API_TEXTLOCK_ALLOW_CMDWIN { + buf_T *buf = find_buffer_by_handle(buffer, err); + if (!buf) { + return 0; + } + if (cmdwin_type != 0 && (enter || buf == curbuf)) { + api_set_error(err, kErrorTypeException, "%s", e_cmdwin); + return 0; + } + FloatConfig fconfig = FLOAT_CONFIG_INIT; if (!parse_float_config(config, &fconfig, false, true, err)) { return 0; @@ -173,7 +182,7 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(float_config) *config, E } // autocmds in win_enter or win_set_buf below may close the window if (win_valid(wp) && buffer > 0) { - win_set_buf(wp->handle, buffer, fconfig.noautocmd, err); + win_set_buf(wp, buf, fconfig.noautocmd, err); } if (!win_valid(wp)) { api_set_error(err, kErrorTypeException, "Window was closed immediately"); diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 5480584aa5..666f09e890 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -50,9 +50,18 @@ Buffer nvim_win_get_buf(Window window, Error *err) /// @param[out] err Error details, if any void nvim_win_set_buf(Window window, Buffer buffer, Error *err) FUNC_API_SINCE(5) - FUNC_API_TEXTLOCK + FUNC_API_TEXTLOCK_ALLOW_CMDWIN { - win_set_buf(window, buffer, false, err); + win_T *win = find_window_by_handle(window, err); + buf_T *buf = find_buffer_by_handle(buffer, err); + if (!win || !buf) { + return; + } + if (cmdwin_type != 0 && (win == curwin || buf == curbuf)) { + api_set_error(err, kErrorTypeException, "%s", e_cmdwin); + return; + } + win_set_buf(win, buf, false, err); } /// Gets the (1,0)-indexed, buffer-relative cursor position for a given window @@ -396,7 +405,7 @@ void nvim_win_close(Window window, Boolean force, Error *err) if (win == curwin) { cmdwin_result = Ctrl_C; } else { - api_set_error(err, kErrorTypeException, "%s", _(e_cmdwin)); + api_set_error(err, kErrorTypeException, "%s", e_cmdwin); } return; } -- cgit From 5d921e28c1cc33eced22bbfa823460ca241e3dc1 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 23 Jul 2023 23:10:28 +0100 Subject: feat(api): allow win_close in cmdwin to close wins except previous Disallow closing the previous window from `nvim_win_close`, as this will cause issues. Again, no telling how safe this is. It also requires exposing old_curwin. :/ Also note that it's possible for the `&cmdheight` to change if, for example, there are 2 tabpages and `nvim_win_close` is used to close the last window in the other tabpage while `&stal` is 1. This is addressed in a later commit. --- src/nvim/api/window.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 666f09e890..350d934825 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -404,10 +404,11 @@ void nvim_win_close(Window window, Boolean force, Error *err) if (cmdwin_type != 0) { if (win == curwin) { cmdwin_result = Ctrl_C; - } else { + return; + } else if (win == cmdwin_old_curwin) { api_set_error(err, kErrorTypeException, "%s", e_cmdwin); + return; } - return; } tabpage_T *tabpage = win_find_tabpage(win); -- cgit From 472271199e483d3f23d62c272b20c5290eec5474 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Mon, 24 Jul 2023 14:19:01 +0100 Subject: feat(api): allow win_hide to close cmdwin or non-previous windows This aligns its behaviour better with `nvim_win_close`. Note that `:hide` is actually incapable of closing the cmdwin, unlike `:close` and `:quit`, so this is a bit of a difference in behaviour. --- src/nvim/api/window.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 350d934825..f32a7e671d 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -362,10 +362,10 @@ Boolean nvim_win_is_valid(Window window) /// @param[out] err Error details, if any void nvim_win_hide(Window window, Error *err) FUNC_API_SINCE(7) - FUNC_API_TEXTLOCK + FUNC_API_TEXTLOCK_ALLOW_CMDWIN { win_T *win = find_window_by_handle(window, err); - if (!win) { + if (!win || !can_close_in_cmdwin(win, err)) { return; } @@ -397,20 +397,10 @@ void nvim_win_close(Window window, Boolean force, Error *err) FUNC_API_TEXTLOCK_ALLOW_CMDWIN { win_T *win = find_window_by_handle(window, err); - if (!win) { + if (!win || !can_close_in_cmdwin(win, err)) { return; } - if (cmdwin_type != 0) { - if (win == curwin) { - cmdwin_result = Ctrl_C; - return; - } else if (win == cmdwin_old_curwin) { - api_set_error(err, kErrorTypeException, "%s", e_cmdwin); - return; - } - } - tabpage_T *tabpage = win_find_tabpage(win); TryState tstate; try_enter(&tstate); -- cgit From d2f81330247ee060d557330b2716ccea8f789a50 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 12 Jul 2023 19:27:14 +0200 Subject: docs: misc Co-authored-by: Kevin Pham --- src/nvim/api/autocmd.c | 10 ++++------ src/nvim/api/command.c | 2 ++ src/nvim/api/options.c | 2 ++ 3 files changed, 8 insertions(+), 6 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 0e06594663..6ab1283f89 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -517,11 +517,9 @@ cleanup: return autocmd_id; } -/// Delete an autocommand by id. +/// Deletes an autocommand by id. /// -/// NOTE: Only autocommands created via the API have an id. -/// @param id Integer The id returned by nvim_create_autocmd -/// @see |nvim_create_autocmd()| +/// @param id Integer Autocommand id returned by |nvim_create_autocmd()| void nvim_del_autocmd(Integer id, Error *err) FUNC_API_SINCE(9) { @@ -533,8 +531,8 @@ void nvim_del_autocmd(Integer id, Error *err) } } -/// Clear all autocommands that match the corresponding {opts}. To delete -/// a particular autocmd, see |nvim_del_autocmd()|. +/// Clears all autocommands selected by {opts}. To delete autocmds see |nvim_del_autocmd()|. +/// /// @param opts Parameters /// - event: (string|table) /// Examples: diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index b254e326f9..75140beb88 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -1230,6 +1230,8 @@ err: /// /// Currently only |user-commands| are supported, not builtin Ex commands. /// +/// @see |nvim_get_all_options_info()| +/// /// @param opts Optional parameters. Currently only supports /// {"builtin":false} /// @param[out] err Error details, if any. diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 858a663b9f..3d42f60940 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -315,6 +315,8 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict( /// The dictionary has the full option names as keys and option metadata /// dictionaries as detailed at |nvim_get_option_info2()|. /// +/// @see |nvim_get_commands()| +/// /// @return dictionary of all options Dictionary nvim_get_all_options_info(Error *err) FUNC_API_SINCE(7) -- cgit From 7bc93e0e2f246dd78026a3472d929a0fe450f70d Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 1 Aug 2023 14:01:19 +0200 Subject: refactor(api): use typed keysets Initially this is just for geting rid of boilerplate, but eventually the types could get exposed as metadata --- src/nvim/api/autocmd.c | 92 ++++++------ src/nvim/api/command.c | 240 ++++++++++++------------------ src/nvim/api/deprecated.c | 6 +- src/nvim/api/extmark.c | 166 +++++++-------------- src/nvim/api/keysets.h | 321 ++++++++++++++++++++++------------------- src/nvim/api/options.c | 46 +++--- src/nvim/api/private/defs.h | 12 +- src/nvim/api/private/helpers.c | 87 ++++++++++- src/nvim/api/private/helpers.h | 5 +- src/nvim/api/vim.c | 99 ++++--------- src/nvim/api/vimscript.c | 14 +- src/nvim/api/win_config.c | 206 +++++++++++--------------- src/nvim/api/window.c | 37 ++--- 13 files changed, 603 insertions(+), 728 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 6ab1283f89..aa0c2695ad 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -11,6 +11,7 @@ #include "lauxlib.h" #include "nvim/api/autocmd.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/ascii.h" @@ -125,7 +126,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) }); } - if (HAS_KEY(opts->event)) { + if (HAS_KEY(opts, get_autocmds, event)) { check_event = true; Object v = opts->event; @@ -148,13 +149,13 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) } } - VALIDATE((!HAS_KEY(opts->pattern) || !HAS_KEY(opts->buffer)), + VALIDATE((!HAS_KEY(opts, get_autocmds, pattern) || !HAS_KEY(opts, get_autocmds, buffer)), "%s", "Cannot use both 'pattern' and 'buffer'", { goto cleanup; }); int pattern_filter_count = 0; - if (HAS_KEY(opts->pattern)) { + if (HAS_KEY(opts, get_autocmds, pattern)) { Object v = opts->pattern; if (v.type == kObjectTypeString) { pattern_filters[pattern_filter_count] = v.data.string.data; @@ -209,7 +210,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) snprintf(pattern_buflocal, BUFLOCAL_PAT_LEN, "", (int)buf->handle); ADD(buffers, CSTR_TO_OBJ(pattern_buflocal)); }); - } else if (HAS_KEY(opts->buffer)) { + } else if (HAS_KEY(opts, get_autocmds, buffer)) { VALIDATE_EXP(false, "buffer", "Integer or Array", api_typename(opts->buffer.type), { goto cleanup; }); @@ -408,12 +409,12 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc goto cleanup; } - VALIDATE((!HAS_KEY(opts->callback) || !HAS_KEY(opts->command)), + VALIDATE((!HAS_KEY(opts, create_autocmd, callback) || !HAS_KEY(opts, create_autocmd, command)), "%s", "Cannot use both 'callback' and 'command'", { goto cleanup; }); - if (HAS_KEY(opts->callback)) { + if (HAS_KEY(opts, create_autocmd, callback)) { // NOTE: We could accept callable tables, but that isn't common in the API. Object *callback = &opts->callback; @@ -442,36 +443,33 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc aucmd.type = CALLABLE_CB; aucmd.callable.cb = cb; - } else if (HAS_KEY(opts->command)) { - Object *command = &opts->command; - VALIDATE_T("command", kObjectTypeString, command->type, { - goto cleanup; - }); + } else if (HAS_KEY(opts, create_autocmd, command)) { aucmd.type = CALLABLE_EX; - aucmd.callable.cmd = string_to_cstr(command->data.string); + aucmd.callable.cmd = string_to_cstr(opts->command); } else { VALIDATE(false, "%s", "Required: 'command' or 'callback'", { goto cleanup; }); } - bool is_once = api_object_to_bool(opts->once, "once", false, err); - bool is_nested = api_object_to_bool(opts->nested, "nested", false, err); - int au_group = get_augroup_from_object(opts->group, err); if (au_group == AUGROUP_ERROR) { goto cleanup; } - if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, opts->buffer, err)) { + bool has_buffer = HAS_KEY(opts, create_autocmd, buffer); + + VALIDATE((!HAS_KEY(opts, create_autocmd, pattern) || !has_buffer), + "%s", "Cannot use both 'pattern' and 'buffer' for the same autocmd", { + goto cleanup; + }); + + if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, has_buffer, opts->buffer, err)) { goto cleanup; } - if (HAS_KEY(opts->desc)) { - VALIDATE_T("desc", kObjectTypeString, opts->desc.type, { - goto cleanup; - }); - desc = opts->desc.data.string.data; + if (HAS_KEY(opts, create_autocmd, desc)) { + desc = opts->desc.data; } if (patterns.size == 0) { @@ -496,8 +494,8 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc pat.data.string.data, (int)pat.data.string.size, au_group, - is_once, - is_nested, + opts->once, + opts->nested, desc, aucmd); }); @@ -568,7 +566,9 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err) goto cleanup; } - VALIDATE((!HAS_KEY(opts->pattern) || !HAS_KEY(opts->buffer)), + bool has_buffer = HAS_KEY(opts, clear_autocmds, buffer); + + VALIDATE((!HAS_KEY(opts, clear_autocmds, pattern) || !has_buffer), "%s", "Cannot use both 'pattern' and 'buffer'", { goto cleanup; }); @@ -578,7 +578,7 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err) goto cleanup; } - if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, opts->buffer, err)) { + if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, has_buffer, opts->buffer, err)) { goto cleanup; } @@ -742,21 +742,22 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err) }); } - if (HAS_KEY(opts->buffer)) { - Object buf_obj = opts->buffer; - VALIDATE_EXP((buf_obj.type == kObjectTypeInteger || buf_obj.type == kObjectTypeBuffer), - "buffer", "Integer", api_typename(buf_obj.type), { + bool has_buffer = false; + if (HAS_KEY(opts, exec_autocmds, buffer)) { + VALIDATE((!HAS_KEY(opts, exec_autocmds, pattern)), + "%s", "Cannot use both 'pattern' and 'buffer' for the same autocmd", { goto cleanup; }); - buf = find_buffer_by_handle((Buffer)buf_obj.data.integer, err); + has_buffer = true; + buf = find_buffer_by_handle(opts->buffer, err); if (ERROR_SET(err)) { goto cleanup; } } - if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, opts->buffer, err)) { + if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, has_buffer, opts->buffer, err)) { goto cleanup; } @@ -764,20 +765,19 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err) ADD(patterns, STATIC_CSTR_TO_OBJ("")); } - if (HAS_KEY(opts->data)) { + if (HAS_KEY(opts, exec_autocmds, data)) { data = &opts->data; } - modeline = api_object_to_bool(opts->modeline, "modeline", true, err); + modeline = GET_BOOL_OR_TRUE(opts, exec_autocmds, modeline); bool did_aucmd = false; FOREACH_ITEM(event_array, event_str, { GET_ONE_EVENT(event_nr, event_str, cleanup) FOREACH_ITEM(patterns, pat, { - char *fname = !HAS_KEY(opts->buffer) ? pat.data.string.data : NULL; - did_aucmd |= - apply_autocmds_group(event_nr, fname, NULL, true, au_group, buf, NULL, data); + char *fname = !has_buffer ? pat.data.string.data : NULL; + did_aucmd |= apply_autocmds_group(event_nr, fname, NULL, true, au_group, buf, NULL, data); }) }) @@ -837,17 +837,12 @@ static int get_augroup_from_object(Object group, Error *err) } } -static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Object buffer, - Error *err) +static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, bool has_buffer, + Buffer buffer, Error *err) { const char pattern_buflocal[BUFLOCAL_PAT_LEN]; - VALIDATE((!HAS_KEY(pattern) || !HAS_KEY(buffer)), - "%s", "Cannot use both 'pattern' and 'buffer' for the same autocmd", { - return false; - }); - - if (HAS_KEY(pattern)) { + if (pattern.type != kObjectTypeNil) { Object *v = &pattern; if (v->type == kObjectTypeString) { @@ -880,13 +875,8 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob return false; }); } - } else if (HAS_KEY(buffer)) { - VALIDATE_EXP((buffer.type == kObjectTypeInteger || buffer.type == kObjectTypeBuffer), - "buffer", "Integer", api_typename(buffer.type), { - return false; - }); - - buf_T *buf = find_buffer_by_handle((Buffer)buffer.data.integer, err); + } else if (has_buffer) { + buf_T *buf = find_buffer_by_handle(buffer, err); if (ERROR_SET(err)) { return false; } diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 75140beb88..2b09cfc4b2 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -341,16 +341,6 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } \ } while (0) -#define OBJ_TO_CMOD_FLAG(flag, value, default, varname) \ - do { \ - if (api_object_to_bool(value, varname, default, err)) { \ - cmdinfo.cmdmod.cmod_flags |= (flag); \ - } \ - if (ERROR_SET(err)) { \ - goto end; \ - } \ - } while (0) - #define VALIDATE_MOD(cond, mod_, name_) \ do { \ if (!(cond)) { \ @@ -359,18 +349,14 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } \ } while (0) - bool output; - OBJ_TO_BOOL(output, opts->output, false, "'output'"); - - VALIDATE_R(HAS_KEY(cmd->cmd), "cmd", { + VALIDATE_R(HAS_KEY(cmd, cmd, cmd), "cmd", { goto end; }); - VALIDATE_EXP((cmd->cmd.type == kObjectTypeString && cmd->cmd.data.string.data[0] != NUL), - "cmd", "non-empty String", NULL, { + VALIDATE_EXP((cmd->cmd.data[0] != NUL), "cmd", "non-empty String", NULL, { goto end; }); - cmdname = string_to_cstr(cmd->cmd.data.string); + cmdname = string_to_cstr(cmd->cmd); ea.cmd = cmdname; char *p = find_ex_command(&ea, NULL); @@ -407,15 +393,11 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } // Parse command arguments since it's needed to get the command address type. - if (HAS_KEY(cmd->args)) { - VALIDATE_T("args", kObjectTypeArray, cmd->args.type, { - goto end; - }); - + if (HAS_KEY(cmd, cmd, args)) { // Process all arguments. Convert non-String arguments to String and check if String arguments // have non-whitespace characters. - for (size_t i = 0; i < cmd->args.data.array.size; i++) { - Object elem = cmd->args.data.array.items[i]; + for (size_t i = 0; i < cmd->args.size; i++) { + Object elem = cmd->args.items[i]; char *data_str; switch (elem.type) { @@ -477,16 +459,13 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error // since it only ever checks the first argument. set_cmd_addr_type(&ea, args.size > 0 ? args.items[0].data.string.data : NULL); - if (HAS_KEY(cmd->range)) { - VALIDATE_MOD((ea.argt & EX_RANGE), "range", cmd->cmd.data.string.data); - VALIDATE_T("range", kObjectTypeArray, cmd->range.type, { - goto end; - }); - VALIDATE_EXP((cmd->range.data.array.size <= 2), "range", "<=2 elements", NULL, { + if (HAS_KEY(cmd, cmd, range)) { + VALIDATE_MOD((ea.argt & EX_RANGE), "range", cmd->cmd.data); + VALIDATE_EXP((cmd->range.size <= 2), "range", "<=2 elements", NULL, { goto end; }); - Array range = cmd->range.data.array; + Array range = cmd->range; ea.addr_count = (int)range.size; for (size_t i = 0; i < range.size; i++) { @@ -519,22 +498,21 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } } - if (HAS_KEY(cmd->count)) { - VALIDATE_MOD((ea.argt & EX_COUNT), "count", cmd->cmd.data.string.data); - VALIDATE_EXP((cmd->count.type == kObjectTypeInteger && cmd->count.data.integer >= 0), - "count", "non-negative Integer", NULL, { + if (HAS_KEY(cmd, cmd, count)) { + VALIDATE_MOD((ea.argt & EX_COUNT), "count", cmd->cmd.data); + VALIDATE_EXP((cmd->count >= 0), "count", "non-negative Integer", NULL, { goto end; }); - set_cmd_count(&ea, (linenr_T)cmd->count.data.integer, true); + set_cmd_count(&ea, (linenr_T)cmd->count, true); } - if (HAS_KEY(cmd->reg)) { - VALIDATE_MOD((ea.argt & EX_REGSTR), "register", cmd->cmd.data.string.data); - VALIDATE_EXP((cmd->reg.type == kObjectTypeString && cmd->reg.data.string.size == 1), - "reg", "single character", cmd->reg.data.string.data, { + if (HAS_KEY(cmd, cmd, reg)) { + VALIDATE_MOD((ea.argt & EX_REGSTR), "register", cmd->cmd.data); + VALIDATE_EXP((cmd->reg.size == 1), + "reg", "single character", cmd->reg.data, { goto end; }); - char regname = cmd->reg.data.string.data[0]; + char regname = cmd->reg.data[0]; VALIDATE((regname != '='), "%s", "Cannot use register \"=", { goto end; }); @@ -545,22 +523,17 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error ea.regname = (uint8_t)regname; } - OBJ_TO_BOOL(ea.forceit, cmd->bang, false, "'bang'"); - VALIDATE_MOD((!ea.forceit || (ea.argt & EX_BANG)), "bang", cmd->cmd.data.string.data); + ea.forceit = cmd->bang; + VALIDATE_MOD((!ea.forceit || (ea.argt & EX_BANG)), "bang", cmd->cmd.data); - if (HAS_KEY(cmd->magic)) { - VALIDATE_T_DICT("magic", cmd->magic, { - goto end; - }); - - Dict(cmd_magic) magic = { 0 }; - if (!api_dict_to_keydict(&magic, KeyDict_cmd_magic_get_field, - cmd->magic.data.dictionary, err)) { + if (HAS_KEY(cmd, cmd, magic)) { + Dict(cmd_magic) magic[1] = { 0 }; + if (!api_dict_to_keydict(magic, KeyDict_cmd_magic_get_field, cmd->magic, err)) { goto end; } - OBJ_TO_BOOL(cmdinfo.magic.file, magic.file, ea.argt & EX_XFILE, "'magic.file'"); - OBJ_TO_BOOL(cmdinfo.magic.bar, magic.bar, ea.argt & EX_TRLBAR, "'magic.bar'"); + cmdinfo.magic.file = HAS_KEY(magic, cmd_magic, file) ? magic->file : (ea.argt & EX_XFILE); + cmdinfo.magic.bar = HAS_KEY(magic, cmd_magic, bar) ? magic->bar : (ea.argt & EX_TRLBAR); if (cmdinfo.magic.file) { ea.argt |= EX_XFILE; } else { @@ -571,89 +544,63 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error cmdinfo.magic.bar = ea.argt & EX_TRLBAR; } - if (HAS_KEY(cmd->mods)) { - VALIDATE_T_DICT("mods", cmd->mods, { - goto end; - }); - - Dict(cmd_mods) mods = { 0 }; - if (!api_dict_to_keydict(&mods, KeyDict_cmd_mods_get_field, cmd->mods.data.dictionary, err)) { + if (HAS_KEY(cmd, cmd, mods)) { + Dict(cmd_mods) mods[1] = { 0 }; + if (!api_dict_to_keydict(mods, KeyDict_cmd_mods_get_field, cmd->mods, err)) { goto end; } - if (HAS_KEY(mods.filter)) { - VALIDATE_T_DICT("mods.filter", mods.filter, { - goto end; - }); - - Dict(cmd_mods_filter) filter = { 0 }; + if (HAS_KEY(mods, cmd_mods, filter)) { + Dict(cmd_mods_filter) filter[1] = { 0 }; if (!api_dict_to_keydict(&filter, KeyDict_cmd_mods_filter_get_field, - mods.filter.data.dictionary, err)) { + mods->filter, err)) { goto end; } - if (HAS_KEY(filter.pattern)) { - VALIDATE_T2(filter.pattern, kObjectTypeString, { - goto end; - }); - - OBJ_TO_BOOL(cmdinfo.cmdmod.cmod_filter_force, filter.force, false, "'mods.filter.force'"); + if (HAS_KEY(filter, cmd_mods_filter, pattern)) { + cmdinfo.cmdmod.cmod_filter_force = filter->force; // "filter! // is not no-op, so add a filter if either the pattern is non-empty or if filter // is inverted. - if (*filter.pattern.data.string.data != NUL || cmdinfo.cmdmod.cmod_filter_force) { - cmdinfo.cmdmod.cmod_filter_pat = string_to_cstr(filter.pattern.data.string); + if (*filter->pattern.data != NUL || cmdinfo.cmdmod.cmod_filter_force) { + cmdinfo.cmdmod.cmod_filter_pat = string_to_cstr(filter->pattern); cmdinfo.cmdmod.cmod_filter_regmatch.regprog = vim_regcomp(cmdinfo.cmdmod.cmod_filter_pat, RE_MAGIC); } } } - if (HAS_KEY(mods.tab)) { - VALIDATE_T2(mods.tab, kObjectTypeInteger, { - goto end; - }); - if ((int)mods.tab.data.integer >= 0) { + if (HAS_KEY(mods, cmd_mods, tab)) { + if ((int)mods->tab >= 0) { // Silently ignore negative integers to allow mods.tab to be set to -1. - cmdinfo.cmdmod.cmod_tab = (int)mods.tab.data.integer + 1; + cmdinfo.cmdmod.cmod_tab = (int)mods->tab + 1; } } - if (HAS_KEY(mods.verbose)) { - VALIDATE_T2(mods.verbose, kObjectTypeInteger, { - goto end; - }); - if ((int)mods.verbose.data.integer >= 0) { + if (HAS_KEY(mods, cmd_mods, verbose)) { + if ((int)mods->verbose >= 0) { // Silently ignore negative integers to allow mods.verbose to be set to -1. - cmdinfo.cmdmod.cmod_verbose = (int)mods.verbose.data.integer + 1; + cmdinfo.cmdmod.cmod_verbose = (int)mods->verbose + 1; } } - bool vertical; - OBJ_TO_BOOL(vertical, mods.vertical, false, "'mods.vertical'"); - cmdinfo.cmdmod.cmod_split |= (vertical ? WSP_VERT : 0); + cmdinfo.cmdmod.cmod_split |= (mods->vertical ? WSP_VERT : 0); - bool horizontal; - OBJ_TO_BOOL(horizontal, mods.horizontal, false, "'mods.horizontal'"); - cmdinfo.cmdmod.cmod_split |= (horizontal ? WSP_HOR : 0); + cmdinfo.cmdmod.cmod_split |= (mods->horizontal ? WSP_HOR : 0); - if (HAS_KEY(mods.split)) { - VALIDATE_T2(mods.split, kObjectTypeString, { - goto end; - }); - - if (*mods.split.data.string.data == NUL) { + if (HAS_KEY(mods, cmd_mods, split)) { + if (*mods->split.data == NUL) { // Empty string, do nothing. - } else if (strcmp(mods.split.data.string.data, "aboveleft") == 0 - || strcmp(mods.split.data.string.data, "leftabove") == 0) { + } else if (strcmp(mods->split.data, "aboveleft") == 0 + || strcmp(mods->split.data, "leftabove") == 0) { cmdinfo.cmdmod.cmod_split |= WSP_ABOVE; - } else if (strcmp(mods.split.data.string.data, "belowright") == 0 - || strcmp(mods.split.data.string.data, "rightbelow") == 0) { + } else if (strcmp(mods->split.data, "belowright") == 0 + || strcmp(mods->split.data, "rightbelow") == 0) { cmdinfo.cmdmod.cmod_split |= WSP_BELOW; - } else if (strcmp(mods.split.data.string.data, "topleft") == 0) { + } else if (strcmp(mods->split.data, "topleft") == 0) { cmdinfo.cmdmod.cmod_split |= WSP_TOP; - } else if (strcmp(mods.split.data.string.data, "botright") == 0) { + } else if (strcmp(mods->split.data, "botright") == 0) { cmdinfo.cmdmod.cmod_split |= WSP_BOT; } else { VALIDATE_S(false, "mods.split", "", { @@ -662,20 +609,25 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } } - OBJ_TO_CMOD_FLAG(CMOD_SILENT, mods.silent, false, "'mods.silent'"); - OBJ_TO_CMOD_FLAG(CMOD_ERRSILENT, mods.emsg_silent, false, "'mods.emsg_silent'"); - OBJ_TO_CMOD_FLAG(CMOD_UNSILENT, mods.unsilent, false, "'mods.unsilent'"); - OBJ_TO_CMOD_FLAG(CMOD_SANDBOX, mods.sandbox, false, "'mods.sandbox'"); - OBJ_TO_CMOD_FLAG(CMOD_NOAUTOCMD, mods.noautocmd, false, "'mods.noautocmd'"); - OBJ_TO_CMOD_FLAG(CMOD_BROWSE, mods.browse, false, "'mods.browse'"); - OBJ_TO_CMOD_FLAG(CMOD_CONFIRM, mods.confirm, false, "'mods.confirm'"); - OBJ_TO_CMOD_FLAG(CMOD_HIDE, mods.hide, false, "'mods.hide'"); - OBJ_TO_CMOD_FLAG(CMOD_KEEPALT, mods.keepalt, false, "'mods.keepalt'"); - OBJ_TO_CMOD_FLAG(CMOD_KEEPJUMPS, mods.keepjumps, false, "'mods.keepjumps'"); - OBJ_TO_CMOD_FLAG(CMOD_KEEPMARKS, mods.keepmarks, false, "'mods.keepmarks'"); - OBJ_TO_CMOD_FLAG(CMOD_KEEPPATTERNS, mods.keeppatterns, false, "'mods.keeppatterns'"); - OBJ_TO_CMOD_FLAG(CMOD_LOCKMARKS, mods.lockmarks, false, "'mods.lockmarks'"); - OBJ_TO_CMOD_FLAG(CMOD_NOSWAPFILE, mods.noswapfile, false, "'mods.noswapfile'"); +#define OBJ_TO_CMOD_FLAG(flag, value) \ + if (value) { \ + cmdinfo.cmdmod.cmod_flags |= (flag); \ + } + + OBJ_TO_CMOD_FLAG(CMOD_SILENT, mods->silent); + OBJ_TO_CMOD_FLAG(CMOD_ERRSILENT, mods->emsg_silent); + OBJ_TO_CMOD_FLAG(CMOD_UNSILENT, mods->unsilent); + OBJ_TO_CMOD_FLAG(CMOD_SANDBOX, mods->sandbox); + OBJ_TO_CMOD_FLAG(CMOD_NOAUTOCMD, mods->noautocmd); + OBJ_TO_CMOD_FLAG(CMOD_BROWSE, mods->browse); + OBJ_TO_CMOD_FLAG(CMOD_CONFIRM, mods->confirm); + OBJ_TO_CMOD_FLAG(CMOD_HIDE, mods->hide); + OBJ_TO_CMOD_FLAG(CMOD_KEEPALT, mods->keepalt); + OBJ_TO_CMOD_FLAG(CMOD_KEEPJUMPS, mods->keepjumps); + OBJ_TO_CMOD_FLAG(CMOD_KEEPMARKS, mods->keepmarks); + OBJ_TO_CMOD_FLAG(CMOD_KEEPPATTERNS, mods->keeppatterns); + OBJ_TO_CMOD_FLAG(CMOD_LOCKMARKS, mods->lockmarks); + OBJ_TO_CMOD_FLAG(CMOD_NOSWAPFILE, mods->noswapfile); if (cmdinfo.cmdmod.cmod_flags & CMOD_ERRSILENT) { // CMOD_ERRSILENT must imply CMOD_SILENT, otherwise apply_cmdmod() and undo_cmdmod() won't @@ -699,13 +651,13 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error garray_T * const save_capture_ga = capture_ga; const int save_msg_col = msg_col; - if (output) { + if (opts->output) { ga_init(&capture_local, 1, 80); capture_ga = &capture_local; } TRY_WRAP(err, { - if (output) { + if (opts->output) { msg_silent++; msg_col = 0; // prevent leading spaces } @@ -714,7 +666,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error execute_cmd(&ea, &cmdinfo, false); }); - if (output) { + if (opts->output) { capture_ga = save_capture_ga; msg_silent = save_msg_silent; // Put msg_col back where it was, since nothing should have been written. @@ -726,7 +678,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error goto clear_ga; } - if (output && capture_local.ga_len > 1) { + if (opts->output && capture_local.ga_len > 1) { retv = (String){ .data = capture_local.ga_data, .size = (size_t)capture_local.ga_len, @@ -740,7 +692,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error goto end; } clear_ga: - if (output) { + if (opts->output) { ga_clear(&capture_local); } end: @@ -1037,7 +989,7 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict( name.data, { goto err; }); - VALIDATE((!HAS_KEY(opts->range) || !HAS_KEY(opts->count)), "%s", + VALIDATE((!HAS_KEY(opts, user_command, range) || !HAS_KEY(opts, user_command, count)), "%s", "Cannot use both 'range' and 'count'", { goto err; }); @@ -1075,13 +1027,14 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict( goto err; }); } - } else if (HAS_KEY(opts->nargs)) { + } else if (HAS_KEY(opts, user_command, nargs)) { VALIDATE_S(false, "nargs", "", { goto err; }); } - VALIDATE((!HAS_KEY(opts->complete) || argt), "%s", "'complete' used without 'nargs'", { + VALIDATE((!HAS_KEY(opts, user_command, complete) || argt), + "%s", "'complete' used without 'nargs'", { goto err; }); @@ -1101,7 +1054,7 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict( argt |= EX_RANGE | EX_ZEROR; def = opts->range.data.integer; addr_type_arg = ADDR_LINES; - } else if (HAS_KEY(opts->range)) { + } else if (HAS_KEY(opts, user_command, range)) { VALIDATE_S(false, "range", "", { goto err; }); @@ -1117,13 +1070,13 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict( argt |= EX_COUNT | EX_ZEROR | EX_RANGE; addr_type_arg = ADDR_OTHER; def = opts->count.data.integer; - } else if (HAS_KEY(opts->count)) { + } else if (HAS_KEY(opts, user_command, count)) { VALIDATE_S(false, "count", "", { goto err; }); } - if (HAS_KEY(opts->addr)) { + if (HAS_KEY(opts, user_command, addr)) { VALIDATE_T("addr", kObjectTypeString, opts->addr.type, { goto err; }); @@ -1139,31 +1092,23 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict( } } - if (api_object_to_bool(opts->bang, "bang", false, err)) { + if (opts->bang) { argt |= EX_BANG; - } else if (ERROR_SET(err)) { - goto err; } - if (api_object_to_bool(opts->bar, "bar", false, err)) { + if (opts->bar) { argt |= EX_TRLBAR; - } else if (ERROR_SET(err)) { - goto err; } - if (api_object_to_bool(opts->register_, "register", false, err)) { + if (opts->register_) { argt |= EX_REGSTR; - } else if (ERROR_SET(err)) { - goto err; } - if (api_object_to_bool(opts->keepscript, "keepscript", false, err)) { + if (opts->keepscript) { argt |= EX_KEEPSCRIPT; - } else if (ERROR_SET(err)) { - goto err; } - bool force = api_object_to_bool(opts->force, "force", true, err); + bool force = GET_BOOL_OR_TRUE(opts, user_command, force); if (ERROR_SET(err)) { goto err; } @@ -1178,13 +1123,13 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict( "complete", opts->complete.data.string.data, { goto err; }); - } else if (HAS_KEY(opts->complete)) { + } else if (HAS_KEY(opts, user_command, complete)) { VALIDATE_EXP(false, "complete", "Function or String", NULL, { goto err; }); } - if (HAS_KEY(opts->preview)) { + if (HAS_KEY(opts, user_command, preview)) { VALIDATE_T("preview", kObjectTypeLuaRef, opts->preview.type, { goto err; }); @@ -1254,13 +1199,12 @@ Dictionary nvim_buf_get_commands(Buffer buffer, Dict(get_commands) *opts, Error FUNC_API_SINCE(4) { bool global = (buffer == -1); - bool builtin = api_object_to_bool(opts->builtin, "builtin", false, err); if (ERROR_SET(err)) { return (Dictionary)ARRAY_DICT_INIT; } if (global) { - if (builtin) { + if (opts->builtin) { api_set_error(err, kErrorTypeValidation, "builtin=true not implemented"); return (Dictionary)ARRAY_DICT_INIT; } @@ -1268,7 +1212,7 @@ Dictionary nvim_buf_get_commands(Buffer buffer, Dict(get_commands) *opts, Error } buf_T *buf = find_buffer_by_handle(buffer, err); - if (builtin || !buf) { + if (opts->builtin || !buf) { return (Dictionary)ARRAY_DICT_INIT; } return commands_array(buf); diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 2e3ebd7c39..f5a77ece7e 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -35,8 +35,7 @@ String nvim_exec(uint64_t channel_id, String src, Boolean output, Error *err) FUNC_API_SINCE(7) FUNC_API_DEPRECATED_SINCE(11) { - Dict(exec_opts) opts = { 0 }; - opts.output = BOOLEAN_OBJ(output); + Dict(exec_opts) opts = { .output = output }; return exec_impl(channel_id, src, &opts, err); } @@ -46,8 +45,7 @@ String nvim_command_output(uint64_t channel_id, String command, Error *err) FUNC_API_SINCE(1) FUNC_API_DEPRECATED_SINCE(7) { - Dict(exec_opts) opts = { 0 }; - opts.output = BOOLEAN_OBJ(true); + Dict(exec_opts) opts = { .output = true }; return exec_impl(channel_id, command, &opts, err); } diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index d254373eb0..8a60d81649 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -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; - } -#define OPTION_TO_BOOL(target, name, val) \ - target = api_object_to_bool(opts->name, #name, val, err); \ - if (ERROR_SET(err)) { \ - goto error; \ + opts->end_row = opts->end_line; + did_end_line = true; } - 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; - }); + bool strict = GET_BOOL_OR_TRUE(opts, set_extmark, strict); - 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); - - if (HAS_KEY(opts->virt_lines)) { - VALIDATE_T("virt_lines", kObjectTypeArray, opts->virt_lines.type, { - goto error; - }); + bool virt_lines_leftcol = opts->virt_lines_leftcol; - 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); - - if (HAS_KEY(opts->priority)) { - VALIDATE_T("priority", kObjectTypeInteger, opts->priority.type, { - goto error; - }); - - Integer val = opts->priority.data.integer; + decor.virt_lines_above = opts->virt_lines_above; - VALIDATE_RANGE((val >= 0 && val <= UINT16_MAX), "priority", { + if (HAS_KEY(opts, set_extmark, priority)) { + VALIDATE_RANGE((opts->priority >= 0 && opts->priority <= 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|. diff --git a/src/nvim/api/keysets.h b/src/nvim/api/keysets.h index e08186161a..a47e278cad 100644 --- a/src/nvim/api/keysets.h +++ b/src/nvim/api/keysets.h @@ -4,135 +4,144 @@ #include "nvim/api/private/defs.h" typedef struct { - Object types; + OptionalKeys is_set__context_; + Array types; } Dict(context); typedef struct { - Object on_start; - Object on_buf; - Object on_win; - Object on_line; - Object on_end; - Object _on_hl_def; - Object _on_spell_nav; + OptionalKeys is_set__set_decoration_provider_; + LuaRef on_start; + LuaRef on_buf; + LuaRef on_win; + LuaRef on_line; + LuaRef on_end; + LuaRef _on_hl_def; + LuaRef _on_spell_nav; } Dict(set_decoration_provider); typedef struct { - Object id; - Object end_line; - Object end_row; - Object end_col; + OptionalKeys is_set__set_extmark_; + Integer id; + Integer end_line; + Integer end_row; + Integer end_col; Object hl_group; - Object virt_text; - Object virt_text_pos; - Object virt_text_win_col; - Object virt_text_hide; - Object hl_eol; - Object hl_mode; - Object ephemeral; - Object priority; - Object right_gravity; - Object end_right_gravity; - Object virt_lines; - Object virt_lines_above; - Object virt_lines_leftcol; - Object strict; - Object sign_text; + Array virt_text; + String virt_text_pos; + Integer virt_text_win_col; + Boolean virt_text_hide; + Boolean hl_eol; + String hl_mode; + Boolean ephemeral; + Integer priority; + Boolean right_gravity; + Boolean end_right_gravity; + Array virt_lines; + Boolean virt_lines_above; + Boolean virt_lines_leftcol; + Boolean strict; + String sign_text; Object sign_hl_group; Object number_hl_group; Object line_hl_group; Object cursorline_hl_group; - Object conceal; - Object spell; - Object ui_watched; + String conceal; + Boolean spell; + Boolean ui_watched; } Dict(set_extmark); typedef struct { - Object noremap; - Object nowait; - Object silent; - Object script; - Object expr; - Object unique; - Object callback; - Object desc; - Object replace_keycodes; + OptionalKeys is_set__keymap_; + Boolean noremap; + Boolean nowait; + Boolean silent; + Boolean script; + Boolean expr; + Boolean unique; + LuaRef callback; + String desc; + Boolean replace_keycodes; } Dict(keymap); typedef struct { - Object builtin; + Boolean builtin; } Dict(get_commands); typedef struct { + OptionalKeys is_set__user_command_; Object addr; - Object bang; - Object bar; + Boolean bang; + Boolean bar; Object complete; Object count; Object desc; - Object force; - Object keepscript; + Boolean force; + Boolean keepscript; Object nargs; Object preview; Object range; - Object register_; + Boolean register_; } Dict(user_command); typedef struct { - Object row; - Object col; - Object width; - Object height; - Object anchor; - Object relative; - Object win; - Object bufpos; - Object external; - Object focusable; - Object zindex; + OptionalKeys is_set__float_config_; + Float row; + Float col; + Integer width; + Integer height; + String anchor; + String relative; + Window win; + Array bufpos; + Boolean external; + Boolean focusable; + Integer zindex; Object border; Object title; - Object title_pos; - Object style; - Object noautocmd; + String title_pos; + String style; + Boolean noautocmd; } Dict(float_config); typedef struct { - Object is_lua; - Object do_source; + Boolean is_lua; + Boolean do_source; } Dict(runtime); typedef struct { - Object winid; - Object maxwidth; - Object fillchar; - Object highlights; - Object use_winbar; - Object use_tabline; - Object use_statuscol_lnum; + OptionalKeys is_set__eval_statusline_; + Window winid; + Integer maxwidth; + String fillchar; + Boolean highlights; + Boolean use_winbar; + Boolean use_tabline; + Integer use_statuscol_lnum; } Dict(eval_statusline); typedef struct { - Object scope; - Object win; - Object buf; - Object filetype; + OptionalKeys is_set__option_; + String scope; + Window win; + Buffer buf; + String filetype; } Dict(option); typedef struct { - Object bold; - Object standout; - Object strikethrough; - Object underline; - Object undercurl; - Object underdouble; - Object underdotted; - Object underdashed; - Object italic; - Object reverse; - Object altfont; - Object nocombine; - Object default_; + OptionalKeys is_set__highlight_; + Boolean bold; + Boolean standout; + Boolean strikethrough; + Boolean underline; + Boolean undercurl; + Boolean underdouble; + Boolean underdotted; + Boolean underdashed; + Boolean italic; + Boolean reverse; + Boolean altfont; + Boolean nocombine; + Boolean default_; Object cterm; Object foreground; Object fg; @@ -144,67 +153,73 @@ typedef struct { Object sp; Object link; Object global_link; - Object fallback; - Object blend; - Object fg_indexed; - Object bg_indexed; + Boolean fallback; + Integer blend; + Boolean fg_indexed; + Boolean bg_indexed; } Dict(highlight); typedef struct { - Object bold; - Object standout; - Object strikethrough; - Object underline; - Object undercurl; - Object underdouble; - Object underdotted; - Object underdashed; - Object italic; - Object reverse; - Object altfont; - Object nocombine; + Boolean bold; + Boolean standout; + Boolean strikethrough; + Boolean underline; + Boolean undercurl; + Boolean underdouble; + Boolean underdotted; + Boolean underdashed; + Boolean italic; + Boolean reverse; + Boolean altfont; + Boolean nocombine; } Dict(highlight_cterm); typedef struct { - Object id; - Object name; - Object link; + OptionalKeys is_set__get_highlight_; + Integer id; + String name; + Boolean link; } Dict(get_highlight); typedef struct { - Object start_row; - Object end_row; - Object start_vcol; - Object end_vcol; + OptionalKeys is_set__win_text_height_; + Integer start_row; + Integer end_row; + Integer start_vcol; + Integer end_vcol; } Dict(win_text_height); typedef struct { - Object buffer; + OptionalKeys is_set__clear_autocmds_; + Buffer buffer; Object event; Object group; Object pattern; } Dict(clear_autocmds); typedef struct { - Object buffer; + OptionalKeys is_set__create_autocmd_; + Buffer buffer; Object callback; - Object command; - Object desc; + String command; + String desc; Object group; - Object nested; - Object once; + Boolean nested; + Boolean once; Object pattern; } Dict(create_autocmd); typedef struct { - Object buffer; + OptionalKeys is_set__exec_autocmds_; + Buffer buffer; Object group; - Object modeline; + Boolean modeline; Object pattern; Object data; } Dict(exec_autocmds); typedef struct { + OptionalKeys is_set__get_autocmds_; Object event; Object group; Object pattern; @@ -216,62 +231,66 @@ typedef struct { } Dict(create_augroup); typedef struct { - Object cmd; - Object range; - Object count; - Object reg; - Object bang; - Object args; - Object magic; - Object mods; + OptionalKeys is_set__cmd_; + String cmd; + Array range; + Integer count; + String reg; + Boolean bang; + Array args; + Dictionary magic; + Dictionary mods; Object nargs; Object addr; Object nextcmd; } Dict(cmd); typedef struct { - Object file; - Object bar; + OptionalKeys is_set__cmd_magic_; + Boolean file; + Boolean bar; } Dict(cmd_magic); typedef struct { - Object silent; - Object emsg_silent; - Object unsilent; - Object filter; - Object sandbox; - Object noautocmd; - Object browse; - Object confirm; - Object hide; - Object horizontal; - Object keepalt; - Object keepjumps; - Object keepmarks; - Object keeppatterns; - Object lockmarks; - Object noswapfile; - Object tab; - Object verbose; - Object vertical; - Object split; + OptionalKeys is_set__cmd_mods_; + Boolean silent; + Boolean emsg_silent; + Boolean unsilent; + Dictionary filter; + Boolean sandbox; + Boolean noautocmd; + Boolean browse; + Boolean confirm; + Boolean hide; + Boolean horizontal; + Boolean keepalt; + Boolean keepjumps; + Boolean keepmarks; + Boolean keeppatterns; + Boolean lockmarks; + Boolean noswapfile; + Integer tab; + Integer verbose; + Boolean vertical; + String split; } Dict(cmd_mods); typedef struct { - Object pattern; - Object force; + OptionalKeys is_set__cmd_mods_filter_; + String pattern; + Boolean force; } Dict(cmd_mods_filter); typedef struct { - Object output; + Boolean output; } Dict(cmd_opts); typedef struct { - Object verbose; + Boolean verbose; } Dict(echo_opts); typedef struct { - Object output; + Boolean output; } Dict(exec_opts); #endif // NVIM_API_KEYSETS_H diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 3d42f60940..e33cb72e8d 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -8,6 +8,7 @@ #include "nvim/api/options.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/autocmd.h" @@ -26,14 +27,11 @@ static int validate_option_value_args(Dict(option) *opts, char *name, int *scope, int *opt_type, void **from, char **filetype, Error *err) { - if (HAS_KEY(opts->scope)) { - VALIDATE_T("scope", kObjectTypeString, opts->scope.type, { - return FAIL; - }); - - if (!strcmp(opts->scope.data.string.data, "local")) { +#define HAS_KEY_X(d, v) HAS_KEY(d, option, v) + if (HAS_KEY_X(opts, scope)) { + if (!strcmp(opts->scope.data, "local")) { *scope = OPT_LOCAL; - } else if (!strcmp(opts->scope.data.string.data, "global")) { + } else if (!strcmp(opts->scope.data, "global")) { *scope = OPT_GLOBAL; } else { VALIDATE_EXP(false, "scope", "'local' or 'global'", NULL, { @@ -44,51 +42,40 @@ static int validate_option_value_args(Dict(option) *opts, char *name, int *scope *opt_type = SREQ_GLOBAL; - if (filetype != NULL && HAS_KEY(opts->filetype)) { - VALIDATE_T("scope", kObjectTypeString, opts->filetype.type, { - return FAIL; - }); - - *filetype = opts->filetype.data.string.data; + if (filetype != NULL && HAS_KEY_X(opts, filetype)) { + *filetype = opts->filetype.data; } - if (HAS_KEY(opts->win)) { - VALIDATE_T_HANDLE("win", kObjectTypeWindow, opts->win.type, { - return FAIL; - }); - + if (HAS_KEY_X(opts, win)) { *opt_type = SREQ_WIN; - *from = find_window_by_handle((int)opts->win.data.integer, err); + *from = find_window_by_handle(opts->win, err); if (ERROR_SET(err)) { return FAIL; } } - if (HAS_KEY(opts->buf)) { - VALIDATE_T_HANDLE("buf", kObjectTypeBuffer, opts->buf.type, { - return FAIL; - }); - + if (HAS_KEY_X(opts, buf)) { *scope = OPT_LOCAL; *opt_type = SREQ_BUF; - *from = find_buffer_by_handle((int)opts->buf.data.integer, err); + *from = find_buffer_by_handle(opts->buf, err); if (ERROR_SET(err)) { return FAIL; } } - VALIDATE((!HAS_KEY(opts->filetype) - || !(HAS_KEY(opts->buf) || HAS_KEY(opts->scope) || HAS_KEY(opts->win))), + VALIDATE((!HAS_KEY_X(opts, filetype) + || !(HAS_KEY_X(opts, buf) || HAS_KEY_X(opts, scope) || HAS_KEY_X(opts, win))), "%s", "cannot use 'filetype' with 'scope', 'buf' or 'win'", { return FAIL; }); - VALIDATE((!HAS_KEY(opts->scope) || !HAS_KEY(opts->buf)), "%s", + VALIDATE((!HAS_KEY_X(opts, scope) || !HAS_KEY_X(opts, buf)), "%s", "cannot use both 'scope' and 'buf'", { return FAIL; }); - VALIDATE((!HAS_KEY(opts->win) || !HAS_KEY(opts->buf)), "%s", "cannot use both 'buf' and 'win'", { + VALIDATE((!HAS_KEY_X(opts, win) || !HAS_KEY_X(opts, buf)), + "%s", "cannot use both 'buf' and 'win'", { return FAIL; }); @@ -111,6 +98,7 @@ static int validate_option_value_args(Dict(option) *opts, char *name, int *scope } return OK; +#undef HAS_KEY_X } /// Create a dummy buffer and run the FileType autocmd on it. diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index b1b9e383b0..b467ce75a9 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -124,10 +124,20 @@ struct key_value_pair { Object value; }; -typedef Object *(*field_hash)(void *retval, const char *str, size_t len); +typedef uint64_t OptionalKeys; + +// this is the prefix of all keysets with optional keys +typedef struct { + OptionalKeys is_set_; +} OptKeySet; + typedef struct { char *str; size_t ptr_off; + ObjectType type; // kObjectTypeNil == untyped + int opt_index; } KeySetLink; +typedef KeySetLink *(*FieldHashfn)(const char *str, size_t len); + #endif // NVIM_API_PRIVATE_DEFS_H diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index d0c8ab4dd4..bbc87422d0 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -16,6 +16,7 @@ #include "nvim/api/private/converter.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/ascii.h" #include "nvim/buffer_defs.h" #include "nvim/eval/typval.h" @@ -915,17 +916,84 @@ free_exit: return (HlMessage)KV_INITIAL_VALUE; } -bool api_dict_to_keydict(void *rv, field_hash hashy, Dictionary dict, Error *err) +// see also nlua_pop_keydict for the lua specific implementation +bool api_dict_to_keydict(void *retval, FieldHashfn hashy, Dictionary dict, Error *err) { for (size_t i = 0; i < dict.size; i++) { String k = dict.items[i].key; - Object *field = hashy(rv, k.data, k.size); + KeySetLink *field = hashy(k.data, k.size); if (!field) { api_set_error(err, kErrorTypeValidation, "Invalid key: '%.*s'", (int)k.size, k.data); return false; } - *field = dict.items[i].value; + if (field->opt_index >= 0) { + OptKeySet *ks = (OptKeySet *)retval; + ks->is_set_ |= (1ULL << field->opt_index); + } + + char *mem = ((char *)retval + field->ptr_off); + Object *value = &dict.items[i].value; + if (field->type == kObjectTypeNil) { + *(Object *)mem = *value; + } else if (field->type == kObjectTypeInteger) { + VALIDATE_T(field->str, kObjectTypeInteger, value->type, { + return false; + }); + *(Integer *)mem = value->data.integer; + } else if (field->type == kObjectTypeFloat) { + Float *val = (Float *)mem; + if (value->type == kObjectTypeInteger) { + *val = (Float)value->data.integer; + } else { + VALIDATE_T(field->str, kObjectTypeFloat, value->type, { + return false; + }); + *val = value->data.floating; + } + } else if (field->type == kObjectTypeBoolean) { + // caller should check HAS_KEY to override the nil behavior, or GET_BOOL_OR_TRUE + // to directly use true when nil + *(Boolean *)mem = api_object_to_bool(*value, field->str, false, err); + if (ERROR_SET(err)) { + return false; + } + } else if (field->type == kObjectTypeString) { + VALIDATE_T(field->str, kObjectTypeString, value->type, { + return false; + }); + *(String *)mem = value->data.string; + } else if (field->type == kObjectTypeArray) { + VALIDATE_T(field->str, kObjectTypeArray, value->type, { + return false; + }); + *(Array *)mem = value->data.array; + } else if (field->type == kObjectTypeDictionary) { + Dictionary *val = (Dictionary *)mem; + // allow empty array as empty dict for lua (directly or via lua-client RPC) + if (value->type == kObjectTypeArray && value->data.array.size == 0) { + *val = (Dictionary)ARRAY_DICT_INIT; + } else if (value->type == kObjectTypeDictionary) { + *val = value->data.dictionary; + } else { + api_err_exp(err, field->str, api_typename(field->type), api_typename(value->type)); + return false; + } + } else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow + || field->type == kObjectTypeTabpage) { + if (value->type == kObjectTypeInteger || value->type == field->type) { + *(handle_T *)mem = (handle_T)value->data.integer; + } else { + api_err_exp(err, field->str, api_typename(field->type), api_typename(value->type)); + return false; + } + } else if (field->type == kObjectTypeLuaRef) { + api_set_error(err, kErrorTypeValidation, "Invalid key: '%.*s' is only allowed from Lua", + (int)k.size, k.data); + return false; + } else { + abort(); + } } return true; @@ -934,7 +1002,18 @@ bool api_dict_to_keydict(void *rv, field_hash hashy, Dictionary dict, Error *err void api_free_keydict(void *dict, KeySetLink *table) { for (size_t i = 0; table[i].str; i++) { - api_free_object(*(Object *)((char *)dict + table[i].ptr_off)); + char *mem = ((char *)dict + table[i].ptr_off); + if (table[i].type == kObjectTypeNil) { + api_free_object(*(Object *)mem); + } else if (table[i].type == kObjectTypeString) { + api_free_string(*(String *)mem); + } else if (table[i].type == kObjectTypeArray) { + api_free_array(*(Array *)mem); + } else if (table[i].type == kObjectTypeDictionary) { + api_free_dictionary(*(Dictionary *)mem); + } else if (table[i].type == kObjectTypeLuaRef) { + api_free_luaref(*(LuaRef *)mem); + } } } diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index cb74c655cd..95e5cf67c8 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -63,8 +63,9 @@ #define NIL ((Object)OBJECT_INIT) #define NULL_STRING ((String)STRING_INIT) -// currently treat key=vim.NIL as if the key was missing -#define HAS_KEY(o) ((o).type != kObjectTypeNil) +#define HAS_KEY(d, typ, key) (((d)->is_set__##typ##_ & (1 << KEYSET_OPTIDX_##typ##__##key)) != 0) + +#define GET_BOOL_OR_TRUE(d, typ, key) (HAS_KEY(d, typ, key) ? (d)->key : true) #define PUT(dict, k, v) \ kv_push(dict, ((KeyValuePair) { .key = cstr_to_string(k), .value = v })) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index b4a6fa718b..22fe69e447 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -558,16 +558,15 @@ ArrayOf(String) nvim__get_runtime(Array pat, Boolean all, Dict(runtime) *opts, E FUNC_API_SINCE(8) FUNC_API_FAST { - bool is_lua = api_object_to_bool(opts->is_lua, "is_lua", false, err); - bool source = api_object_to_bool(opts->do_source, "do_source", false, err); - VALIDATE((!source || nlua_is_deferred_safe()), "%s", "'do_source' used in fast callback", {}); + VALIDATE((!opts->do_source || nlua_is_deferred_safe()), "%s", "'do_source' used in fast callback", + {}); if (ERROR_SET(err)) { return (Array)ARRAY_DICT_INIT; } - ArrayOf(String) res = runtime_get_named(is_lua, pat, all); + ArrayOf(String) res = runtime_get_named(opts->is_lua, pat, all); - if (source) { + if (opts->do_source) { for (size_t i = 0; i < res.size; i++) { String name = res.items[i].data.string; (void)do_source(name.data, false, DOSO_NONE, NULL); @@ -718,15 +717,13 @@ void nvim_echo(Array chunks, Boolean history, Dict(echo_opts) *opts, Error *err) goto error; } - bool verbose = api_object_to_bool(opts->verbose, "verbose", false, err); - - if (verbose) { + if (opts->verbose) { verbose_enter(); } msg_multiattr(hl_msg, history ? "echomsg" : "echo", history); - if (verbose) { + if (opts->verbose) { verbose_leave(); verbose_stop(); // flush now } @@ -1323,11 +1320,8 @@ Dictionary nvim_get_context(Dict(context) *opts, Error *err) FUNC_API_SINCE(6) { Array types = ARRAY_DICT_INIT; - if (HAS_KEY(opts->types)) { - VALIDATE_T("types", kObjectTypeArray, opts->types.type, { - return (Dictionary)ARRAY_DICT_INIT; - }); - types = opts->types.data.array; + if (HAS_KEY(opts, context, types)) { + types = opts->types; } int int_types = types.size > 0 ? 0 : kCtxAll; @@ -2091,12 +2085,8 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * int maxwidth; int fillchar = 0; - int use_bools = 0; int statuscol_lnum = 0; Window window = 0; - bool use_winbar = false; - bool use_tabline = false; - bool highlights = false; if (str.size < 2 || memcmp(str.data, "%!", 2) != 0) { const char *const errmsg = check_stl_option(str.data); @@ -2105,58 +2095,28 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * }); } - if (HAS_KEY(opts->winid)) { - VALIDATE_T("winid", kObjectTypeInteger, opts->winid.type, { - return result; - }); - - window = (Window)opts->winid.data.integer; + if (HAS_KEY(opts, eval_statusline, winid)) { + window = opts->winid; } - if (HAS_KEY(opts->fillchar)) { - VALIDATE_T("fillchar", kObjectTypeString, opts->fillchar.type, { - return result; - }); - VALIDATE_EXP((opts->fillchar.data.string.size != 0 - && ((size_t)utf_ptr2len(opts->fillchar.data.string.data) - == opts->fillchar.data.string.size)), + if (HAS_KEY(opts, eval_statusline, fillchar)) { + VALIDATE_EXP((*opts->fillchar.data != 0 + && ((size_t)utf_ptr2len(opts->fillchar.data) == opts->fillchar.size)), "fillchar", "single character", NULL, { return result; }); - fillchar = utf_ptr2char(opts->fillchar.data.string.data); + fillchar = utf_ptr2char(opts->fillchar.data); } - if (HAS_KEY(opts->highlights)) { - highlights = api_object_to_bool(opts->highlights, "highlights", false, err); - if (ERROR_SET(err)) { - return result; - } - } - if (HAS_KEY(opts->use_winbar)) { - use_winbar = api_object_to_bool(opts->use_winbar, "use_winbar", false, err); - if (ERROR_SET(err)) { - return result; - } - use_bools++; - } - if (HAS_KEY(opts->use_tabline)) { - use_tabline = api_object_to_bool(opts->use_tabline, "use_tabline", false, err); - if (ERROR_SET(err)) { - return result; - } - use_bools++; - } + int use_bools = (int)opts->use_winbar + (int)opts->use_tabline; - win_T *wp = use_tabline ? curwin : find_window_by_handle(window, err); + win_T *wp = opts->use_tabline ? curwin : find_window_by_handle(window, err); if (wp == NULL) { api_set_error(err, kErrorTypeException, "unknown winid %d", window); return result; } - if (HAS_KEY(opts->use_statuscol_lnum)) { - VALIDATE_T("use_statuscol_lnum", kObjectTypeInteger, opts->use_statuscol_lnum.type, { - return result; - }); - statuscol_lnum = (int)opts->use_statuscol_lnum.data.integer; + if (HAS_KEY(opts, eval_statusline, use_statuscol_lnum)) { + statuscol_lnum = (int)opts->use_statuscol_lnum; VALIDATE_RANGE(statuscol_lnum > 0 && statuscol_lnum <= wp->w_buffer->b_ml.ml_line_count, "use_statuscol_lnum", { return result; @@ -2172,11 +2132,11 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * statuscol_T statuscol = { 0 }; SignTextAttrs sattrs[SIGN_SHOW_MAX] = { 0 }; - if (use_tabline) { + if (opts->use_tabline) { fillchar = ' '; } else { if (fillchar == 0) { - if (use_winbar) { + if (opts->use_winbar) { fillchar = wp->w_p_fcs_chars.wbr; } else { int attr; @@ -2220,15 +2180,12 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * } } - if (HAS_KEY(opts->maxwidth)) { - VALIDATE_T("maxwidth", kObjectTypeInteger, opts->maxwidth.type, { - return result; - }); - - maxwidth = (int)opts->maxwidth.data.integer; + if (HAS_KEY(opts, eval_statusline, maxwidth)) { + maxwidth = (int)opts->maxwidth; } else { maxwidth = statuscol_lnum ? win_col_off(wp) - : (use_tabline || (!use_winbar && global_stl_height() > 0)) ? Columns : wp->w_width; + : (opts->use_tabline + || (!opts->use_winbar && global_stl_height() > 0)) ? Columns : wp->w_width; } char buf[MAXPATHL]; @@ -2246,7 +2203,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * 0, fillchar, maxwidth, - highlights ? &hltab : NULL, + opts->highlights ? &hltab : NULL, NULL, statuscol_lnum ? &statuscol : NULL); @@ -2255,7 +2212,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * // Restore original value of 'cursorbind' wp->w_p_crb = p_crb_save; - if (highlights) { + if (opts->highlights) { Array hl_values = ARRAY_DICT_INIT; const char *grpname; char user_group[15]; // strlen("User") + strlen("2147483647") + NUL @@ -2264,7 +2221,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * // add the default highlight at the beginning of the highlight list if (hltab->start == NULL || (hltab->start - buf) != 0) { Dictionary hl_info = ARRAY_DICT_INIT; - grpname = get_default_stl_hl(use_tabline ? NULL : wp, use_winbar, stc_hl_id); + grpname = get_default_stl_hl(opts->use_tabline ? NULL : wp, opts->use_winbar, stc_hl_id); PUT(hl_info, "start", INTEGER_OBJ(0)); PUT(hl_info, "group", CSTR_TO_OBJ(grpname)); @@ -2278,7 +2235,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * PUT(hl_info, "start", INTEGER_OBJ(sp->start - buf)); if (sp->userhl == 0) { - grpname = get_default_stl_hl(use_tabline ? NULL : wp, use_winbar, stc_hl_id); + grpname = get_default_stl_hl(opts->use_tabline ? NULL : wp, opts->use_winbar, stc_hl_id); } else if (sp->userhl < 0) { grpname = syn_id2name(-sp->userhl); } else { diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 8a598d86f0..4801562ad2 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -61,7 +61,7 @@ Dictionary nvim_exec2(uint64_t channel_id, String src, Dict(exec_opts) *opts, Er return result; } - if (HAS_KEY(opts->output) && api_object_to_bool(opts->output, "opts.output", false, err)) { + if (opts->output) { PUT(result, "output", STRING_OBJ(output)); } @@ -70,19 +70,17 @@ Dictionary nvim_exec2(uint64_t channel_id, String src, Dict(exec_opts) *opts, Er String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *err) { - Boolean output = api_object_to_bool(opts->output, "opts.output", false, err); - const int save_msg_silent = msg_silent; garray_T *const save_capture_ga = capture_ga; const int save_msg_col = msg_col; garray_T capture_local; - if (output) { + if (opts->output) { ga_init(&capture_local, 1, 80); capture_ga = &capture_local; } try_start(); - if (output) { + if (opts->output) { msg_silent++; msg_col = 0; // prevent leading spaces } @@ -90,7 +88,7 @@ String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error * const sctx_T save_current_sctx = api_set_sctx(channel_id); do_source_str(src.data, "nvim_exec2()"); - if (output) { + if (opts->output) { capture_ga = save_capture_ga; msg_silent = save_msg_silent; // Put msg_col back where it was, since nothing should have been written. @@ -104,7 +102,7 @@ String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error * goto theend; } - if (output && capture_local.ga_len > 1) { + if (opts->output && capture_local.ga_len > 1) { String s = (String){ .data = capture_local.ga_data, .size = (size_t)capture_local.ga_len, @@ -118,7 +116,7 @@ String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error * return s; // Caller will free the memory. } theend: - if (output) { + if (opts->output) { ga_clear(&capture_local); } return (String)STRING_INIT; diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 81a239d913..b666d1efa2 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -7,6 +7,7 @@ #include "klib/kvec.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/win_config.h" #include "nvim/ascii.h" @@ -231,7 +232,7 @@ void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err) win_config_float(win, fconfig); win->w_pos_changed = true; } - if (HAS_KEY(config->style)) { + if (HAS_KEY(config, float_config, style)) { if (fconfig.style == kWinStyleMinimal) { win_set_minimal_style(win); didset_window_options(win, true); @@ -380,12 +381,8 @@ static bool parse_float_bufpos(Array bufpos, lpos_T *out) return true; } -static void parse_border_title(Object title, Object title_pos, FloatConfig *fconfig, Error *err) +static void parse_border_title(Object title, FloatConfig *fconfig, Error *err) { - if (!parse_title_pos(title_pos, fconfig, err)) { - return; - } - if (title.type == kObjectTypeString) { if (title.data.string.size == 0) { fconfig->title = false; @@ -415,24 +412,14 @@ static void parse_border_title(Object title, Object title_pos, FloatConfig *fcon fconfig->title = true; } -static bool parse_title_pos(Object title_pos, FloatConfig *fconfig, Error *err) +static bool parse_title_pos(String title_pos, FloatConfig *fconfig, Error *err) { - if (!HAS_KEY(title_pos)) { + if (title_pos.size == 0) { fconfig->title_pos = kAlignLeft; return true; } - if (title_pos.type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, "title_pos must be string"); - return false; - } - - if (title_pos.data.string.size == 0) { - fconfig->title_pos = kAlignLeft; - return true; - } - - char *pos = title_pos.data.string.data; + char *pos = title_pos.data; if (strequal(pos, "left")) { fconfig->title_pos = kAlignLeft; @@ -559,110 +546,90 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err) static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig, bool reconf, bool new_win, Error *err) { +#define HAS_KEY_X(d, key) HAS_KEY(d, float_config, key) bool has_relative = false, relative_is_win = false; - if (config->relative.type == kObjectTypeString) { - // ignore empty string, to match nvim_win_get_config - if (config->relative.data.string.size > 0) { - if (!parse_float_relative(config->relative.data.string, &fconfig->relative)) { - api_set_error(err, kErrorTypeValidation, "Invalid value of 'relative' key"); - return false; - } + // ignore empty string, to match nvim_win_get_config + if (HAS_KEY_X(config, relative) && config->relative.size > 0) { + if (!parse_float_relative(config->relative, &fconfig->relative)) { + api_set_error(err, kErrorTypeValidation, "Invalid value of 'relative' key"); + return false; + } - if (!(HAS_KEY(config->row) && HAS_KEY(config->col)) && !HAS_KEY(config->bufpos)) { - api_set_error(err, kErrorTypeValidation, - "'relative' requires 'row'/'col' or 'bufpos'"); - return false; - } + if (!(HAS_KEY_X(config, row) && HAS_KEY_X(config, col)) && !HAS_KEY_X(config, bufpos)) { + api_set_error(err, kErrorTypeValidation, + "'relative' requires 'row'/'col' or 'bufpos'"); + return false; + } - has_relative = true; - fconfig->external = false; - if (fconfig->relative == kFloatRelativeWindow) { - relative_is_win = true; - fconfig->bufpos.lnum = -1; - } + has_relative = true; + fconfig->external = false; + if (fconfig->relative == kFloatRelativeWindow) { + relative_is_win = true; + fconfig->bufpos.lnum = -1; } - } else if (HAS_KEY(config->relative)) { - api_set_error(err, kErrorTypeValidation, "'relative' key must be String"); - return false; } - if (config->anchor.type == kObjectTypeString) { - if (!parse_float_anchor(config->anchor.data.string, &fconfig->anchor)) { + if (HAS_KEY_X(config, anchor)) { + if (!parse_float_anchor(config->anchor, &fconfig->anchor)) { api_set_error(err, kErrorTypeValidation, "Invalid value of 'anchor' key"); return false; } - } else if (HAS_KEY(config->anchor)) { - api_set_error(err, kErrorTypeValidation, "'anchor' key must be String"); - return false; } - if (HAS_KEY(config->row)) { + if (HAS_KEY_X(config, row)) { if (!has_relative) { api_set_error(err, kErrorTypeValidation, "non-float cannot have 'row'"); return false; - } else if (config->row.type == kObjectTypeInteger) { - fconfig->row = (double)config->row.data.integer; - } else if (config->row.type == kObjectTypeFloat) { - fconfig->row = config->row.data.floating; - } else { - api_set_error(err, kErrorTypeValidation, - "'row' key must be Integer or Float"); - return false; } + fconfig->row = config->row; } - if (HAS_KEY(config->col)) { + if (HAS_KEY_X(config, col)) { if (!has_relative) { api_set_error(err, kErrorTypeValidation, "non-float cannot have 'col'"); return false; - } else if (config->col.type == kObjectTypeInteger) { - fconfig->col = (double)config->col.data.integer; - } else if (config->col.type == kObjectTypeFloat) { - fconfig->col = config->col.data.floating; - } else { - api_set_error(err, kErrorTypeValidation, - "'col' key must be Integer or Float"); - return false; } + fconfig->col = config->col; } - if (HAS_KEY(config->bufpos)) { + if (HAS_KEY_X(config, bufpos)) { if (!has_relative) { api_set_error(err, kErrorTypeValidation, "non-float cannot have 'bufpos'"); return false; - } else if (config->bufpos.type == kObjectTypeArray) { - if (!parse_float_bufpos(config->bufpos.data.array, &fconfig->bufpos)) { + } else { + if (!parse_float_bufpos(config->bufpos, &fconfig->bufpos)) { api_set_error(err, kErrorTypeValidation, "Invalid value of 'bufpos' key"); return false; } - if (!HAS_KEY(config->row)) { + if (!HAS_KEY_X(config, row)) { fconfig->row = (fconfig->anchor & kFloatAnchorSouth) ? 0 : 1; } - if (!HAS_KEY(config->col)) { + if (!HAS_KEY_X(config, col)) { fconfig->col = 0; } - } else { - api_set_error(err, kErrorTypeValidation, "'bufpos' key must be Array"); - return false; } } - if (config->width.type == kObjectTypeInteger && config->width.data.integer > 0) { - fconfig->width = (int)config->width.data.integer; - } else if (HAS_KEY(config->width)) { - api_set_error(err, kErrorTypeValidation, "'width' key must be a positive Integer"); - return false; + if (HAS_KEY_X(config, width)) { + if (config->width > 0) { + fconfig->width = (int)config->width; + } else { + api_set_error(err, kErrorTypeValidation, "'width' key must be a positive Integer"); + return false; + } } else if (!reconf) { api_set_error(err, kErrorTypeValidation, "Must specify 'width'"); return false; } - if (config->height.type == kObjectTypeInteger && config->height.data.integer > 0) { - fconfig->height = (int)config->height.data.integer; - } else if (HAS_KEY(config->height)) { - api_set_error(err, kErrorTypeValidation, "'height' key must be a positive Integer"); - return false; + if (HAS_KEY_X(config, height)) { + if (config->height > 0) { + fconfig->height = (int)config->height; + } else { + api_set_error(err, kErrorTypeValidation, "'height' key must be a positive Integer"); + return false; + } } else if (!reconf) { api_set_error(err, kErrorTypeValidation, "Must specify 'height'"); return false; @@ -670,26 +637,20 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig, if (relative_is_win) { fconfig->window = curwin->handle; - if (config->win.type == kObjectTypeInteger || config->win.type == kObjectTypeWindow) { - if (config->win.data.integer > 0) { - fconfig->window = (Window)config->win.data.integer; + if (HAS_KEY_X(config, win)) { + if (config->win > 0) { + fconfig->window = config->win; } - } else if (HAS_KEY(config->win)) { - api_set_error(err, kErrorTypeValidation, "'win' key must be Integer or Window"); - return false; } } else { - if (HAS_KEY(config->win)) { + if (HAS_KEY_X(config, win)) { api_set_error(err, kErrorTypeValidation, "'win' key is only valid with relative='win'"); return false; } } - if (HAS_KEY(config->external)) { - fconfig->external = api_object_to_bool(config->external, "'external' key", false, err); - if (ERROR_SET(err)) { - return false; - } + if (HAS_KEY_X(config, external)) { + fconfig->external = config->external; if (has_relative && fconfig->external) { api_set_error(err, kErrorTypeValidation, "Only one of 'relative' and 'external' must be used"); @@ -708,30 +669,22 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig, return false; } - if (HAS_KEY(config->focusable)) { - fconfig->focusable = api_object_to_bool(config->focusable, "'focusable' key", false, err); - if (ERROR_SET(err)) { - return false; - } - } - - if (config->zindex.type == kObjectTypeInteger && config->zindex.data.integer > 0) { - fconfig->zindex = (int)config->zindex.data.integer; - } else if (HAS_KEY(config->zindex)) { - api_set_error(err, kErrorTypeValidation, "'zindex' key must be a positive Integer"); - return false; + if (HAS_KEY_X(config, focusable)) { + fconfig->focusable = config->focusable; } - if (HAS_KEY(config->title_pos)) { - if (!HAS_KEY(config->title)) { - api_set_error(err, kErrorTypeException, "title_pos requires title to be set"); + if (HAS_KEY_X(config, zindex)) { + if (config->zindex > 0) { + fconfig->zindex = (int)config->zindex; + } else { + api_set_error(err, kErrorTypeValidation, "'zindex' key must be a positive Integer"); return false; } } - if (HAS_KEY(config->title)) { + if (HAS_KEY_X(config, title)) { // title only work with border - if (!HAS_KEY(config->border) && !fconfig->border) { + if (!HAS_KEY_X(config, border) && !fconfig->border) { api_set_error(err, kErrorTypeException, "title requires border to be set"); return false; } @@ -739,42 +692,49 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig, if (fconfig->title) { clear_virttext(&fconfig->title_chunks); } - parse_border_title(config->title, config->title_pos, fconfig, err); + + parse_border_title(config->title, fconfig, err); if (ERROR_SET(err)) { return false; } + + // handles unset 'title_pos' same as empty string + if (!parse_title_pos(config->title_pos, fconfig, err)) { + return false; + } + } else { + if (HAS_KEY_X(config, title_pos)) { + api_set_error(err, kErrorTypeException, "title_pos requires title to be set"); + return false; + } } - if (HAS_KEY(config->border)) { + if (HAS_KEY_X(config, border)) { parse_border_style(config->border, fconfig, err); if (ERROR_SET(err)) { return false; } } - if (config->style.type == kObjectTypeString) { - if (config->style.data.string.data[0] == NUL) { + if (HAS_KEY_X(config, style)) { + if (config->style.data[0] == NUL) { fconfig->style = kWinStyleUnused; - } else if (striequal(config->style.data.string.data, "minimal")) { + } else if (striequal(config->style.data, "minimal")) { fconfig->style = kWinStyleMinimal; } else { api_set_error(err, kErrorTypeValidation, "Invalid value of 'style' key"); + return false; } - } else if (HAS_KEY(config->style)) { - api_set_error(err, kErrorTypeValidation, "'style' key must be String"); - return false; } - if (HAS_KEY(config->noautocmd)) { + if (HAS_KEY_X(config, noautocmd)) { if (!new_win) { api_set_error(err, kErrorTypeValidation, "Invalid key: 'noautocmd'"); return false; } - fconfig->noautocmd = api_object_to_bool(config->noautocmd, "'noautocmd' key", false, err); - if (ERROR_SET(err)) { - return false; - } + fconfig->noautocmd = config->noautocmd; } return true; +#undef HAS_KEY_X } diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index f32a7e671d..f74071a002 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -7,6 +7,7 @@ #include #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/api/window.h" @@ -513,18 +514,12 @@ Dictionary nvim_win_text_height(Window window, Dict(win_text_height) *opts, Aren bool oob = false; - if (HAS_KEY(opts->start_row)) { - VALIDATE_T("start_row", kObjectTypeInteger, opts->start_row.type, { - return rv; - }); - start_lnum = (linenr_T)normalize_index(buf, opts->start_row.data.integer, false, &oob); + if (HAS_KEY(opts, win_text_height, start_row)) { + start_lnum = (linenr_T)normalize_index(buf, opts->start_row, false, &oob); } - if (HAS_KEY(opts->end_row)) { - VALIDATE_T("end_row", kObjectTypeInteger, opts->end_row.type, { - return rv; - }); - end_lnum = (linenr_T)normalize_index(buf, opts->end_row.data.integer, false, &oob); + if (HAS_KEY(opts, win_text_height, end_row)) { + end_lnum = (linenr_T)normalize_index(buf, opts->end_row, false, &oob); } VALIDATE(!oob, "%s", "Line index out of bounds", { @@ -534,27 +529,23 @@ Dictionary nvim_win_text_height(Window window, Dict(win_text_height) *opts, Aren return rv; }); - if (HAS_KEY(opts->start_vcol)) { - VALIDATE(HAS_KEY(opts->start_row), "%s", "'start_vcol' specified without 'start_row'", { + if (HAS_KEY(opts, win_text_height, start_vcol)) { + VALIDATE(HAS_KEY(opts, win_text_height, start_row), + "%s", "'start_vcol' specified without 'start_row'", { return rv; }); - VALIDATE_T("start_vcol", kObjectTypeInteger, opts->start_vcol.type, { - return rv; - }); - start_vcol = opts->start_vcol.data.integer; + start_vcol = opts->start_vcol; VALIDATE_RANGE((start_vcol >= 0 && start_vcol <= MAXCOL), "start_vcol", { return rv; }); } - if (HAS_KEY(opts->end_vcol)) { - VALIDATE(HAS_KEY(opts->end_row), "%s", "'end_vcol' specified without 'end_row'", { - return rv; - }); - VALIDATE_T("end_vcol", kObjectTypeInteger, opts->end_vcol.type, { + if (HAS_KEY(opts, win_text_height, end_vcol)) { + VALIDATE(HAS_KEY(opts, win_text_height, end_row), + "%s", "'end_vcol' specified without 'end_row'", { return rv; }); - end_vcol = opts->end_vcol.data.integer; + end_vcol = opts->end_vcol; VALIDATE_RANGE((end_vcol >= 0 && end_vcol <= MAXCOL), "end_vcol", { return rv; }); @@ -568,7 +559,7 @@ Dictionary nvim_win_text_height(Window window, Dict(win_text_height) *opts, Aren int64_t fill = 0; int64_t all = win_text_height(win, start_lnum, start_vcol, end_lnum, end_vcol, &fill); - if (!HAS_KEY(opts->end_row)) { + if (!HAS_KEY(opts, win_text_height, end_row)) { const int64_t end_fill = win_get_fill(win, line_count + 1); fill += end_fill; all += end_fill; -- cgit From 713311be62db5c5453bcd0a7f1dbed8d1d1add15 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 12 Aug 2023 06:08:07 +0800 Subject: vim-patch:9.0.1687: mapset() not properly handling script ID (#24666) Problem: mapset() not properly handling script ID Solution: replace_termcodes() may accept a script ID closes: vim/vim#12699 closes: vim/vim#12697 https://github.com/vim/vim/commit/7e0bae024d4c1673cff31763227ad52b936fa56f --- src/nvim/api/vim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 22fe69e447..4179ae40b8 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -431,7 +431,7 @@ String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt, Bool } char *ptr = NULL; - replace_termcodes(str.data, str.size, &ptr, flags, NULL, CPO_TO_CPO_FLAGS); + replace_termcodes(str.data, str.size, &ptr, 0, flags, NULL, CPO_TO_CPO_FLAGS); return cstr_as_string(ptr); } -- cgit From 22d9338afceae5f8ef3845f152dea07a19d512d1 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Thu, 17 Aug 2023 00:53:10 +0100 Subject: fix(api): disallow win_set_buf from changing cmdwin's old curbuf (#24745) A command typed in the cmdwin and executed with `` is expected to be executed in the context of the old curwin/buf, so it shouldn't be changed. --- src/nvim/api/window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index f74071a002..001797add5 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -58,7 +58,7 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err) if (!win || !buf) { return; } - if (cmdwin_type != 0 && (win == curwin || buf == curbuf)) { + if (cmdwin_type != 0 && (win == curwin || win == cmdwin_old_curwin || buf == curbuf)) { api_set_error(err, kErrorTypeException, "%s", e_cmdwin); return; } -- cgit From cefd774fac76b91f5368833555818c80c992c3b1 Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 24 Aug 2023 15:14:23 +0200 Subject: refactor(memline): distinguish mutating uses of ml_get_buf() ml_get_buf() takes a third parameters to indicate whether the caller wants to mutate the memline data in place. However the vast majority of the call sites is using this function just to specify a buffer but without any mutation. This makes it harder to grep for the places which actually perform mutation. Solution: Remove the bool param from ml_get_buf(). it now works like ml_get() except for a non-current buffer. Add a new ml_get_buf_mut() function for the mutating use-case, which can be grepped along with the other ml_replace() etc functions which can modify the memline. --- src/nvim/api/buffer.c | 8 ++++---- src/nvim/api/extmark.c | 4 ++-- src/nvim/api/private/helpers.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index e6c91df521..4e3468f8d1 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -546,7 +546,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In char *str_at_end = NULL; // Another call to ml_get_buf() may free the line, so make a copy. - str_at_start = xstrdup(ml_get_buf(buf, (linenr_T)start_row, false)); + str_at_start = xstrdup(ml_get_buf(buf, (linenr_T)start_row)); size_t len_at_start = strlen(str_at_start); start_col = start_col < 0 ? (int64_t)len_at_start + start_col + 1 : start_col; VALIDATE_RANGE((start_col >= 0 && (size_t)start_col <= len_at_start), "start_col", { @@ -554,7 +554,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In }); // Another call to ml_get_buf() may free the line, so make a copy. - str_at_end = xstrdup(ml_get_buf(buf, (linenr_T)end_row, false)); + str_at_end = xstrdup(ml_get_buf(buf, (linenr_T)end_row)); size_t len_at_end = strlen(str_at_end); end_col = end_col < 0 ? (int64_t)len_at_end + end_col + 1 : end_col; VALIDATE_RANGE((end_col >= 0 && (size_t)end_col <= len_at_end), "end_col", { @@ -584,7 +584,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In for (int64_t i = 1; i < end_row - start_row; i++) { int64_t lnum = start_row + i; - const char *bufline = ml_get_buf(buf, (linenr_T)lnum, false); + const char *bufline = ml_get_buf(buf, (linenr_T)lnum); old_byte += (bcount_t)(strlen(bufline)) + 1; } old_byte += (bcount_t)end_col + 1; @@ -1415,7 +1415,7 @@ bool buf_collect_lines(buf_T *buf, size_t n, linenr_T start, int start_idx, bool return false; } - char *bufstr = ml_get_buf(buf, lnum, false); + char *bufstr = ml_get_buf(buf, lnum); push_linestr(lstate, l, bufstr, strlen(bufstr), start_idx + (int)i, replace_nl); } diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 8a60d81649..30e39cd7aa 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -783,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 = opts->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)); } if (col == -1) { @@ -801,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 = opts->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)); } else if (line2 == buf->b_ml.ml_line_count) { // We are trying to add an extmark past final newline len = 0; diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index bbc87422d0..8fcabb3605 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -517,7 +517,7 @@ String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col return rv; } - char *bufstr = ml_get_buf(buf, (linenr_T)lnum, false); + char *bufstr = ml_get_buf(buf, (linenr_T)lnum); size_t line_length = strlen(bufstr); start_col = start_col < 0 ? (int64_t)line_length + start_col + 1 : start_col; -- cgit From 008154954791001efcc46c28146e21403f3a698b Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 21 Aug 2023 14:52:17 +0200 Subject: refactor(change): do API changes to buffer without curbuf switch Most of the messy things when changing a non-current buffer is not about the buffer, it is about windows. In particular, it is about `curwin`. When editing a non-current buffer which is displayed in some other window in the current tabpage, one such window will be "borrowed" as the curwin. But this means if two or more non-current windows displayed the buffers, one of them will be treated differenty. this is not desirable. In particular, with nvim_buf_set_text, cursor _column_ position was only corrected for one single window. Two new tests are added: the test with just one non-current window passes, but the one with two didn't. Two corresponding such tests were also added for nvim_buf_set_lines. This already worked correctly on master, but make sure this is well-tested for future refactors. Also, nvim_create_buf no longer invokes autocmds just because you happened to use `scratch=true`. No option value was changed, therefore OptionSet must not be fired. --- src/nvim/api/buffer.c | 97 ++++++++++++++++++++++++++------------------------- src/nvim/api/vim.c | 17 +++++---- 2 files changed, 59 insertions(+), 55 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 4e3468f8d1..775b6e8ea7 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -386,27 +386,29 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ } try_start(); - aco_save_T aco; - aucmd_prepbuf(&aco, buf); if (!MODIFIABLE(buf)) { api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'"); goto end; } - if (u_save((linenr_T)(start - 1), (linenr_T)end) == FAIL) { + if (!buf_ensure_loaded(buf)) { + goto end; + } + + if (u_save_buf(buf, (linenr_T)(start - 1), (linenr_T)end) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to save undo information"); goto end; } - bcount_t deleted_bytes = get_region_bytecount(curbuf, (linenr_T)start, (linenr_T)end, 0, 0); + bcount_t deleted_bytes = get_region_bytecount(buf, (linenr_T)start, (linenr_T)end, 0, 0); // If the size of the range is reducing (ie, new_len < old_len) we // need to delete some old_len. We do this at the start, by // repeatedly deleting line "start". size_t to_delete = (new_len < old_len) ? old_len - new_len : 0; for (size_t i = 0; i < to_delete; i++) { - if (ml_delete((linenr_T)start, false) == FAIL) { + if (ml_delete_buf(buf, (linenr_T)start, false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to delete line"); goto end; } @@ -428,7 +430,7 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ goto end; }); - if (ml_replace((linenr_T)lnum, lines[i], false) == FAIL) { + if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to replace line"); goto end; } @@ -447,7 +449,7 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ goto end; }); - if (ml_append((linenr_T)lnum, lines[i], 0, false) == FAIL) { + if (ml_append_buf(buf, (linenr_T)lnum, lines[i], 0, false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to insert line"); goto end; } @@ -462,20 +464,18 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ // Adjust marks. Invalidate any which lie in the // changed range, and move any in the remainder of the buffer. - // Only adjust marks if we managed to switch to a window that holds - // the buffer, otherwise line numbers will be invalid. - mark_adjust((linenr_T)start, - (linenr_T)(end - 1), - MAXLNUM, - (linenr_T)extra, - kExtmarkNOOP); - - extmark_splice(curbuf, (int)start - 1, 0, (int)(end - start), 0, + mark_adjust_buf(buf, (linenr_T)start, (linenr_T)(end - 1), MAXLNUM, (linenr_T)extra, + true, true, kExtmarkNOOP); + + extmark_splice(buf, (int)start - 1, 0, (int)(end - start), 0, deleted_bytes, (int)new_len, 0, inserted_bytes, kExtmarkUndo); - changed_lines((linenr_T)start, 0, (linenr_T)end, (linenr_T)extra, true); - fix_cursor((linenr_T)start, (linenr_T)end, (linenr_T)extra); + changed_lines(buf, (linenr_T)start, 0, (linenr_T)end, (linenr_T)extra, true); + if (curwin->w_buffer == buf) { + // mark_adjust_buf handles non-current windows + fix_cursor(curwin, (linenr_T)start, (linenr_T)end, (linenr_T)extra); + } end: for (size_t i = 0; i < new_len; i++) { @@ -483,7 +483,6 @@ end: } xfree(lines); - aucmd_restbuf(&aco); try_end(err); } @@ -630,17 +629,19 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In } try_start(); - aco_save_T aco; - aucmd_prepbuf(&aco, buf); if (!MODIFIABLE(buf)) { api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'"); goto end; } + if (!buf_ensure_loaded(buf)) { + goto end; + } + // Small note about undo states: unlike set_lines, we want to save the // undo state of one past the end_row, since end_row is inclusive. - if (u_save((linenr_T)start_row - 1, (linenr_T)end_row + 1) == FAIL) { + if (u_save_buf(buf, (linenr_T)start_row - 1, (linenr_T)end_row + 1) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to save undo information"); goto end; } @@ -653,7 +654,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In // repeatedly deleting line "start". size_t to_delete = (new_len < old_len) ? old_len - new_len : 0; for (size_t i = 0; i < to_delete; i++) { - if (ml_delete((linenr_T)start_row, false) == FAIL) { + if (ml_delete_buf(buf, (linenr_T)start_row, false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to delete line"); goto end; } @@ -674,7 +675,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In goto end; }); - if (ml_replace((linenr_T)lnum, lines[i], false) == FAIL) { + if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to replace line"); goto end; } @@ -691,7 +692,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In goto end; }); - if (ml_append((linenr_T)lnum, lines[i], 0, false) == FAIL) { + if (ml_append_buf(buf, (linenr_T)lnum, lines[i], 0, false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to insert line"); goto end; } @@ -702,35 +703,37 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In extra++; } + colnr_T col_extent = (colnr_T)(end_col + - ((end_row == start_row) ? start_col : 0)); + // Adjust marks. Invalidate any which lie in the // changed range, and move any in the remainder of the buffer. - mark_adjust((linenr_T)start_row, - (linenr_T)end_row, - MAXLNUM, - (linenr_T)extra, - kExtmarkNOOP); + // Do not adjust any cursors. need to use column-aware logic (below) + mark_adjust_buf(buf, (linenr_T)start_row, (linenr_T)end_row, MAXLNUM, (linenr_T)extra, + true, false, kExtmarkNOOP); - colnr_T col_extent = (colnr_T)(end_col - - ((end_row == start_row) ? start_col : 0)); extmark_splice(buf, (int)start_row - 1, (colnr_T)start_col, (int)(end_row - start_row), col_extent, old_byte, (int)new_len - 1, (colnr_T)last_item.size, new_byte, kExtmarkUndo); - changed_lines((linenr_T)start_row, 0, (linenr_T)end_row + 1, (linenr_T)extra, true); + changed_lines(buf, (linenr_T)start_row, 0, (linenr_T)end_row + 1, (linenr_T)extra, true); - // adjust cursor like an extmark ( i e it was inside last_part_len) - if (curwin->w_cursor.lnum == end_row && curwin->w_cursor.col > end_col) { - curwin->w_cursor.col -= col_extent - (colnr_T)last_item.size; + FOR_ALL_TAB_WINDOWS(tp, win) { + if (win->w_buffer == buf) { + // adjust cursor like an extmark ( i e it was inside last_part_len) + if (win->w_cursor.lnum == end_row && win->w_cursor.col > end_col) { + win->w_cursor.col -= col_extent - (colnr_T)last_item.size; + } + fix_cursor(win, (linenr_T)start_row, (linenr_T)end_row, (linenr_T)extra); + } } - fix_cursor((linenr_T)start_row, (linenr_T)end_row, (linenr_T)extra); end: for (size_t i = 0; i < new_len; i++) { xfree(lines[i]); } xfree(lines); - aucmd_restbuf(&aco); try_end(err); early_end: @@ -1317,21 +1320,19 @@ Dictionary nvim__buf_stats(Buffer buffer, Error *err) // Check if deleting lines made the cursor position invalid. // Changed lines from `lo` to `hi`; added `extra` lines (negative if deleted). -static void fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra) +static void fix_cursor(win_T *win, linenr_T lo, linenr_T hi, linenr_T extra) { - if (curwin->w_cursor.lnum >= lo) { + if (win->w_cursor.lnum >= lo) { // Adjust cursor position if it's in/after the changed lines. - if (curwin->w_cursor.lnum >= hi) { - curwin->w_cursor.lnum += extra; - check_cursor_col(); + if (win->w_cursor.lnum >= hi) { + win->w_cursor.lnum += extra; } else if (extra < 0) { - check_cursor(); - } else { - check_cursor_col(); + check_cursor_lnum(win); } - changed_cline_bef_curs(); + check_cursor_col_win(win); + changed_cline_bef_curs(win); } - invalidate_botline(); + invalidate_botline(win); } /// Initialise a string array either: diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 4179ae40b8..b278a21d8e 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -912,14 +912,17 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err) goto fail; } + // Only strictly needed for scratch, but could just as well be consistent + // and do this now. buffer is created NOW, not when it latter first happen + // to reach a window or aucmd_prepbuf() .. + buf_copy_options(buf, BCO_ENTER | BCO_NOHELP); + if (scratch) { - aco_save_T aco; - aucmd_prepbuf(&aco, buf); - set_option_value("bufhidden", STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL); - set_option_value("buftype", STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL); - set_option_value("swapfile", BOOLEAN_OPTVAL(false), OPT_LOCAL); - set_option_value("modeline", BOOLEAN_OPTVAL(false), OPT_LOCAL); // 'nomodeline' - aucmd_restbuf(&aco); + set_string_option_direct_in_buf(buf, "bufhidden", -1, "hide", OPT_LOCAL, 0); + set_string_option_direct_in_buf(buf, "buftype", -1, "nofile", OPT_LOCAL, 0); + assert(buf->b_ml.ml_mfp->mf_fd < 0); // ml_open() should not have opened swapfile already + buf->b_p_swf = false; + buf->b_p_ml = false; } return buf->b_fnum; -- cgit From b46e93c5fd2c73b99b618d4954ab8d1c71ad3fb0 Mon Sep 17 00:00:00 2001 From: Alisue Date: Mon, 7 Aug 2023 00:19:51 +0900 Subject: docs(msgpack_rpc): add "msgpack-rpc" client type --- src/nvim/api/vim.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 4179ae40b8..16e6ab3fe0 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1497,7 +1497,10 @@ Array nvim_get_api_info(uint64_t channel_id, Arena *arena) /// - "commit" hash or similar identifier of commit /// @param type Must be one of the following values. Client libraries should /// default to "remote" unless overridden by the user. -/// - "remote" remote client connected to Nvim. +/// - "remote" remote client connected "Nvim flavored" MessagePack-RPC (responses +/// must be in reverse order of requests). |msgpack-rpc| +/// - "msgpack-rpc" remote client connected to Nvim via fully MessagePack-RPC +/// compliant protocol. /// - "ui" gui frontend /// - "embedder" application using Nvim as a component (for example, /// IDE/editor implementing a vim mode). -- cgit From 617fd5bdc6ab9a82bfc6136f549fc31dcf442ed7 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Fri, 25 Aug 2023 10:53:29 +0300 Subject: refactor(float): extract "title" and "title_pos" handling --- src/nvim/api/win_config.c | 127 ++++++++++++++++++++++++++++++---------------- src/nvim/api/win_config.h | 1 + 2 files changed, 85 insertions(+), 43 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index b666d1efa2..9473803652 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -240,6 +240,48 @@ void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err) } } +Dictionary config_put_bordertext(Dictionary config, FloatConfig *fconfig, + BorderTextType bordertext_type) +{ + VirtText chunks; + AlignTextPos align; + char *field_name; + char *field_pos_name; + if (bordertext_type == kBorderTextTitle) { + chunks = fconfig->title_chunks; + align = fconfig->title_pos; + field_name = "title"; + field_pos_name = "title_pos"; + } + + Array bordertext = ARRAY_DICT_INIT; + for (size_t i = 0; i < chunks.size; i++) { + Array tuple = ARRAY_DICT_INIT; + ADD(tuple, CSTR_TO_OBJ(chunks.items[i].text)); + if (chunks.items[i].hl_id > 0) { + ADD(tuple, CSTR_TO_OBJ(syn_id2name(chunks.items[i].hl_id))); + } + ADD(bordertext, ARRAY_OBJ(tuple)); + } + PUT(config, field_name, ARRAY_OBJ(bordertext)); + + char *pos; + switch (align) { + case kAlignLeft: + pos = "left"; + break; + case kAlignCenter: + pos = "center"; + break; + case kAlignRight: + pos = "right"; + break; + } + PUT(config, field_pos_name, CSTR_TO_OBJ(pos)); + + return config; +} + /// Gets window configuration. /// /// The returned value may be given to |nvim_open_win()|. @@ -301,26 +343,7 @@ Dictionary nvim_win_get_config(Window window, Error *err) } PUT(rv, "border", ARRAY_OBJ(border)); if (config->title) { - Array titles = ARRAY_DICT_INIT; - VirtText title_datas = config->title_chunks; - for (size_t i = 0; i < title_datas.size; i++) { - Array tuple = ARRAY_DICT_INIT; - ADD(tuple, CSTR_TO_OBJ(title_datas.items[i].text)); - if (title_datas.items[i].hl_id > 0) { - ADD(tuple, CSTR_TO_OBJ(syn_id2name(title_datas.items[i].hl_id))); - } - ADD(titles, ARRAY_OBJ(tuple)); - } - PUT(rv, "title", ARRAY_OBJ(titles)); - char *title_pos; - if (config->title_pos == kAlignLeft) { - title_pos = "left"; - } else if (config->title_pos == kAlignCenter) { - title_pos = "center"; - } else { - title_pos = "right"; - } - PUT(rv, "title_pos", CSTR_TO_OBJ(title_pos)); + rv = config_put_bordertext(rv, config, kBorderTextTitle); } } } @@ -381,54 +404,72 @@ static bool parse_float_bufpos(Array bufpos, lpos_T *out) return true; } -static void parse_border_title(Object title, FloatConfig *fconfig, Error *err) +static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, + FloatConfig *fconfig, Error *err) { - if (title.type == kObjectTypeString) { - if (title.data.string.size == 0) { - fconfig->title = false; + bool *is_present; + VirtText *chunks; + int *width; + if (bordertext_type == kBorderTextTitle) { + is_present = &fconfig->title; + chunks = &fconfig->title_chunks; + width = &fconfig->title_width; + } + + if (bordertext.type == kObjectTypeString) { + if (bordertext.data.string.size == 0) { + *is_present = false; return; } int hl_id = syn_check_group(S_LEN("FloatTitle")); - kv_push(fconfig->title_chunks, ((VirtTextChunk){ .text = xstrdup(title.data.string.data), - .hl_id = hl_id })); - fconfig->title_width = (int)mb_string2cells(title.data.string.data); - fconfig->title = true; + kv_push(*chunks, ((VirtTextChunk){ .text = xstrdup(bordertext.data.string.data), + .hl_id = hl_id })); + *width = (int)mb_string2cells(bordertext.data.string.data); + *is_present = true; return; } - if (title.type != kObjectTypeArray) { + if (bordertext.type != kObjectTypeArray) { api_set_error(err, kErrorTypeValidation, "title must be string or array"); return; } - if (title.data.array.size == 0) { + if (bordertext.data.array.size == 0) { api_set_error(err, kErrorTypeValidation, "title cannot be an empty array"); return; } - fconfig->title_width = 0; - fconfig->title_chunks = parse_virt_text(title.data.array, err, &fconfig->title_width); + *width = 0; + *chunks = parse_virt_text(bordertext.data.array, err, width); - fconfig->title = true; + *is_present = true; } -static bool parse_title_pos(String title_pos, FloatConfig *fconfig, Error *err) +static bool parse_bordertext_pos(String bordertext_pos, BorderTextType bordertext_type, + FloatConfig *fconfig, Error *err) { - if (title_pos.size == 0) { - fconfig->title_pos = kAlignLeft; + AlignTextPos *align; + if (bordertext_type == kBorderTextTitle) { + align = &fconfig->title_pos; + } + + if (bordertext_pos.size == 0) { + *align = kAlignLeft; return true; } - char *pos = title_pos.data; + char *pos = bordertext_pos.data; if (strequal(pos, "left")) { - fconfig->title_pos = kAlignLeft; + *align = kAlignLeft; } else if (strequal(pos, "center")) { - fconfig->title_pos = kAlignCenter; + *align = kAlignCenter; } else if (strequal(pos, "right")) { - fconfig->title_pos = kAlignRight; + *align = kAlignRight; } else { - api_set_error(err, kErrorTypeValidation, "invalid title_pos value"); + if (bordertext_type == kBorderTextTitle) { + api_set_error(err, kErrorTypeValidation, "invalid title_pos value"); + } return false; } return true; @@ -693,13 +734,13 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig, clear_virttext(&fconfig->title_chunks); } - parse_border_title(config->title, fconfig, err); + parse_bordertext(config->title, kBorderTextTitle, fconfig, err); if (ERROR_SET(err)) { return false; } // handles unset 'title_pos' same as empty string - if (!parse_title_pos(config->title_pos, fconfig, err)) { + if (!parse_bordertext_pos(config->title_pos, kBorderTextTitle, fconfig, err)) { return false; } } else { diff --git a/src/nvim/api/win_config.h b/src/nvim/api/win_config.h index a4614f02ce..426a74fb3e 100644 --- a/src/nvim/api/win_config.h +++ b/src/nvim/api/win_config.h @@ -3,6 +3,7 @@ #include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" +#include "nvim/buffer_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/win_config.h.generated.h" -- cgit From 35570e4a11bef061777d741929f74fa66ba3f45a Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Fri, 25 Aug 2023 10:53:35 +0300 Subject: feat(float): implement footer Problem: Now way to show text at the bottom part of floating window border (a.k.a. "footer"). Solution: Allows `footer` and `footer_pos` config fields similar to `title` and `title_pos`. --- src/nvim/api/keysets.h | 2 ++ src/nvim/api/win_config.c | 83 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 75 insertions(+), 10 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/keysets.h b/src/nvim/api/keysets.h index a47e278cad..1f5c7069a9 100644 --- a/src/nvim/api/keysets.h +++ b/src/nvim/api/keysets.h @@ -99,6 +99,8 @@ typedef struct { Object border; Object title; String title_pos; + Object footer; + String footer_pos; String style; Boolean noautocmd; } Dict(float_config); diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 9473803652..325d0cbfa0 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -145,11 +145,18 @@ /// By default, `FloatBorder` highlight is used, which links to `WinSeparator` /// when not defined. It could also be specified by character: /// [ ["+", "MyCorner"], ["x", "MyBorder"] ]. -/// - title: Title (optional) in window border, String or list. -/// List is [text, highlight] tuples. if is string the default -/// highlight group is `FloatTitle`. -/// - title_pos: Title position must set with title option. -/// value can be of `left` `center` `right` default is left. +/// - title: Title (optional) in window border, string or list. +/// List should consist of `[text, highlight]` tuples. +/// If string, the default highlight group is `FloatTitle`. +/// - title_pos: Title position. Must be set with `title` option. +/// Value can be one of "left", "center", or "right". +/// Default is `"left"`. +/// - footer: Footer (optional) in window border, string or list. +/// List should consist of `[text, highlight]` tuples. +/// If string, the default highlight group is `FloatTitle`. +/// - footer_pos: Footer position. Must be set with `footer` option. +/// Value can be one of "left", "center", or "right". +/// Default is `"left"`. /// - noautocmd: If true then no buffer-related autocommand events such as /// |BufEnter|, |BufLeave| or |BufWinEnter| may fire from /// calling this function. @@ -247,11 +254,19 @@ Dictionary config_put_bordertext(Dictionary config, FloatConfig *fconfig, AlignTextPos align; char *field_name; char *field_pos_name; - if (bordertext_type == kBorderTextTitle) { + switch (bordertext_type) { + case kBorderTextTitle: chunks = fconfig->title_chunks; align = fconfig->title_pos; field_name = "title"; field_pos_name = "title_pos"; + break; + case kBorderTextFooter: + chunks = fconfig->footer_chunks; + align = fconfig->footer_pos; + field_name = "footer"; + field_pos_name = "footer_pos"; + break; } Array bordertext = ARRAY_DICT_INIT; @@ -345,6 +360,9 @@ Dictionary nvim_win_get_config(Window window, Error *err) if (config->title) { rv = config_put_bordertext(rv, config, kBorderTextTitle); } + if (config->footer) { + rv = config_put_bordertext(rv, config, kBorderTextFooter); + } } } @@ -410,10 +428,17 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, bool *is_present; VirtText *chunks; int *width; - if (bordertext_type == kBorderTextTitle) { + switch (bordertext_type) { + case kBorderTextTitle: is_present = &fconfig->title; chunks = &fconfig->title_chunks; width = &fconfig->title_width; + break; + case kBorderTextFooter: + is_present = &fconfig->footer; + chunks = &fconfig->footer_chunks; + width = &fconfig->footer_width; + break; } if (bordertext.type == kObjectTypeString) { @@ -449,8 +474,13 @@ static bool parse_bordertext_pos(String bordertext_pos, BorderTextType bordertex FloatConfig *fconfig, Error *err) { AlignTextPos *align; - if (bordertext_type == kBorderTextTitle) { + switch (bordertext_type) { + case kBorderTextTitle: align = &fconfig->title_pos; + break; + case kBorderTextFooter: + align = &fconfig->footer_pos; + break; } if (bordertext_pos.size == 0) { @@ -467,8 +497,13 @@ static bool parse_bordertext_pos(String bordertext_pos, BorderTextType bordertex } else if (strequal(pos, "right")) { *align = kAlignRight; } else { - if (bordertext_type == kBorderTextTitle) { + switch (bordertext_type) { + case kBorderTextTitle: api_set_error(err, kErrorTypeValidation, "invalid title_pos value"); + break; + case kBorderTextFooter: + api_set_error(err, kErrorTypeValidation, "invalid footer_pos value"); + break; } return false; } @@ -559,8 +594,9 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err) String str = style.data.string; if (str.size == 0 || strequal(str.data, "none")) { fconfig->border = false; - // title does not work with border equal none + // border text does not work with border equal none fconfig->title = false; + fconfig->footer = false; return; } for (size_t i = 0; defaults[i].name; i++) { @@ -750,6 +786,33 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig, } } + if (HAS_KEY_X(config, footer)) { + // footer only work with border + if (!HAS_KEY_X(config, border) && !fconfig->border) { + api_set_error(err, kErrorTypeException, "footer requires border to be set"); + return false; + } + + if (fconfig->footer) { + clear_virttext(&fconfig->footer_chunks); + } + + parse_bordertext(config->footer, kBorderTextFooter, fconfig, err); + if (ERROR_SET(err)) { + return false; + } + + // handles unset 'footer_pos' same as empty string + if (!parse_bordertext_pos(config->footer_pos, kBorderTextFooter, fconfig, err)) { + return false; + } + } else { + if (HAS_KEY_X(config, footer_pos)) { + api_set_error(err, kErrorTypeException, "footer_pos requires footer to be set"); + return false; + } + } + if (HAS_KEY_X(config, border)) { parse_border_style(config->border, fconfig, err); if (ERROR_SET(err)) { -- cgit From 986bf7e78d09286e198b696630254eb097ad0875 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Fri, 25 Aug 2023 10:53:39 +0300 Subject: feat(highlight): add `FloatFooter` highlight group Problem: No clear separation of floating title and footer highlighting. Solution: Add new `FloatFooter` highlight group. --- src/nvim/api/win_config.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 325d0cbfa0..ac27554172 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -153,7 +153,7 @@ /// Default is `"left"`. /// - footer: Footer (optional) in window border, string or list. /// List should consist of `[text, highlight]` tuples. -/// If string, the default highlight group is `FloatTitle`. +/// If string, the default highlight group is `FloatFooter`. /// - footer_pos: Footer position. Must be set with `footer` option. /// Value can be one of "left", "center", or "right". /// Default is `"left"`. @@ -428,16 +428,19 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, bool *is_present; VirtText *chunks; int *width; + int default_hl_id; switch (bordertext_type) { case kBorderTextTitle: is_present = &fconfig->title; chunks = &fconfig->title_chunks; width = &fconfig->title_width; + default_hl_id = syn_check_group(S_LEN("FloatTitle")); break; case kBorderTextFooter: is_present = &fconfig->footer; chunks = &fconfig->footer_chunks; width = &fconfig->footer_width; + default_hl_id = syn_check_group(S_LEN("FloatFooter")); break; } @@ -446,9 +449,8 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, *is_present = false; return; } - int hl_id = syn_check_group(S_LEN("FloatTitle")); kv_push(*chunks, ((VirtTextChunk){ .text = xstrdup(bordertext.data.string.data), - .hl_id = hl_id })); + .hl_id = default_hl_id })); *width = (int)mb_string2cells(bordertext.data.string.data); *is_present = true; return; -- cgit From 9b9030ff2ca820d4c4f4b559f86b0f9a3496645b Mon Sep 17 00:00:00 2001 From: bfredl Date: Sun, 27 Aug 2023 11:20:59 +0200 Subject: fix(api): fix inconsistent behavior of topline touched in recent refactor The change in #24824 0081549 was not a regression, however it was an incomplete change. Unfortunately some common plugins come to depend on this exising self-inconsistent behavior. These plugins are going to need to update for 0.10 nvim_buf_set_lines used to NOT adjust the topline correctly if a buffer was displayed in just one window. However, if displayed in multiple windows, it was correctly adjusted for any window not deemed the current window for the buffer (which could be an arbitrary choice if the buffer was not already current, as noted in the last rafactor) This fixes so that all windows have their topline adjusted. The added tests show this behavior, which should be the reasonable one. --- src/nvim/api/buffer.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 775b6e8ea7..d36f0dd050 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -472,9 +472,11 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ kExtmarkUndo); changed_lines(buf, (linenr_T)start, 0, (linenr_T)end, (linenr_T)extra, true); - if (curwin->w_buffer == buf) { - // mark_adjust_buf handles non-current windows - fix_cursor(curwin, (linenr_T)start, (linenr_T)end, (linenr_T)extra); + + FOR_ALL_TAB_WINDOWS(tp, win) { + if (win->w_buffer == buf) { + fix_cursor(win, (linenr_T)start, (linenr_T)end, (linenr_T)extra); + } } end: @@ -710,7 +712,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In // changed range, and move any in the remainder of the buffer. // Do not adjust any cursors. need to use column-aware logic (below) mark_adjust_buf(buf, (linenr_T)start_row, (linenr_T)end_row, MAXLNUM, (linenr_T)extra, - true, false, kExtmarkNOOP); + true, true, kExtmarkNOOP); extmark_splice(buf, (int)start_row - 1, (colnr_T)start_col, (int)(end_row - start_row), col_extent, old_byte, -- cgit From 0a81ec14a4c006822509b06396871509140b7a79 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 28 Aug 2023 11:35:09 +0200 Subject: fix(api): better topline adjustments in nvim_buf_set_lines Some more reasonable defaults for topline: - if topline was replaced with another line, that now becomes topline - if line was inserted just before topline, display it. This is more similar to the previous API behavior. --- src/nvim/api/buffer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index d36f0dd050..b8cb09ceb3 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -464,7 +464,8 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ // Adjust marks. Invalidate any which lie in the // changed range, and move any in the remainder of the buffer. - mark_adjust_buf(buf, (linenr_T)start, (linenr_T)(end - 1), MAXLNUM, (linenr_T)extra, + linenr_T adjust = end > start ? MAXLNUM : 0; + mark_adjust_buf(buf, (linenr_T)start, (linenr_T)(end - 1), adjust, (linenr_T)extra, true, true, kExtmarkNOOP); extmark_splice(buf, (int)start - 1, 0, (int)(end - start), 0, @@ -711,7 +712,8 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In // Adjust marks. Invalidate any which lie in the // changed range, and move any in the remainder of the buffer. // Do not adjust any cursors. need to use column-aware logic (below) - mark_adjust_buf(buf, (linenr_T)start_row, (linenr_T)end_row, MAXLNUM, (linenr_T)extra, + linenr_T adjust = end_row >= start_row ? MAXLNUM : 0; + mark_adjust_buf(buf, (linenr_T)start_row, (linenr_T)end_row, adjust, (linenr_T)extra, true, true, kExtmarkNOOP); extmark_splice(buf, (int)start_row - 1, (colnr_T)start_col, -- cgit From 6a449a892bdc25f4984b1cd4dcbe4e7157142a46 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 13 Jul 2023 15:53:07 +0100 Subject: refactor(option): remove OPT_CLEAR --- src/nvim/api/options.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index e33cb72e8d..eb80683365 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -465,9 +465,6 @@ OptVal get_option_value_for(const char *const name, uint32_t *flagsp, int scope, /// @param[in] name Option name. /// @param[in] value Option value. /// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both). -/// If OPT_CLEAR is set, the value of the option -/// is cleared (the exact semantics of this depend -/// on the option). /// @param[in] opt_type Option type. See SREQ_* in option_defs.h. /// @param[in] from Target buffer/window. /// @param[out] err Error message, if any. -- cgit From 0c86828ac57429e3dea1bb4a9e686dc4f0dc9ddb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 2 Sep 2023 18:50:12 +0800 Subject: fix(ui): avoid ambiguity about chunk that clears part of line (#24982) Co-authored-by: bfredl --- src/nvim/api/ui.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 9fa5a89407..891c81d470 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -830,6 +830,7 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int size_t ncells = (size_t)(endcol - startcol); int last_hl = -1; uint32_t nelem = 0; + bool was_space = false; for (size_t i = 0; i < ncells; i++) { repeat++; if (i == ncells - 1 || attrs[i] != attrs[i + 1] @@ -868,9 +869,12 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int data->ncells_pending += MIN(repeat, 2); last_hl = attrs[i]; repeat = 0; + was_space = strequal(chunk[i], " "); } } - if (endcol < clearcol) { + // If the last chunk was all spaces, add a clearing chunk even if there are + // no more cells to clear, so there is no ambiguity about what to clear. + if (endcol < clearcol || was_space) { nelem++; data->ncells_pending += 1; mpack_array(buf, 3); -- cgit From 5970157e1d22fd5e05ae5d3bd949f807fb7a744c Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 17 May 2023 16:08:06 +0200 Subject: refactor(map): enhanced implementation, Clean Code™, etc etc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This involves two redesigns of the map.c implementations: 1. Change of macro style and code organization The old khash.h and map.c implementation used huge #define blocks with a lot of backslash line continuations. This instead uses the "implementation file" .c.h pattern. Such a file is meant to be included multiple times, with different macros set prior to inclusion as parameters. we already use this pattern e.g. for eval/typval_encode.c.h to implement different typval encoders reusing a similar structure. We can structure this code into two parts. one that only depends on key type and is enough to implement sets, and one which depends on both key and value to implement maps (as a wrapper around sets, with an added value[] array) 2. Separate the main hash buckets from the key / value arrays Change the hack buckets to only contain an index into separate key / value arrays This is a common pattern in modern, state of the art hashmap implementations. Even though this leads to one more allocated array, it is this often is a net reduction of memory consumption. Consider key+value consuming at least 12 bytes per pair. On average, we will have twice as many buckets per item. Thus old implementation: 2*12 = 24 bytes per item New implementation 1*12 + 2*4 = 20 bytes per item And the difference gets bigger with larger items. One might think we have pulled a fast one here, as wouldn't the average size of the new key/value arrays be 1.5 slots per items due to amortized grows? But remember, these arrays are fully dense, and thus the accessed memory, measured in _cache lines_, the unit which actually matters, will be the fully used memory but just rounded up to the nearest cache line boundary. This has some other interesting properties, such as an insert-only set/map will be fully ordered by insert only. Preserving this ordering in face of deletions is more tricky tho. As we currently don't use ordered maps, the "delete" operation maintains compactness of the item arrays in the simplest way by breaking the ordering. It would be possible to implement an order-preserving delete although at some cost, like allowing the items array to become non-dense until the next rehash. Finally, in face of these two major changes, all code used in khash.h has been integrated into map.c and friends. Given the heavy edits it makes no sense to "layer" the code into a vendored and a wrapper part. Rather, the layered cake follows the specialization depth: code shared for all maps, code specialized to a key type (and its equivalence relation), and finally code specialized to value+key type. --- src/nvim/api/extmark.c | 8 ++++---- src/nvim/api/extmark.h | 2 +- src/nvim/api/ui.c | 18 +++++++++--------- 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 30e39cd7aa..6ec1fc4ee0 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -54,14 +54,14 @@ void api_extmark_free_all_mem(void) Integer nvim_create_namespace(String name) FUNC_API_SINCE(5) { - handle_T id = map_get(String, handle_T)(&namespace_ids, name); + handle_T id = map_get(String, int)(&namespace_ids, name); if (id > 0) { return id; } id = next_namespace_id++; if (name.size > 0) { String name_alloc = copy_string(name, NULL); - map_put(String, handle_T)(&namespace_ids, name_alloc, id); + map_put(String, int)(&namespace_ids, name_alloc, id); } return (Integer)id; } @@ -76,7 +76,7 @@ Dictionary nvim_get_namespaces(void) String name; handle_T id; - map_foreach(handle_T, &namespace_ids, name, id, { + map_foreach(&namespace_ids, name, id, { PUT(retval, name.data, INTEGER_OBJ(id)); }) @@ -87,7 +87,7 @@ const char *describe_ns(NS ns_id) { String name; handle_T id; - map_foreach(handle_T, &namespace_ids, name, id, { + map_foreach(&namespace_ids, name, id, { if ((NS)id == ns_id && name.size) { return name.data; } diff --git a/src/nvim/api/extmark.h b/src/nvim/api/extmark.h index 3c979fa4f6..a7baad496f 100644 --- a/src/nvim/api/extmark.h +++ b/src/nvim/api/extmark.h @@ -8,7 +8,7 @@ #include "nvim/map.h" #include "nvim/types.h" -EXTERN Map(String, handle_T) namespace_ids INIT(= MAP_INIT); +EXTERN Map(String, int) namespace_ids INIT(= MAP_INIT); EXTERN handle_T next_namespace_id INIT(= 1); #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 891c81d470..70c97be984 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -136,7 +136,7 @@ void remote_ui_wait_for_attach(void) } LOOP_PROCESS_EVENTS_UNTIL(&main_loop, channel->events, -1, - pmap_has(uint64_t)(&connected_uis, CHAN_STDIO)); + map_has(uint64_t, &connected_uis, CHAN_STDIO)); } /// Activates UI events on the channel. @@ -158,7 +158,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona Error *err) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY { - if (pmap_has(uint64_t)(&connected_uis, channel_id)) { + if (map_has(uint64_t, &connected_uis, channel_id)) { api_set_error(err, kErrorTypeException, "UI already attached to channel: %" PRId64, channel_id); return; @@ -233,7 +233,7 @@ void ui_attach(uint64_t channel_id, Integer width, Integer height, Boolean enabl void nvim_ui_set_focus(uint64_t channel_id, Boolean gained, Error *error) FUNC_API_SINCE(11) FUNC_API_REMOTE_ONLY { - if (!pmap_has(uint64_t)(&connected_uis, channel_id)) { + if (!map_has(uint64_t, &connected_uis, channel_id)) { api_set_error(error, kErrorTypeException, "UI not attached to channel: %" PRId64, channel_id); return; @@ -255,7 +255,7 @@ void nvim_ui_set_focus(uint64_t channel_id, Boolean gained, Error *error) void nvim_ui_detach(uint64_t channel_id, Error *err) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY { - if (!pmap_has(uint64_t)(&connected_uis, channel_id)) { + if (!map_has(uint64_t, &connected_uis, channel_id)) { api_set_error(err, kErrorTypeException, "UI not attached to channel: %" PRId64, channel_id); return; @@ -271,7 +271,7 @@ void remote_ui_stop(UI *ui) void nvim_ui_try_resize(uint64_t channel_id, Integer width, Integer height, Error *err) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY { - if (!pmap_has(uint64_t)(&connected_uis, channel_id)) { + if (!map_has(uint64_t, &connected_uis, channel_id)) { api_set_error(err, kErrorTypeException, "UI not attached to channel: %" PRId64, channel_id); return; @@ -292,7 +292,7 @@ void nvim_ui_try_resize(uint64_t channel_id, Integer width, Integer height, Erro void nvim_ui_set_option(uint64_t channel_id, String name, Object value, Error *error) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY { - if (!pmap_has(uint64_t)(&connected_uis, channel_id)) { + if (!map_has(uint64_t, &connected_uis, channel_id)) { api_set_error(error, kErrorTypeException, "UI not attached to channel: %" PRId64, channel_id); return; @@ -426,7 +426,7 @@ void nvim_ui_try_resize_grid(uint64_t channel_id, Integer grid, Integer width, I Error *err) FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY { - if (!pmap_has(uint64_t)(&connected_uis, channel_id)) { + if (!map_has(uint64_t, &connected_uis, channel_id)) { api_set_error(err, kErrorTypeException, "UI not attached to channel: %" PRId64, channel_id); return; @@ -448,7 +448,7 @@ void nvim_ui_try_resize_grid(uint64_t channel_id, Integer grid, Integer width, I void nvim_ui_pum_set_height(uint64_t channel_id, Integer height, Error *err) FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY { - if (!pmap_has(uint64_t)(&connected_uis, channel_id)) { + if (!map_has(uint64_t, &connected_uis, channel_id)) { api_set_error(err, kErrorTypeException, "UI not attached to channel: %" PRId64, channel_id); return; @@ -489,7 +489,7 @@ void nvim_ui_pum_set_bounds(uint64_t channel_id, Float width, Float height, Floa Error *err) FUNC_API_SINCE(7) FUNC_API_REMOTE_ONLY { - if (!pmap_has(uint64_t)(&connected_uis, channel_id)) { + if (!map_has(uint64_t, &connected_uis, channel_id)) { api_set_error(err, kErrorTypeException, "UI not attached to channel: %" PRId64, channel_id); return; -- cgit From 8afb3a49c0762eb60368aee0314e6de261daa6ef Mon Sep 17 00:00:00 2001 From: glepnir Date: Thu, 7 Sep 2023 18:42:38 +0800 Subject: fix(highlight): add create param in nvim_get_hl --- src/nvim/api/keysets.h | 1 + src/nvim/api/vim.c | 1 + 2 files changed, 2 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/keysets.h b/src/nvim/api/keysets.h index 1f5c7069a9..0a07e8c16f 100644 --- a/src/nvim/api/keysets.h +++ b/src/nvim/api/keysets.h @@ -181,6 +181,7 @@ typedef struct { Integer id; String name; Boolean link; + Boolean create; } Dict(get_highlight); typedef struct { diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 411d63b921..da10ab5bd4 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -96,6 +96,7 @@ Integer nvim_get_hl_id_by_name(String name) /// - name: (string) Get a highlight definition by name. /// - id: (integer) Get a highlight definition by id. /// - link: (boolean, default true) Show linked group name instead of effective definition |:hi-link|. +/// - create: (boolean, default true) When highlight group doesn't exist create it. /// /// @param[out] err Error details, if any. /// @return Highlight groups as a map from group name to a highlight definition map as in |nvim_set_hl()|, -- cgit From d22172f36bbe147f3aa6b76a1c43ae445f481c2e Mon Sep 17 00:00:00 2001 From: Sergey Slipchenko Date: Mon, 11 Sep 2023 08:16:03 +0400 Subject: fix(api): more intuitive cursor updates in nvim_buf_set_text Fixes #22526 --- src/nvim/api/buffer.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 4 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index b8cb09ceb3..baac694848 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -504,7 +504,10 @@ end: /// /// Prefer |nvim_buf_set_lines()| if you are only adding or deleting entire lines. /// +/// Prefer |nvim_put()| if you want to insert text at the cursor position. +/// /// @see |nvim_buf_set_lines()| +/// @see |nvim_put()| /// /// @param channel_id /// @param buffer Buffer handle, or 0 for current buffer @@ -725,11 +728,12 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In FOR_ALL_TAB_WINDOWS(tp, win) { if (win->w_buffer == buf) { - // adjust cursor like an extmark ( i e it was inside last_part_len) - if (win->w_cursor.lnum == end_row && win->w_cursor.col > end_col) { - win->w_cursor.col -= col_extent - (colnr_T)last_item.size; + if (win->w_cursor.lnum >= start_row && win->w_cursor.lnum <= end_row) { + fix_cursor_cols(win, (linenr_T)start_row, (colnr_T)start_col, (linenr_T)end_row, + (colnr_T)end_col, (linenr_T)new_len, (colnr_T)last_item.size); + } else { + fix_cursor(win, (linenr_T)start_row, (linenr_T)end_row, (linenr_T)extra); } - fix_cursor(win, (linenr_T)start_row, (linenr_T)end_row, (linenr_T)extra); } } @@ -1339,6 +1343,79 @@ static void fix_cursor(win_T *win, linenr_T lo, linenr_T hi, linenr_T extra) invalidate_botline(win); } +/// Fix cursor position after replacing text +/// between (start_row, start_col) and (end_row, end_col). +/// +/// win->w_cursor.lnum is assumed to be >= start_row and <= end_row. +static void fix_cursor_cols(win_T *win, linenr_T start_row, colnr_T start_col, linenr_T end_row, + colnr_T end_col, linenr_T new_rows, colnr_T new_cols_at_end_row) +{ + colnr_T mode_col_adj = win == curwin && (State & MODE_INSERT) ? 0 : 1; + + colnr_T end_row_change_start = new_rows == 1 ? start_col : 0; + colnr_T end_row_change_end = end_row_change_start + new_cols_at_end_row; + + // check if cursor is after replaced range or not + if (win->w_cursor.lnum == end_row && win->w_cursor.col + mode_col_adj > end_col) { + // if cursor is after replaced range, it's shifted + // to keep it's position the same, relative to end_col + + linenr_T old_rows = end_row - start_row + 1; + win->w_cursor.lnum += new_rows - old_rows; + win->w_cursor.col += end_row_change_end - end_col; + } else { + // if cursor is inside replaced range + // and the new range got smaller, + // it's shifted to keep it inside the new range + // + // if cursor is before range or range did not + // got smaller, position is not changed + + colnr_T old_coladd = win->w_cursor.coladd; + + // it's easier to work with a single value here. + // col and coladd are fixed by a later call + // to check_cursor_col_win when necessary + win->w_cursor.col += win->w_cursor.coladd; + win->w_cursor.coladd = 0; + + linenr_T new_end_row = start_row + new_rows - 1; + + // make sure cursor row is in the new row range + if (win->w_cursor.lnum > new_end_row) { + win->w_cursor.lnum = new_end_row; + + // don't simply move cursor up, but to the end + // of new_end_row, if it's not at or after + // it already (in case virtualedit is active) + // column might be additionally adjusted below + // to keep it inside col range if needed + colnr_T len = (colnr_T)strlen(ml_get_buf(win->w_buffer, new_end_row)); + if (win->w_cursor.col < len) { + win->w_cursor.col = len; + } + } + + // if cursor is at the last row and + // it wasn't after eol before, move it exactly + // to end_row_change_end + if (win->w_cursor.lnum == new_end_row + && win->w_cursor.col > end_row_change_end && old_coladd == 0) { + win->w_cursor.col = end_row_change_end; + + // make sure cursor is inside range, not after it, + // except when doing so would move it before new range + if (win->w_cursor.col - mode_col_adj >= end_row_change_start) { + win->w_cursor.col -= mode_col_adj; + } + } + } + + check_cursor_col_win(win); + changed_cline_bef_curs(win); + invalidate_botline(win); +} + /// Initialise a string array either: /// - on the Lua stack (as a table) (if lstate is not NULL) /// - as an API array object (if lstate is NULL). -- cgit From 65738202f8be3ca63b75197d48f2c7a9324c035b Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Tue, 12 Sep 2023 04:29:39 +0900 Subject: fix(decorations): better approximation of botline #24794 Problem: * The guessed botline might be smaller than the actual botline e.g. when there are folds and the user is typing in insert mode. This may result in incorrect treesitter highlights for injections. * botline can be larger than the last line number of the buffer, which results in errors when placing extmarks. Solution: * Take a more conservative approximation. I am not sure if it is sufficient to guarantee correctness, but it seems to be good enough for the case mentioned above. * Clamp it to the last line number. Co-authored-by: Lewis Russell --- src/nvim/api/extmark.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 6ec1fc4ee0..268fdded9a 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -1035,7 +1035,8 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, /// window callbacks) /// ["buf", bufnr, tick] /// - on_win: called when starting to redraw a -/// specific window. +/// specific window. botline_guess is an approximation +/// that does not exceed the last line number. /// ["win", winid, bufnr, topline, botline_guess] /// - on_line: called for each buffer line being redrawn. /// (The interaction with fold lines is subject to change) -- cgit From b04286a187d57c50f01cd36cd4668b7a69026579 Mon Sep 17 00:00:00 2001 From: bfredl Date: Sun, 22 Nov 2020 10:10:37 +0100 Subject: feat(extmark): support proper multiline ranges The removes the previous restriction that nvim_buf_set_extmark() could not be used to highlight arbitrary multi-line regions The problem can be summarized as follows: let's assume an extmark with a hl_group is placed covering the region (5,0) to (50,0) Now, consider what happens if nvim needs to redraw a window covering the lines 20-30. It needs to be able to ask the marktree what extmarks cover this region, even if they don't begin or end here. Therefore the marktree needs to be augmented with the information covers a point, not just what marks begin or end there. To do this, we augment each node with a field "intersect" which is a set the ids of the marks which overlap this node, but only if it is not part of the set of any parent. This ensures the number of nodes that need to be explicitly marked grows only logarithmically with the total number of explicitly nodes (and thus the number of of overlapping marks). Thus we can quickly iterate all marks which overlaps any query position by looking up what leaf node contains that position. Then we only need to consider all "start" marks within that leaf node, and the "intersect" set of that node and all its parents. Now, and the major source of complexity is that the tree restructuring operations (to ensure that each node has T-1 <= size <= 2*T-1) also need to update these sets. If a full inner node is split in two, one of the new parents might start to completely overlap some ranges and its ids will need to be moved from its children's sets to its own set. Similarly, if two undersized nodes gets joined into one, it might no longer completely overlap some ranges, and now the children which do needs to have the have the ids in its set instead. And then there are the pivots! Yes the pivot operations when a child gets moved from one parent to another. --- src/nvim/api/extmark.c | 98 +++++++++++++++++++++++--------------------------- src/nvim/api/keysets.h | 9 +++++ 2 files changed, 54 insertions(+), 53 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 268fdded9a..b76a275c0d 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -308,6 +308,10 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, /// If `end` is less than `start`, traversal works backwards. (Useful /// with `limit`, to get the first marks prior to a given position.) /// +/// Note: when using extmark ranges (marks with a end_row/end_col position) +/// the `overlap` option might be useful. Otherwise only the start position +/// of an extmark will be considered. +/// /// Example: ///
lua
 ///   local api = vim.api
@@ -334,11 +338,13 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
 ///          - limit:  Maximum number of marks to return
 ///          - details: Whether to include the details dict
 ///          - hl_name: Whether to include highlight group name instead of id, true if omitted
+///          - overlap: Also include marks which overlap the range, even if
+///                     their start position is less than `start`
 ///          - type: Filter marks by type: "highlight", "sign", "virt_text" and "virt_lines"
 /// @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,
+                            Dict(get_extmarks) *opts, Error *err)
   FUNC_API_SINCE(7)
 {
   Array rv = ARRAY_DICT_INIT;
@@ -348,63 +354,32 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
     return rv;
   }
 
-  bool all_ns;
-  if (ns_id == -1) {
-    all_ns = true;
-  } else {
-    VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, {
-      return rv;
-    });
-    all_ns = false;
-  }
+  VALIDATE_INT(ns_id == -1 || ns_initialized((uint32_t)ns_id), "ns_id", ns_id, {
+    return rv;
+  });
 
-  Integer limit = -1;
-  bool details = false;
-  bool hl_name = true;
-  ExtmarkType type = kExtmarkNone;
+  bool details = opts->details;
+  bool hl_name = GET_BOOL_OR_TRUE(opts, get_extmarks, hl_name);
 
-  for (size_t i = 0; i < opts.size; i++) {
-    String k = opts.items[i].key;
-    Object *v = &opts.items[i].value;
-    if (strequal("limit", k.data)) {
-      VALIDATE_T("limit", kObjectTypeInteger, v->type, {
-        return rv;
-      });
-      limit = v->data.integer;
-    } else if (strequal("details", k.data)) {
-      details = api_object_to_bool(*v, "details", false, err);
-      if (ERROR_SET(err)) {
-        return rv;
-      }
-    } else if (strequal("hl_name", k.data)) {
-      hl_name = api_object_to_bool(*v, "hl_name", false, err);
-      if (ERROR_SET(err)) {
-        return rv;
-      }
-    } else if (strequal("type", k.data)) {
-      VALIDATE_EXP(v->type == kObjectTypeString, "type", "String", api_typename(v->type), {
-        return rv;
-      });
-      if (strequal(v->data.string.data, "sign")) {
-        type = kExtmarkSign;
-      } else if (strequal(v->data.string.data, "virt_text")) {
-        type = kExtmarkVirtText;
-      } else if (strequal(v->data.string.data, "virt_lines")) {
-        type = kExtmarkVirtLines;
-      } else if (strequal(v->data.string.data, "highlight")) {
-        type = kExtmarkHighlight;
-      } else {
-        VALIDATE_EXP(false, "type", "sign, virt_text, virt_lines or highlight", v->data.string.data, {
-          return rv;
-        });
-      }
+  ExtmarkType type = kExtmarkNone;
+  if (HAS_KEY(opts, get_extmarks, type)) {
+    if (strequal(opts->type.data, "sign")) {
+      type = kExtmarkSign;
+    } else if (strequal(opts->type.data, "virt_text")) {
+      type = kExtmarkVirtText;
+    } else if (strequal(opts->type.data, "virt_lines")) {
+      type = kExtmarkVirtLines;
+    } else if (strequal(opts->type.data, "highlight")) {
+      type = kExtmarkHighlight;
     } else {
-      VALIDATE_S(false, "'opts' key", k.data, {
+      VALIDATE_EXP(false, "type", "sign, virt_text, virt_lines or highlight", opts->type.data, {
         return rv;
       });
     }
   }
 
+  Integer limit = HAS_KEY(opts, get_extmarks, limit) ? opts->limit : -1;
+
   if (limit == 0) {
     return rv;
   } else if (limit < 0) {
@@ -429,11 +404,12 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
     reverse = true;
   }
 
+  // note: ns_id=-1 allowed, represented as UINT32_MAX
   ExtmarkInfoArray marks = extmark_get(buf, (uint32_t)ns_id, l_row, l_col, u_row,
-                                       u_col, (int64_t)limit, reverse, all_ns, type);
+                                       u_col, (int64_t)limit, reverse, type, opts->overlap);
 
   for (size_t i = 0; i < kv_size(marks); i++) {
-    ADD(rv, ARRAY_OBJ(extmark_to_array(&kv_A(marks, i), true, (bool)details, hl_name)));
+    ADD(rv, ARRAY_OBJ(extmark_to_array(&kv_A(marks, i), true, details, hl_name)));
   }
 
   kv_destroy(marks);
@@ -451,6 +427,11 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
 /// 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.
 ///
+/// If present, the position defined by `end_col` and `end_row` should be after
+/// the start position in order for the extmark to cover a range.
+/// An earlier end position is not an error, but then it behaves like an empty
+/// range (no highlighting).
+///
 /// @param buffer  Buffer handle, or 0 for current buffer
 /// @param ns_id  Namespace id from |nvim_create_namespace()|
 /// @param line  Line where to place the mark, 0-based. |api-indexing|
@@ -1230,3 +1211,14 @@ free_exit:
   clear_virttext(&virt_text);
   return virt_text;
 }
+
+String nvim__buf_debug_extmarks(Buffer buffer, Boolean keys, Boolean dot, Error *err)
+  FUNC_API_SINCE(7)
+{
+  buf_T *buf = find_buffer_by_handle(buffer, err);
+  if (!buf) {
+    return NULL_STRING;
+  }
+
+  return mt_inspect(buf->b_marktree, keys, dot);
+}
diff --git a/src/nvim/api/keysets.h b/src/nvim/api/keysets.h
index 0a07e8c16f..4e5e7af619 100644
--- a/src/nvim/api/keysets.h
+++ b/src/nvim/api/keysets.h
@@ -50,6 +50,15 @@ typedef struct {
   Boolean ui_watched;
 } Dict(set_extmark);
 
+typedef struct {
+  OptionalKeys is_set__get_extmarks_;
+  Integer limit;
+  Boolean details;
+  Boolean hl_name;
+  Boolean overlap;
+  String type;
+} Dict(get_extmarks);
+
 typedef struct {
   OptionalKeys is_set__keymap_;
   Boolean noremap;
-- 
cgit 


From 2e92065686f62851318150a315591c30b8306a4b Mon Sep 17 00:00:00 2001
From: Gregory Anders <8965202+gpanders@users.noreply.github.com>
Date: Thu, 14 Sep 2023 08:23:01 -0500
Subject: docs: replace 
 with ``` (#25136)

---
 src/nvim/api/autocmd.c    | 73 +++++++++++++++++++++++++----------------------
 src/nvim/api/buffer.c     | 14 +++++----
 src/nvim/api/command.c    | 11 +++----
 src/nvim/api/extmark.c    | 38 ++++++++++++------------
 src/nvim/api/vim.c        | 32 ++++++++++++---------
 src/nvim/api/win_config.c | 19 ++++++------
 6 files changed, 103 insertions(+), 84 deletions(-)

(limited to 'src/nvim/api')

diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c
index aa0c2695ad..2e4d2a622d 100644
--- a/src/nvim/api/autocmd.c
+++ b/src/nvim/api/autocmd.c
@@ -49,19 +49,20 @@ static int64_t next_autocmd_id = 1;
 /// Get all autocommands that match the corresponding {opts}.
 ///
 /// These examples will get autocommands matching ALL the given criteria:
-/// 
lua
-///   -- Matches all criteria
-///   autocommands = vim.api.nvim_get_autocmds({
-///     group = "MyGroup",
-///     event = {"BufEnter", "BufWinEnter"},
-///     pattern = {"*.c", "*.h"}
-///   })
 ///
-///   -- All commands from one group
-///   autocommands = vim.api.nvim_get_autocmds({
-///     group = "MyGroup",
-///   })
-/// 
+/// ```lua +/// -- Matches all criteria +/// autocommands = vim.api.nvim_get_autocmds({ +/// group = "MyGroup", +/// event = {"BufEnter", "BufWinEnter"}, +/// pattern = {"*.c", "*.h"} +/// }) +/// +/// -- All commands from one group +/// autocommands = vim.api.nvim_get_autocmds({ +/// group = "MyGroup", +/// }) +/// ``` /// /// NOTE: When multiple patterns or events are provided, it will find all the autocommands that /// match any combination of them. @@ -344,28 +345,31 @@ cleanup: /// function _name_ string) or `command` (Ex command string). /// /// Example using Lua callback: -///
lua
-///     vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {
-///       pattern = {"*.c", "*.h"},
-///       callback = function(ev)
-///         print(string.format('event fired: \%s', vim.inspect(ev)))
-///       end
-///     })
-/// 
+/// +/// ```lua +/// vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, { +/// pattern = {"*.c", "*.h"}, +/// callback = function(ev) +/// print(string.format('event fired: %s', vim.inspect(ev))) +/// end +/// }) +/// ``` /// /// Example using an Ex command as the handler: -///
lua
-///     vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {
-///       pattern = {"*.c", "*.h"},
-///       command = "echo 'Entering a C or C++ file'",
-///     })
-/// 
+/// +/// ```lua +/// vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, { +/// pattern = {"*.c", "*.h"}, +/// command = "echo 'Entering a C or C++ file'", +/// }) +/// ``` /// /// Note: `pattern` is NOT automatically expanded (unlike with |:autocmd|), thus names like "$HOME" /// and "~" must be expanded explicitly: -///
lua
-///   pattern = vim.fn.expand("~") .. "/some/path/*.py"
-/// 
+/// +/// ```lua +/// pattern = vim.fn.expand("~") .. "/some/path/*.py" +/// ``` /// /// @param event (string|array) Event(s) that will trigger the handler (`callback` or `command`). /// @param opts Options dict: @@ -619,11 +623,12 @@ cleanup: /// Create or get an autocommand group |autocmd-groups|. /// /// To get an existing group id, do: -///
lua
-///     local id = vim.api.nvim_create_augroup("MyGroup", {
-///         clear = false
-///     })
-/// 
+/// +/// ```lua +/// local id = vim.api.nvim_create_augroup("MyGroup", { +/// clear = false +/// }) +/// ``` /// /// @param name String: The name of the group /// @param opts Dictionary Parameters diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index baac694848..e8f9f809f2 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -85,11 +85,15 @@ Integer nvim_buf_line_count(Buffer buffer, Error *err) /// /// Example (Lua): capture buffer updates in a global `events` variable /// (use "vim.print(events)" to see its contents): -///
lua
-///   events = {}
-///   vim.api.nvim_buf_attach(0, false, {
-///     on_lines=function(...) table.insert(events, {...}) end})
-/// 
+/// +/// ```lua +/// events = {} +/// vim.api.nvim_buf_attach(0, false, { +/// on_lines = function(...) +/// table.insert(events, {...}) +/// end, +/// }) +/// ``` /// /// @see |nvim_buf_detach()| /// @see |api-buffer-updates-lua| diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 2b09cfc4b2..808d4e0b8d 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -860,11 +860,12 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin /// For Lua usage see |lua-guide-commands-create|. /// /// Example: -///
vim
-///    :call nvim_create_user_command('SayHello', 'echo "Hello world!"', {'bang': v:true})
-///    :SayHello
-///    Hello world!
-/// 
+/// +/// ```vim +/// :call nvim_create_user_command('SayHello', 'echo "Hello world!"', {'bang': v:true}) +/// :SayHello +/// Hello world! +/// ``` /// /// @param name Name of the new user command. Must begin with an uppercase letter. /// @param command Replacement command to execute when this user command is executed. When called diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index b76a275c0d..05f62f6c7c 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -300,10 +300,11 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, /// Region can be given as (row,col) tuples, or valid extmark ids (whose /// positions define the bounds). 0 and -1 are understood as (0,0) and (-1,-1) /// respectively, thus the following are equivalent: -///
lua
-///   vim.api.nvim_buf_get_extmarks(0, my_ns, 0, -1, {})
-///   vim.api.nvim_buf_get_extmarks(0, my_ns, {0,0}, {-1,-1}, {})
-/// 
+/// +/// ```lua +/// vim.api.nvim_buf_get_extmarks(0, my_ns, 0, -1, {}) +/// vim.api.nvim_buf_get_extmarks(0, my_ns, {0,0}, {-1,-1}, {}) +/// ``` /// /// If `end` is less than `start`, traversal works backwards. (Useful /// with `limit`, to get the first marks prior to a given position.) @@ -313,20 +314,21 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, /// of an extmark will be considered. /// /// Example: -///
lua
-///   local api = vim.api
-///   local pos = api.nvim_win_get_cursor(0)
-///   local ns  = api.nvim_create_namespace('my-plugin')
-///   -- Create new extmark at line 1, column 1.
-///   local m1  = api.nvim_buf_set_extmark(0, ns, 0, 0, {})
-///   -- Create new extmark at line 3, column 1.
-///   local m2  = api.nvim_buf_set_extmark(0, ns, 2, 0, {})
-///   -- Get extmarks only from line 3.
-///   local ms  = api.nvim_buf_get_extmarks(0, ns, {2,0}, {2,0}, {})
-///   -- Get all marks in this buffer + namespace.
-///   local all = api.nvim_buf_get_extmarks(0, ns, 0, -1, {})
-///   vim.print(ms)
-/// 
+/// +/// ```lua +/// local api = vim.api +/// local pos = api.nvim_win_get_cursor(0) +/// local ns = api.nvim_create_namespace('my-plugin') +/// -- Create new extmark at line 1, column 1. +/// local m1 = api.nvim_buf_set_extmark(0, ns, 0, 0, {}) +/// -- Create new extmark at line 3, column 1. +/// local m2 = api.nvim_buf_set_extmark(0, ns, 2, 0, {}) +/// -- Get extmarks only from line 3. +/// local ms = api.nvim_buf_get_extmarks(0, ns, {2,0}, {2,0}, {}) +/// -- Get all marks in this buffer + namespace. +/// local all = api.nvim_buf_get_extmarks(0, ns, 0, -1, {}) +/// vim.print(ms) +/// ``` /// /// @param buffer Buffer handle, or 0 for current buffer /// @param ns_id Namespace id from |nvim_create_namespace()| or -1 for all namespaces diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index da10ab5bd4..916409b973 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -212,10 +212,11 @@ void nvim_set_hl_ns_fast(Integer ns_id, Error *err) /// nvim_feedkeys(). /// /// Example: -///
vim
-///     :let key = nvim_replace_termcodes("", v:true, v:false, v:true)
-///     :call nvim_feedkeys(key, 'n', v:false)
-/// 
+/// +/// ```vim +/// :let key = nvim_replace_termcodes("", v:true, v:false, v:true) +/// :call nvim_feedkeys(key, 'n', v:false) +/// ``` /// /// @param keys to be typed /// @param mode behavior flags, see |feedkeys()| @@ -1280,10 +1281,11 @@ void nvim_unsubscribe(uint64_t channel_id, String event) /// "#rrggbb" hexadecimal string. /// /// Example: -///
vim
-///     :echo nvim_get_color_by_name("Pink")
-///     :echo nvim_get_color_by_name("#cbcbcb")
-/// 
+/// +/// ```vim +/// :echo nvim_get_color_by_name("Pink") +/// :echo nvim_get_color_by_name("#cbcbcb") +/// ``` /// /// @param name Color name or "#rrggbb" string /// @return 24-bit RGB value, or -1 for invalid argument. @@ -1420,14 +1422,16 @@ ArrayOf(Dictionary) nvim_get_keymap(String mode) /// Empty {rhs} is ||. |keycodes| are replaced as usual. /// /// Example: -///
vim
-///     call nvim_set_keymap('n', ' ', '', {'nowait': v:true})
-/// 
+/// +/// ```vim +/// call nvim_set_keymap('n', ' ', '', {'nowait': v:true}) +/// ``` /// /// is equivalent to: -///
vim
-///     nmap   
-/// 
+/// +/// ```vim +/// nmap +/// ``` /// /// @param channel_id /// @param mode Mode short-name (map command prefix: "n", "i", "v", "x", …) diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index ac27554172..6a16d06fb7 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -56,16 +56,19 @@ /// this should not be used to specify arbitrary WM screen positions. /// /// Example (Lua): window-relative float -///
lua
-///     vim.api.nvim_open_win(0, false,
-///       {relative='win', row=3, col=3, width=12, height=3})
-/// 
+/// +/// ```lua +/// vim.api.nvim_open_win(0, false, +/// {relative='win', row=3, col=3, width=12, height=3}) +/// ``` /// /// Example (Lua): buffer-relative float (travels as buffer is scrolled) -///
lua
-///     vim.api.nvim_open_win(0, false,
-///       {relative='win', width=12, height=3, bufpos={100,10}})
-/// 
+/// +/// ```lua +/// vim.api.nvim_open_win(0, false, +/// {relative='win', width=12, height=3, bufpos={100,10}}) +/// }) +/// ``` /// /// @param buffer Buffer to display, or 0 for current buffer /// @param enter Enter the window (make it the current window) -- cgit From a916523574135549865d698732a6c9eaae7c7811 Mon Sep 17 00:00:00 2001 From: glepnir Date: Sun, 10 Sep 2023 15:09:20 +0800 Subject: fix(ui): doesn't trigger au event when enter is false --- src/nvim/api/win_config.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index ac27554172..3a3e6da2b1 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -190,7 +190,8 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(float_config) *config, E } // autocmds in win_enter or win_set_buf below may close the window if (win_valid(wp) && buffer > 0) { - win_set_buf(wp, buf, fconfig.noautocmd, err); + Boolean noautocmd = !enter || fconfig.noautocmd; + win_set_buf(wp, buf, noautocmd, err); } if (!win_valid(wp)) { api_set_error(err, kErrorTypeException, "Window was closed immediately"); -- cgit From 71530cc972576e6656431b6d000aec9b69a0997e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 17 Sep 2023 20:29:18 +0800 Subject: feat(folds): support virtual text format for 'foldtext' (#25209) Co-authored-by: Lewis Russell --- src/nvim/api/extmark.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 05f62f6c7c..faab6e593c 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -1206,7 +1206,9 @@ VirtText parse_virt_text(Array chunks, Error *err, int *width) kv_push(virt_text, ((VirtTextChunk){ .text = text, .hl_id = hl_id })); } - *width = w; + if (width != NULL) { + *width = w; + } return virt_text; free_exit: -- cgit From fd08fd3de3020647c8ae73f1c7d2cf9a4926c828 Mon Sep 17 00:00:00 2001 From: glepnir Date: Thu, 14 Sep 2023 13:30:51 +0800 Subject: fix(float): add fixd option --- src/nvim/api/keysets.h | 1 + src/nvim/api/win_config.c | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/keysets.h b/src/nvim/api/keysets.h index 4e5e7af619..736ca9ce07 100644 --- a/src/nvim/api/keysets.h +++ b/src/nvim/api/keysets.h @@ -112,6 +112,7 @@ typedef struct { String footer_pos; String style; Boolean noautocmd; + Boolean fixed; } Dict(float_config); typedef struct { diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index ac27554172..74c5228329 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -160,6 +160,8 @@ /// - noautocmd: If true then no buffer-related autocommand events such as /// |BufEnter|, |BufLeave| or |BufWinEnter| may fire from /// calling this function. +/// - fixed: If true when anchor is NW or SW, the float window +/// would be kept fixed even if the window would be truncated. /// /// @param[out] err Error details, if any /// @@ -841,6 +843,10 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig, fconfig->noautocmd = config->noautocmd; } + if (HAS_KEY_X(config, fixed)) { + fconfig->fixed = config->fixed; + } + return true; #undef HAS_KEY_X } -- cgit From 8da986ea877b07a5eb117446f410f2a7fc8cd9cb Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 13 Sep 2023 13:39:18 +0200 Subject: refactor(grid): change schar_T representation to be more compact Previously, a screen cell would occupy 28+4=32 bytes per cell as we always made space for up to MAX_MCO+1 codepoints in a cell. As an example, even a pretty modest 50*80 screen would consume 50*80*2*32 = 256000, i e a quarter megabyte With the factor of two due to the TUI side buffer, and even more when using msg_grid and/or ext_multigrid. This instead stores a 4-byte union of either: - a valid UTF-8 sequence up to 4 bytes - an escape char which is invalid UTF-8 (0xFF) plus a 24-bit index to a glyph cache This avoids allocating space for huge composed glyphs _upfront_, while still keeping rendering such glyphs reasonably fast (1 hash table lookup + one plain index lookup). If the same large glyphs are using repeatedly on the screen, this is still a net reduction of memory/cache consumption. The only case which really gets worse is if you blast the screen full with crazy emojis and zalgo text and even this case only leads to 4 extra bytes per char. When only <= 4-byte glyphs are used, plus the 4-byte attribute code, i e 8 bytes in total there is a factor of four reduction of memory use. Memory which will be quite hot in cache as the screen buffer is scanned over in win_line() buffer text drawing A slight complication is that the representation depends on host byte order. I've tested this manually by compling and running this in qemu-s390x and it works fine. We might add a qemu based solution to CI at some point. --- src/nvim/api/ui.c | 15 +++++++++------ src/nvim/api/vim.c | 9 ++++++++- src/nvim/api/win_config.c | 8 ++++---- 3 files changed, 21 insertions(+), 11 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 70c97be984..0ea2310042 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -833,8 +833,7 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int bool was_space = false; for (size_t i = 0; i < ncells; i++) { repeat++; - if (i == ncells - 1 || attrs[i] != attrs[i + 1] - || strcmp(chunk[i], chunk[i + 1]) != 0) { + if (i == ncells - 1 || attrs[i] != attrs[i + 1] || chunk[i] != chunk[i + 1]) { if (UI_BUF_SIZE - BUF_POS(data) < 2 * (1 + 2 + sizeof(schar_T) + 5 + 5) + 1) { // close to overflowing the redraw buffer. finish this event, // flush, and start a new "grid_line" event at the current position. @@ -859,7 +858,9 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int uint32_t csize = (repeat > 1) ? 3 : ((attrs[i] != last_hl) ? 2 : 1); nelem++; mpack_array(buf, csize); - mpack_str(buf, chunk[i]); + char sc_buf[MAX_SCHAR_SIZE]; + schar_get(sc_buf, chunk[i]); + mpack_str(buf, sc_buf); if (csize >= 2) { mpack_uint(buf, (uint32_t)attrs[i]); if (csize >= 3) { @@ -869,7 +870,7 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int data->ncells_pending += MIN(repeat, 2); last_hl = attrs[i]; repeat = 0; - was_space = strequal(chunk[i], " "); + was_space = chunk[i] == schar_from_ascii(' '); } } // If the last chunk was all spaces, add a clearing chunk even if there are @@ -893,8 +894,10 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int for (int i = 0; i < endcol - startcol; i++) { remote_ui_cursor_goto(ui, row, startcol + i); remote_ui_highlight_set(ui, attrs[i]); - remote_ui_put(ui, chunk[i]); - if (utf_ambiguous_width(utf_ptr2char((char *)chunk[i]))) { + char sc_buf[MAX_SCHAR_SIZE]; + schar_get(sc_buf, chunk[i]); + remote_ui_put(ui, sc_buf); + if (utf_ambiguous_width(utf_ptr2char(sc_buf))) { data->client_col = -1; // force cursor update } } diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 916409b973..0a94b8aafc 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1947,7 +1947,9 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Arena *arena, E } ret = arena_array(arena, 3); size_t off = g->line_offset[(size_t)row] + (size_t)col; - ADD_C(ret, CSTR_AS_OBJ((char *)g->chars[off])); + char *sc_buf = arena_alloc(arena, MAX_SCHAR_SIZE, false); + schar_get(sc_buf, g->chars[off]); + ADD_C(ret, CSTR_AS_OBJ(sc_buf)); int attr = g->attrs[off]; ADD_C(ret, DICTIONARY_OBJ(hl_get_attr_by_id(attr, true, arena, err))); // will not work first time @@ -1963,6 +1965,11 @@ void nvim__screenshot(String path) ui_call_screenshot(path); } +void nvim__invalidate_glyph_cache(void) +{ + schar_cache_clear_force(); +} + Object nvim__unpack(String str, Error *err) FUNC_API_FAST { diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 63cf3bb701..a579b0dde5 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -16,7 +16,7 @@ #include "nvim/drawscreen.h" #include "nvim/extmark_defs.h" #include "nvim/globals.h" -#include "nvim/grid_defs.h" +#include "nvim/grid.h" #include "nvim/highlight_group.h" #include "nvim/macros.h" #include "nvim/mbyte.h" @@ -348,7 +348,7 @@ Dictionary nvim_win_get_config(Window window, Error *err) for (size_t i = 0; i < 8; i++) { Array tuple = ARRAY_DICT_INIT; - String s = cstrn_to_string(config->border_chars[i], sizeof(schar_T)); + String s = cstrn_to_string(config->border_chars[i], MAX_SCHAR_SIZE); int hi_id = config->border_hl_ids[i]; char *hi_name = syn_id2name(hi_id); @@ -520,7 +520,7 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err) { struct { const char *name; - schar_T chars[8]; + char chars[8][MAX_SCHAR_SIZE]; bool shadow_color; } defaults[] = { { "double", { "╔", "═", "╗", "║", "╝", "═", "╚", "║" }, false }, @@ -531,7 +531,7 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err) { NULL, { { NUL } }, false }, }; - schar_T *chars = fconfig->border_chars; + char (*chars)[MAX_SCHAR_SIZE] = fconfig->border_chars; int *hl_ids = fconfig->border_hl_ids; fconfig->border = true; -- cgit From 437ed3cee2d29a24d555a873d024cd851b953153 Mon Sep 17 00:00:00 2001 From: glepnir Date: Mon, 11 Sep 2023 19:46:15 +0800 Subject: fix(float): trigger winnew event when float window create --- src/nvim/api/win_config.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 63cf3bb701..35b9e73d81 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -195,6 +195,9 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(float_config) *config, E if (win_valid(wp) && buffer > 0) { Boolean noautocmd = !enter || fconfig.noautocmd; win_set_buf(wp, buf, noautocmd, err); + if (!fconfig.noautocmd) { + apply_autocmds(EVENT_WINNEW, NULL, NULL, false, buf); + } } if (!win_valid(wp)) { api_set_error(err, kErrorTypeException, "Window was closed immediately"); -- cgit From 1b55f51d0d8468ca357514a868ac8e188b0c8722 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 20 Sep 2023 04:15:23 -0700 Subject: docs: misc #24561 fix #24699 fix #25253 --- src/nvim/api/vim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 0a94b8aafc..7a5c7cc181 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1441,7 +1441,7 @@ ArrayOf(Dictionary) nvim_get_keymap(String mode) /// @param rhs Right-hand-side |{rhs}| of the mapping. /// @param opts Optional parameters map: Accepts all |:map-arguments| as keys except ||, /// values are booleans (default false). Also: -/// - "noremap" non-recursive mapping |:noremap| +/// - "noremap" disables |recursive_mapping|, like |:noremap| /// - "desc" human-readable description. /// - "callback" Lua function called in place of {rhs}. /// - "replace_keycodes" (boolean) When "expr" is true, replace keycodes in the -- cgit From 911f3d962358bb032b55e9984d0b25ffc522ff49 Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 21 Sep 2023 10:18:37 +0200 Subject: fix(tui): don't overwrite an assertion faliure message on exit If nvim exited with nonzero status this is for one of the two reasons - `:cquit` was invoked. This is used by users and plugins to communicate a result, like a nonzero status will fail a `git commit` operation - There was an internal error or deadly signal. in this case an error message was likely written to stderr or to the screen. In the latter case, the error message was often hidden by the TUI exiting altscreen mode, which erases all visible terminal text. This change prevents this in the latter case, while still cleaning up the terminal properly when `:cquit` was deliberatily invoked. Other cleanup like exiting mouse mode and raw mode is still done. --- src/nvim/api/ui_events.in.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index fc70215352..6ca5024a04 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -167,4 +167,7 @@ void msg_history_show(Array entries) FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY; void msg_history_clear(void) FUNC_API_SINCE(10) FUNC_API_REMOTE_ONLY; + +void error_exit(Integer status) + FUNC_API_SINCE(12); #endif // NVIM_API_UI_EVENTS_IN_H -- cgit From 64e8a3c4d19eab40888fbac36b96e97bd9d68c42 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 22 Sep 2023 15:36:24 +0800 Subject: fix(ui): handle virtual text with multiple hl in more cases (#25304) --- src/nvim/api/extmark.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index faab6e593c..1e44c66974 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -1188,8 +1188,7 @@ VirtText parse_virt_text(Array chunks, Error *err, int *width) goto free_exit; } if (j < arr.size - 1) { - kv_push(virt_text, ((VirtTextChunk){ .text = NULL, - .hl_id = hl_id })); + kv_push(virt_text, ((VirtTextChunk){ .text = NULL, .hl_id = hl_id })); } } } else { -- cgit From b7763d7f6b7fdcabe06658c664457df8bc147563 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 22 Sep 2023 17:56:05 +0800 Subject: fix(api): get virtual text with multiple hl properly (#25307) --- src/nvim/api/extmark.c | 57 ++++++++++++++++++++++++++++------------------- src/nvim/api/win_config.c | 18 +++++---------- 2 files changed, 40 insertions(+), 35 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 1e44c66974..91e197bea7 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -113,6 +113,36 @@ static Object hl_group_name(int hl_id, bool hl_name) } } +Array virt_text_to_array(VirtText vt, bool hl_name) +{ + Array chunks = ARRAY_DICT_INIT; + Array hl_array = ARRAY_DICT_INIT; + for (size_t i = 0; i < kv_size(vt); i++) { + char *text = kv_A(vt, i).text; + int hl_id = kv_A(vt, i).hl_id; + if (text == NULL) { + if (hl_id > 0) { + ADD(hl_array, hl_group_name(hl_id, hl_name)); + } + continue; + } + Array chunk = ARRAY_DICT_INIT; + ADD(chunk, CSTR_TO_OBJ(text)); + if (hl_array.size > 0) { + if (hl_id > 0) { + ADD(hl_array, hl_group_name(hl_id, hl_name)); + } + ADD(chunk, ARRAY_OBJ(hl_array)); + hl_array = (Array)ARRAY_DICT_INIT; + } else if (hl_id > 0) { + ADD(chunk, hl_group_name(hl_id, hl_name)); + } + ADD(chunks, ARRAY_OBJ(chunk)); + } + assert(hl_array.size == 0); + return chunks; +} + static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict, bool hl_name) { Array rv = ARRAY_DICT_INIT; @@ -145,16 +175,7 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict } 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, CSTR_TO_OBJ(vtc->text)); - if (vtc->hl_id > 0) { - ADD(chunk, hl_group_name(vtc->hl_id, hl_name)); - } - ADD(chunks, ARRAY_OBJ(chunk)); - } + Array chunks = virt_text_to_array(decor->virt_text, hl_name); PUT(dict, "virt_text", ARRAY_OBJ(chunks)); PUT(dict, "virt_text_hide", BOOLEAN_OBJ(decor->virt_text_hide)); if (decor->virt_text_pos == kVTWinCol) { @@ -171,19 +192,9 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict if (kv_size(decor->virt_lines)) { Array all_chunks = ARRAY_DICT_INIT; bool virt_lines_leftcol = false; - for (size_t i = 0; i < decor->virt_lines.size; i++) { - Array chunks = ARRAY_DICT_INIT; - VirtText *vt = &decor->virt_lines.items[i].line; - virt_lines_leftcol = decor->virt_lines.items[i].left_col; - for (size_t j = 0; j < vt->size; j++) { - Array chunk = ARRAY_DICT_INIT; - VirtTextChunk *vtc = &vt->items[j]; - ADD(chunk, CSTR_TO_OBJ(vtc->text)); - if (vtc->hl_id > 0) { - ADD(chunk, hl_group_name(vtc->hl_id, hl_name)); - } - ADD(chunks, ARRAY_OBJ(chunk)); - } + for (size_t i = 0; i < kv_size(decor->virt_lines); i++) { + virt_lines_leftcol = kv_A(decor->virt_lines, i).left_col; + Array chunks = virt_text_to_array(kv_A(decor->virt_lines, i).line, hl_name); ADD(all_chunks, ARRAY_OBJ(chunks)); } PUT(dict, "virt_lines", ARRAY_OBJ(all_chunks)); diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index ebdbd896a5..ea0b7ce512 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -259,34 +259,28 @@ void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err) Dictionary config_put_bordertext(Dictionary config, FloatConfig *fconfig, BorderTextType bordertext_type) { - VirtText chunks; + VirtText vt; AlignTextPos align; char *field_name; char *field_pos_name; switch (bordertext_type) { case kBorderTextTitle: - chunks = fconfig->title_chunks; + vt = fconfig->title_chunks; align = fconfig->title_pos; field_name = "title"; field_pos_name = "title_pos"; break; case kBorderTextFooter: - chunks = fconfig->footer_chunks; + vt = fconfig->footer_chunks; align = fconfig->footer_pos; field_name = "footer"; field_pos_name = "footer_pos"; break; + default: + abort(); } - Array bordertext = ARRAY_DICT_INIT; - for (size_t i = 0; i < chunks.size; i++) { - Array tuple = ARRAY_DICT_INIT; - ADD(tuple, CSTR_TO_OBJ(chunks.items[i].text)); - if (chunks.items[i].hl_id > 0) { - ADD(tuple, CSTR_TO_OBJ(syn_id2name(chunks.items[i].hl_id))); - } - ADD(bordertext, ARRAY_OBJ(tuple)); - } + Array bordertext = virt_text_to_array(vt, true); PUT(config, field_name, ARRAY_OBJ(bordertext)); char *pos; -- cgit From 4d3a38ac074fff7e2a4bede4cee7699bdd55ffdc Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 24 Sep 2023 10:57:09 +0800 Subject: fix(api, lua): handle setting v: variables properly (#25325) --- src/nvim/api/private/helpers.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 8fcabb3605..5463578b56 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -21,8 +21,10 @@ #include "nvim/buffer_defs.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/eval/vars.h" #include "nvim/ex_eval.h" #include "nvim/garray.h" +#include "nvim/globals.h" #include "nvim/highlight_group.h" #include "nvim/lua/executor.h" #include "nvim/map.h" @@ -235,8 +237,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva // Delete the key if (di == NULL) { // Doesn't exist, fail - api_set_error(err, kErrorTypeValidation, "Key not found: %s", - key.data); + api_set_error(err, kErrorTypeValidation, "Key not found: %s", key.data); } else { // Notify watchers if (watched) { @@ -265,13 +266,23 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva di = tv_dict_item_alloc_len(key.data, key.size); tv_dict_add(dict, di); } else { - if (watched) { - tv_copy(&di->di_tv, &oldtv); - } // Return the old value if (retval) { rv = vim_to_object(&di->di_tv); } + bool type_error = false; + if (dict == &vimvardict + && !before_set_vvar(key.data, di, &tv, true, watched, &type_error)) { + tv_clear(&tv); + if (type_error) { + api_set_error(err, kErrorTypeValidation, + "Setting v:%s to value with wrong type", key.data); + } + return rv; + } + if (watched) { + tv_copy(&di->di_tv, &oldtv); + } tv_clear(&di->di_tv); } -- cgit From b3be7b741386bbbf076e87859cb1e3d990316f5c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 25 Sep 2023 11:06:15 +0800 Subject: fix(api): handle NUL in nvim_err_write() and nvim_out_write() (#25354) --- src/nvim/api/vim.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 7a5c7cc181..78396edef5 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1709,6 +1709,8 @@ static void write_msg(String message, bool to_err, bool writeln) msg_didout = true; \ kv_drop(line_buf, kv_size(line_buf)); \ kv_resize(line_buf, LINE_BUFFER_MIN_SIZE); \ + } else if (c == NUL) { \ + kv_push(line_buf, NL); \ } else { \ kv_push(line_buf, c); \ } -- cgit From db51548036ebe4b01c5b78aeca7a76aa71ab4fbe Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sun, 24 Sep 2023 21:39:59 -0700 Subject: docs: do not use deprecated functions #25334 --- src/nvim/api/deprecated.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index f5a77ece7e..f345edc52c 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -518,6 +518,7 @@ static int64_t convert_index(int64_t index) /// @return Option Information Dictionary nvim_get_option_info(String name, Error *err) FUNC_API_SINCE(7) + FUNC_API_DEPRECATED_SINCE(11) { return get_vimoption(name, OPT_GLOBAL, curbuf, curwin, err); } @@ -531,6 +532,7 @@ Dictionary nvim_get_option_info(String name, Error *err) /// @param[out] err Error details, if any void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err) FUNC_API_SINCE(1) + FUNC_API_DEPRECATED_SINCE(11) { set_option_to(channel_id, NULL, SREQ_GLOBAL, name, value, err); } @@ -543,6 +545,7 @@ void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err) /// @return Option value (global) Object nvim_get_option(String name, Arena *arena, Error *err) FUNC_API_SINCE(1) + FUNC_API_DEPRECATED_SINCE(11) { return get_option_from(NULL, SREQ_GLOBAL, name, err); } @@ -556,6 +559,7 @@ Object nvim_get_option(String name, Arena *arena, Error *err) /// @return Option value Object nvim_buf_get_option(Buffer buffer, String name, Arena *arena, Error *err) FUNC_API_SINCE(1) + FUNC_API_DEPRECATED_SINCE(11) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -577,6 +581,7 @@ Object nvim_buf_get_option(Buffer buffer, String name, Arena *arena, Error *err) /// @param[out] err Error details, if any void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, String name, Object value, Error *err) FUNC_API_SINCE(1) + FUNC_API_DEPRECATED_SINCE(11) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -596,6 +601,7 @@ void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, String name, Object /// @return Option value Object nvim_win_get_option(Window window, String name, Arena *arena, Error *err) FUNC_API_SINCE(1) + FUNC_API_DEPRECATED_SINCE(11) { win_T *win = find_window_by_handle(window, err); @@ -617,6 +623,7 @@ Object nvim_win_get_option(Window window, String name, Arena *arena, Error *err) /// @param[out] err Error details, if any void nvim_win_set_option(uint64_t channel_id, Window window, String name, Object value, Error *err) FUNC_API_SINCE(1) + FUNC_API_DEPRECATED_SINCE(11) { win_T *win = find_window_by_handle(window, err); -- cgit From f8ea49cfe1f4f3ed30da160d346553f0949ec1de Mon Sep 17 00:00:00 2001 From: glepnir Date: Mon, 18 Sep 2023 14:50:27 +0800 Subject: fix(highlight): add force in nvim_set_hl --- src/nvim/api/keysets.h | 1 + src/nvim/api/vim.c | 1 + 2 files changed, 2 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/keysets.h b/src/nvim/api/keysets.h index 4e5e7af619..a98cbe276f 100644 --- a/src/nvim/api/keysets.h +++ b/src/nvim/api/keysets.h @@ -168,6 +168,7 @@ typedef struct { Integer blend; Boolean fg_indexed; Boolean bg_indexed; + Boolean force; } Dict(highlight); typedef struct { diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 916409b973..9d08e9b6c7 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -151,6 +151,7 @@ Dictionary nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena *arena, E /// - cterm: cterm attribute map, like |highlight-args|. If not set, /// cterm attributes will match those from the attribute map /// documented above. +/// - force: if true force update the highlight group when it exists. /// @param[out] err Error details, if any /// // TODO(bfredl): val should take update vs reset flag -- cgit From b85f1dafc7c0a19704135617454f1c66f41202c1 Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 27 Sep 2023 22:21:17 +0200 Subject: refactor(messages): fold msg_attr into msg problem: there are too many different functions in message.c solution: fold some of the functions into themselves --- src/nvim/api/vim.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 00641c633d..c55f9592bf 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1699,21 +1699,26 @@ static void write_msg(String message, bool to_err, bool writeln) { static StringBuilder out_line_buf = KV_INITIAL_VALUE; static StringBuilder err_line_buf = KV_INITIAL_VALUE; + StringBuilder *line_buf = to_err ? &err_line_buf : &out_line_buf; -#define PUSH_CHAR(c, line_buf, msg) \ - if (kv_max(line_buf) == 0) { \ - kv_resize(line_buf, LINE_BUFFER_MIN_SIZE); \ +#define PUSH_CHAR(c) \ + if (kv_max(*line_buf) == 0) { \ + kv_resize(*line_buf, LINE_BUFFER_MIN_SIZE); \ } \ if (c == NL) { \ - kv_push(line_buf, NUL); \ - msg(line_buf.items); \ + kv_push(*line_buf, NUL); \ + if (to_err) { \ + emsg(line_buf->items); \ + } else { \ + msg(line_buf->items, 0); \ + } \ msg_didout = true; \ - kv_drop(line_buf, kv_size(line_buf)); \ - kv_resize(line_buf, LINE_BUFFER_MIN_SIZE); \ + kv_drop(*line_buf, kv_size(*line_buf)); \ + kv_resize(*line_buf, LINE_BUFFER_MIN_SIZE); \ } else if (c == NUL) { \ - kv_push(line_buf, NL); \ + kv_push(*line_buf, NL); \ } else { \ - kv_push(line_buf, c); \ + kv_push(*line_buf, c); \ } no_wait_return++; @@ -1721,18 +1726,10 @@ static void write_msg(String message, bool to_err, bool writeln) if (got_int) { break; } - if (to_err) { - PUSH_CHAR(message.data[i], err_line_buf, emsg); - } else { - PUSH_CHAR(message.data[i], out_line_buf, msg); - } + PUSH_CHAR(message.data[i]); } if (writeln) { - if (to_err) { - PUSH_CHAR(NL, err_line_buf, emsg); - } else { - PUSH_CHAR(NL, out_line_buf, msg); - } + PUSH_CHAR(NL); } no_wait_return--; msg_end(); -- cgit From af7d317f3ff31d5ac5d8724b5057a422e1451b54 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Tue, 26 Sep 2023 22:36:08 +0200 Subject: refactor: remove long long is 32-bits even on 64-bit windows which makes the type suboptimal for a codebase meant to be cross-platform. --- src/nvim/api/deprecated.c | 2 +- src/nvim/api/options.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index f345edc52c..a96485be83 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -729,7 +729,7 @@ static void set_option_to(uint64_t channel_id, void *to, int type, String name, "Option '%s' value is out of range", name.data, { return; }); - optval = NUMBER_OPTVAL(value.data.integer); + optval = NUMBER_OPTVAL((OptInt)value.data.integer); } else { VALIDATE(value.type == kObjectTypeString, "Option '%s' value must be String", name.data, { return; diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index eb80683365..619e23affb 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -165,7 +165,7 @@ static OptVal object_as_optval(Object o, bool *error) case kObjectTypeBoolean: return BOOLEAN_OPTVAL(o.data.boolean); case kObjectTypeInteger: - return NUMBER_OPTVAL(o.data.integer); + return NUMBER_OPTVAL((OptInt)o.data.integer); case kObjectTypeString: return STRING_OPTVAL(o.data.string); default: -- cgit From cf8b2c0e74fd5e723b0c15c2ce84e6900fd322d3 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 30 Sep 2023 12:05:28 +0800 Subject: build(iwyu): add a few more _defs.h mappings (#25435) --- src/nvim/api/autocmd.c | 5 ++--- src/nvim/api/buffer.c | 2 +- src/nvim/api/command.c | 1 + src/nvim/api/deprecated.c | 4 +++- src/nvim/api/extmark.c | 3 ++- src/nvim/api/options.c | 8 +++++--- src/nvim/api/private/converter.c | 2 +- src/nvim/api/private/helpers.c | 2 +- src/nvim/api/private/helpers.h | 2 ++ src/nvim/api/private/validate.c | 10 ++++++---- src/nvim/api/private/validate.h | 5 +++++ src/nvim/api/ui.c | 1 + src/nvim/api/vim.c | 4 +++- src/nvim/api/vimscript.c | 4 +--- src/nvim/api/win_config.c | 4 +++- src/nvim/api/window.c | 7 ++++--- 16 files changed, 41 insertions(+), 23 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 2e4d2a622d..768ed869cc 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -8,17 +8,16 @@ #include #include +#include "klib/kvec.h" #include "lauxlib.h" #include "nvim/api/autocmd.h" +#include "nvim/api/keysets.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/ascii.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/eval/typval.h" -#include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds_defs.h" #include "nvim/globals.h" #include "nvim/lua/executor.h" diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index e8f9f809f2..64dddea5b8 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -4,7 +4,6 @@ // Some of this code was adapted from 'if_py_both.h' from the original // vim source -#include #include #include #include @@ -14,6 +13,7 @@ #include "klib/kvec.h" #include "lua.h" #include "nvim/api/buffer.h" +#include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/api/private/validate.h" diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 808d4e0b8d..eb32f46143 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -9,6 +9,7 @@ #include "klib/kvec.h" #include "lauxlib.h" #include "nvim/api/command.h" +#include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index a96485be83..e0827012f6 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -1,13 +1,15 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include #include #include -#include +#include #include "nvim/api/buffer.h" #include "nvim/api/deprecated.h" #include "nvim/api/extmark.h" +#include "nvim/api/keysets.h" #include "nvim/api/options.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 91e197bea7..14454b626e 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -9,8 +9,8 @@ #include "klib/kvec.h" #include "lauxlib.h" #include "nvim/api/extmark.h" +#include "nvim/api/keysets.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" @@ -20,6 +20,7 @@ #include "nvim/drawscreen.h" #include "nvim/extmark.h" #include "nvim/highlight_group.h" +#include "nvim/marktree.h" #include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/memory.h" diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 619e23affb..5a75d10043 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -1,22 +1,24 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include #include -#include #include +#include #include +#include "nvim/api/keysets.h" #include "nvim/api/options.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/autocmd.h" -#include "nvim/buffer_defs.h" +#include "nvim/buffer.h" #include "nvim/eval/window.h" #include "nvim/globals.h" #include "nvim/memory.h" #include "nvim/option.h" +#include "nvim/types.h" #include "nvim/vim.h" #include "nvim/window.h" diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index 68939e609c..dc6928f4b9 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -15,7 +15,6 @@ #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" -#include "nvim/garray.h" #include "nvim/lua/executor.h" #include "nvim/memory.h" #include "nvim/types.h" @@ -204,6 +203,7 @@ static inline void typval_encode_dict_end(EncodedData *const edata) #define TYPVAL_ENCODE_FIRST_ARG_TYPE EncodedData *const #define TYPVAL_ENCODE_FIRST_ARG_NAME edata #include "nvim/eval/typval_encode.c.h" + #undef TYPVAL_ENCODE_SCOPE #undef TYPVAL_ENCODE_NAME #undef TYPVAL_ENCODE_FIRST_ARG_TYPE diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 5463578b56..25e752bea8 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -20,7 +20,6 @@ #include "nvim/ascii.h" #include "nvim/buffer_defs.h" #include "nvim/eval/typval.h" -#include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" #include "nvim/ex_eval.h" #include "nvim/garray.h" @@ -34,6 +33,7 @@ #include "nvim/message.h" #include "nvim/msgpack_rpc/helpers.h" #include "nvim/pos.h" +#include "nvim/types.h" #include "nvim/ui.h" #include "nvim/version.h" diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 95e5cf67c8..e5ad30a10f 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -6,9 +6,11 @@ #include "klib/kvec.h" #include "nvim/api/private/defs.h" +#include "nvim/api/private/dispatch.h" #include "nvim/decoration.h" #include "nvim/ex_eval_defs.h" #include "nvim/getchar.h" +#include "nvim/gettext.h" #include "nvim/globals.h" #include "nvim/macros.h" #include "nvim/map.h" diff --git a/src/nvim/api/private/validate.c b/src/nvim/api/private/validate.c index c4dd5bcac8..cede32f72c 100644 --- a/src/nvim/api/private/validate.c +++ b/src/nvim/api/private/validate.c @@ -1,13 +1,15 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include +#include +#include + #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/api/private/validate.h" - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "api/private/validate.c.generated.h" -#endif +#include "nvim/ascii.h" +#include "nvim/globals.h" /// Creates "Invalid …" message and sets it on `err`. void api_err_invalid(Error *err, const char *name, const char *val_s, int64_t val_n, bool quote_val) diff --git a/src/nvim/api/private/validate.h b/src/nvim/api/private/validate.h index a3e77ea838..089b8d2f9c 100644 --- a/src/nvim/api/private/validate.h +++ b/src/nvim/api/private/validate.h @@ -1,8 +1,13 @@ #ifndef NVIM_API_PRIVATE_VALIDATE_H #define NVIM_API_PRIVATE_VALIDATE_H +#include +#include + #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/assert.h" +#include "nvim/macros.h" #define VALIDATE(cond, fmt_, fmt_arg1, code) \ do { \ diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 0ea2310042..e0b5e6ea57 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -21,6 +21,7 @@ #include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/highlight.h" +#include "nvim/macros.h" #include "nvim/main.h" #include "nvim/map.h" #include "nvim/mbyte.h" diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index c55f9592bf..f064a8e82a 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -14,6 +14,7 @@ #include "lauxlib.h" #include "nvim/api/buffer.h" #include "nvim/api/deprecated.h" +#include "nvim/api/keysets.h" #include "nvim/api/private/converter.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" @@ -26,12 +27,13 @@ #include "nvim/channel.h" #include "nvim/context.h" #include "nvim/cursor.h" +#include "nvim/decoration.h" #include "nvim/drawscreen.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" -#include "nvim/eval/typval_defs.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" +#include "nvim/fold.h" #include "nvim/getchar.h" #include "nvim/globals.h" #include "nvim/grid.h" diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 4801562ad2..b09e4d7d87 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -8,21 +8,19 @@ #include #include "klib/kvec.h" +#include "nvim/api/keysets.h" #include "nvim/api/private/converter.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/api/vimscript.h" #include "nvim/ascii.h" -#include "nvim/buffer_defs.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" -#include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" #include "nvim/ex_docmd.h" #include "nvim/garray.h" #include "nvim/globals.h" #include "nvim/memory.h" -#include "nvim/pos.h" #include "nvim/runtime.h" #include "nvim/vim.h" #include "nvim/viml/parser/expressions.h" diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index ea0b7ce512..656f33aab1 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -2,15 +2,17 @@ // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include +#include #include #include "klib/kvec.h" #include "nvim/api/extmark.h" +#include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" -#include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" #include "nvim/api/win_config.h" #include "nvim/ascii.h" +#include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/decoration.h" #include "nvim/drawscreen.h" diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 001797add5..53095ab019 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -6,12 +6,12 @@ #include #include +#include "nvim/api/keysets.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/api/window.h" -#include "nvim/ascii.h" +#include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" @@ -20,7 +20,8 @@ #include "nvim/gettext.h" #include "nvim/globals.h" #include "nvim/lua/executor.h" -#include "nvim/memline_defs.h" +#include "nvim/memory.h" +#include "nvim/message.h" #include "nvim/move.h" #include "nvim/plines.h" #include "nvim/pos.h" -- cgit From dc6d0d2daf69e2fdadda81feb97906dbc962a239 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 30 Sep 2023 14:41:34 +0800 Subject: refactor: reorganize option header files (#25437) - Move vimoption_T to option.h - option_defs.h is for option-related types - option_vars.h corresponds to Vim's option.h - option_defs.h and option_vars.h don't include each other --- src/nvim/api/vim.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index f064a8e82a..9d9a5080e4 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -55,6 +55,7 @@ #include "nvim/msgpack_rpc/unpacker.h" #include "nvim/ops.h" #include "nvim/option.h" +#include "nvim/option_vars.h" #include "nvim/optionstr.h" #include "nvim/os/input.h" #include "nvim/os/os_defs.h" -- cgit From 4200a0f1678c06c6da4e4cfb0184c29c1174ed21 Mon Sep 17 00:00:00 2001 From: glepnir Date: Wed, 27 Sep 2023 17:23:42 +0800 Subject: feat(float): support toggle show float window --- src/nvim/api/keysets.h | 1 + src/nvim/api/win_config.c | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/keysets.h b/src/nvim/api/keysets.h index 236e75983e..429826f231 100644 --- a/src/nvim/api/keysets.h +++ b/src/nvim/api/keysets.h @@ -113,6 +113,7 @@ typedef struct { String style; Boolean noautocmd; Boolean fixed; + Boolean hide; } Dict(float_config); typedef struct { diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index ea0b7ce512..60d32eb30d 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -165,6 +165,7 @@ /// calling this function. /// - fixed: If true when anchor is NW or SW, the float window /// would be kept fixed even if the window would be truncated. +/// - hide: If true the floating window will be hidden. /// /// @param[out] err Error details, if any /// @@ -323,6 +324,7 @@ Dictionary nvim_win_get_config(Window window, Error *err) PUT(rv, "focusable", BOOLEAN_OBJ(config->focusable)); PUT(rv, "external", BOOLEAN_OBJ(config->external)); + PUT(rv, "hide", BOOLEAN_OBJ(config->hide)); if (wp->w_floating) { PUT(rv, "width", INTEGER_OBJ(config->width)); @@ -848,6 +850,10 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig, fconfig->fixed = config->fixed; } + if (HAS_KEY_X(config, hide)) { + fconfig->hide = config->hide; + } + return true; #undef HAS_KEY_X } -- cgit From 2615ed879e66a3d05920c47177e77383adc7aca0 Mon Sep 17 00:00:00 2001 From: Daniel Steinberg Date: Tue, 18 Jul 2023 17:02:45 -0400 Subject: feat(ui): allow to get the highlight namespace --- src/nvim/api/keysets.h | 5 +++++ src/nvim/api/vim.c | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/keysets.h b/src/nvim/api/keysets.h index 236e75983e..5962dec3ec 100644 --- a/src/nvim/api/keysets.h +++ b/src/nvim/api/keysets.h @@ -195,6 +195,11 @@ typedef struct { Boolean create; } Dict(get_highlight); +typedef struct { + OptionalKeys is_set__get_ns_; + Window winid; +} Dict(get_ns); + typedef struct { OptionalKeys is_set__win_text_height_; Integer start_row; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index c55f9592bf..6a38374ade 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -170,6 +170,29 @@ void nvim_set_hl(Integer ns_id, String name, Dict(highlight) *val, Error *err) } } +/// Gets the active highlight namespace. +/// +/// @param opts Optional parameters +/// - winid: (number) |window-ID| for retrieving a window's highlight +/// namespace. A value of -1 is returned when |nvim_win_set_hl_ns()| +/// has not been called for the window (or was called with a namespace +/// of -1). +/// @param[out] err Error details, if any +/// @return Namespace id, or -1 +Integer nvim_get_hl_ns(Dict(get_ns) *opts, Error *err) + FUNC_API_SINCE(12) +{ + if (HAS_KEY(opts, get_ns, winid)) { + win_T *win = find_window_by_handle(opts->winid, err); + if (!win) { + return 0; + } + return win->w_ns_hl; + } else { + return ns_hl_global; + } +} + /// Set active namespace for highlights defined with |nvim_set_hl()|. This can be set for /// a single window, see |nvim_win_set_hl_ns()|. /// -- cgit From 09a17f91d0d362c6e58bfdbe3ccdeacffb0b44b9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 2 Oct 2023 10:45:33 +0800 Subject: refactor: move cmdline completion types to cmdexpand_defs.h (#25465) --- src/nvim/api/command.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index eb32f46143..f4c6f646eb 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -17,6 +17,7 @@ #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" +#include "nvim/cmdexpand_defs.h" #include "nvim/decoration.h" #include "nvim/ex_cmds.h" #include "nvim/ex_docmd.h" -- cgit From b2a8a9314798e18c0685faf7463bda32f691d755 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 3 Oct 2023 20:54:42 +0800 Subject: fix(api): avoid immediate TextChanged with nvim_create_buf (#25492) --- src/nvim/api/vim.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 675aaf1006..b8e0934669 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -941,6 +941,12 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err) goto fail; } + // Set last_changedtick to avoid triggering a TextChanged autocommand right + // after it was added. + buf->b_last_changedtick = buf_get_changedtick(buf); + buf->b_last_changedtick_i = buf_get_changedtick(buf); + buf->b_last_changedtick_pum = buf_get_changedtick(buf); + // Only strictly needed for scratch, but could just as well be consistent // and do this now. buffer is created NOW, not when it latter first happen // to reach a window or aucmd_prepbuf() .. -- cgit From 30d311ebcf9433f84bd4d98f9e049b36c9d352ac Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sun, 8 Oct 2023 11:59:54 +0200 Subject: fix(PVS/V592): expression is enclosed by parentheses twice --- src/nvim/api/vim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index b8e0934669..ce3eca52b5 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -587,7 +587,7 @@ ArrayOf(String) nvim__get_runtime(Array pat, Boolean all, Dict(runtime) *opts, E FUNC_API_SINCE(8) FUNC_API_FAST { - VALIDATE((!opts->do_source || nlua_is_deferred_safe()), "%s", "'do_source' used in fast callback", + VALIDATE(!opts->do_source || nlua_is_deferred_safe(), "%s", "'do_source' used in fast callback", {}); if (ERROR_SET(err)) { return (Array)ARRAY_DICT_INIT; -- cgit From 139e6f68f937b9efcadf2709ee1c83213d3266fa Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:50:44 +0200 Subject: fix(autocmd): API functions accept garbage after event name #25523 "VimEnter foo" was accepted as a valid event name for "VimEnter". Events delimited with commas, eg. "VimEnter,BufRead", were also accepted, even though only the first event was actually parsed. Co-authored-by: ii14 --- src/nvim/api/autocmd.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 768ed869cc..d19f44798b 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -33,13 +33,11 @@ // Copy string or array of strings into an empty array. // Get the event number, unless it is an error. Then goto `goto_name`. #define GET_ONE_EVENT(event_nr, event_str, goto_name) \ - char *__next_ev; \ event_T event_nr = \ - event_name2nr(event_str.data.string.data, &__next_ev); \ - if (event_nr >= NUM_EVENTS) { \ - api_set_error(err, kErrorTypeValidation, "unexpected event"); \ + event_name2nr_str(event_str.data.string); \ + VALIDATE_S((event_nr < NUM_EVENTS), "event", event_str.data.string.data, { \ goto goto_name; \ - } + }); // ID for associating autocmds created via nvim_create_autocmd // Used to delete autocmds from nvim_del_autocmd -- cgit From 9ff6f73f838a1f90d09922448c434033ba5e094e Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Mon, 9 Oct 2023 00:36:48 +0600 Subject: refactor: allow not having a `default` case for enum Problem: The style guide states that all switch statements that are not conditional on an enum must have a `default` case, but does not give any explicit guideline for switch statements that are conditional on enums. As a result, a `default` case is added in many enum switch statements, even when the switch statement is exhaustive. This is not ideal because it removes the ability to have compiler errors to easily detect unchanged switch statements when a new possible value for an enum is added. Solution: Add explicit guidelines for switch statements that are conditional on an enum, clarifying that a `default` case is not necessary if the switch statement is exhaustive. Also refactor pre-existing code with unnecessary `default` cases. --- src/nvim/api/autocmd.c | 2 +- src/nvim/api/options.c | 6 ++---- src/nvim/api/private/converter.c | 3 --- src/nvim/api/private/helpers.c | 10 ++-------- src/nvim/api/win_config.c | 2 -- 5 files changed, 5 insertions(+), 18 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index d19f44798b..d0efb58cb6 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -294,7 +294,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) case kCallbackPartial: PUT(autocmd_info, "callback", CSTR_AS_OBJ(callback_to_string(cb))); break; - default: + case kCallbackNone: abort(); } } else { diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 5a75d10043..867d1d5e5c 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -146,16 +146,14 @@ static Object optval_as_object(OptVal o) return BOOLEAN_OBJ(o.data.boolean); case kNone: return NIL; - default: - abort(); } + UNREACHABLE; case kOptValTypeNumber: return INTEGER_OBJ(o.data.number); case kOptValTypeString: return STRING_OBJ(o.data.string); - default: - abort(); } + UNREACHABLE; } /// Consume an API Object and convert it to an OptVal. diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index dc6928f4b9..10152cb3c8 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -363,9 +363,6 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) tv->vval.v_string = xstrdup(name); break; } - - default: - abort(); } return true; diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 25e752bea8..eaee94786c 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -610,9 +610,6 @@ void api_free_object(Object value) case kObjectTypeLuaRef: api_free_luaref(value.data.luaref); break; - - default: - abort(); } } @@ -800,10 +797,8 @@ Object copy_object(Object obj, Arena *arena) case kObjectTypeLuaRef: return LUAREF_OBJ(api_new_luaref(obj.data.luaref)); - - default: - abort(); } + UNREACHABLE; } void api_set_error(Error *err, ErrorType errType, const char *format, ...) @@ -884,9 +879,8 @@ char *api_typename(ObjectType t) return "Window"; case kObjectTypeTabpage: return "Tabpage"; - default: - abort(); } + UNREACHABLE; } HlMessage parse_hl_msg(Array chunks, Error *err) diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index ca7086ab7f..2fd30bc5a5 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -279,8 +279,6 @@ Dictionary config_put_bordertext(Dictionary config, FloatConfig *fconfig, field_name = "footer"; field_pos_name = "footer_pos"; break; - default: - abort(); } Array bordertext = virt_text_to_array(vt, true); -- cgit From 13f55750e9bea8ec8f50550546edc64a0f0964d8 Mon Sep 17 00:00:00 2001 From: nwounkn Date: Fri, 13 Oct 2023 12:01:26 +0500 Subject: fix(ui): empty line before the next message after :silent command Problem: The next command after `silent !{cmd}` or `silent lua print('str')` prints an empty line before printing a message, because these commands set `msg_didout = true` despite not printing any messages. Solution: Set `msg_didout = true` only if `msg_silent == 0` --- src/nvim/api/vim.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index ce3eca52b5..6ce1f41e39 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1744,7 +1744,9 @@ static void write_msg(String message, bool to_err, bool writeln) } else { \ msg(line_buf->items, 0); \ } \ - msg_didout = true; \ + if (msg_silent == 0) { \ + msg_didout = true; \ + } \ kv_drop(*line_buf, kv_size(*line_buf)); \ kv_resize(*line_buf, LINE_BUFFER_MIN_SIZE); \ } else if (c == NUL) { \ -- cgit From 93b9c889465ee6a55e71c1fd681c1c6b1d5ed060 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Wed, 27 Sep 2023 23:30:17 +0600 Subject: refactor(options): unify set_num_option and set_bool_option --- src/nvim/api/options.c | 41 ----------------------------------------- 1 file changed, 41 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 867d1d5e5c..498638d606 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -133,47 +133,6 @@ static buf_T *do_ft_buf(char *filetype, aco_save_T *aco, Error *err) return ftbuf; } -/// Consume an OptVal and convert it to an API Object. -static Object optval_as_object(OptVal o) -{ - switch (o.type) { - case kOptValTypeNil: - return NIL; - case kOptValTypeBoolean: - switch (o.data.boolean) { - case kFalse: - case kTrue: - return BOOLEAN_OBJ(o.data.boolean); - case kNone: - return NIL; - } - UNREACHABLE; - case kOptValTypeNumber: - return INTEGER_OBJ(o.data.number); - case kOptValTypeString: - return STRING_OBJ(o.data.string); - } - UNREACHABLE; -} - -/// Consume an API Object and convert it to an OptVal. -static OptVal object_as_optval(Object o, bool *error) -{ - switch (o.type) { - case kObjectTypeNil: - return NIL_OPTVAL; - case kObjectTypeBoolean: - return BOOLEAN_OPTVAL(o.data.boolean); - case kObjectTypeInteger: - return NUMBER_OPTVAL((OptInt)o.data.integer); - case kObjectTypeString: - return STRING_OPTVAL(o.data.string); - default: - *error = true; - return NIL_OPTVAL; - } -} - /// Gets the value of an option. The behavior of this function matches that of /// |:set|: the local value of an option is returned if it exists; otherwise, /// the global value is returned. Local values always correspond to the current -- cgit From 6c87d3e0fbf88ae693be11a3ede3a1ec6ec0e30e Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Thu, 19 Oct 2023 20:09:02 +0600 Subject: refactor(options): `get_option_value_strict()` and `SREQ_*` `SREQ_*` values are now actual typedef'd enums. `get_option_value_strict()` has also been refactored and split into two functions, `get_option_attrs()` for getting the option attributes, and `get_option_value_strict()` for getting the actual value. Moreover, it now returns an `OptVal`. Other miscellaneous refactors have also been made. --- src/nvim/api/deprecated.c | 116 ++++++++------------ src/nvim/api/options.c | 264 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 238 insertions(+), 142 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index e0827012f6..31ba20f627 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -536,7 +536,7 @@ void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err) FUNC_API_SINCE(1) FUNC_API_DEPRECATED_SINCE(11) { - set_option_to(channel_id, NULL, SREQ_GLOBAL, name, value, err); + set_option_to(channel_id, NULL, kOptReqGlobal, name, value, err); } /// Gets the global value of an option. @@ -549,7 +549,7 @@ Object nvim_get_option(String name, Arena *arena, Error *err) FUNC_API_SINCE(1) FUNC_API_DEPRECATED_SINCE(11) { - return get_option_from(NULL, SREQ_GLOBAL, name, err); + return get_option_from(NULL, kOptReqGlobal, name, err); } /// Gets a buffer option value @@ -569,7 +569,7 @@ Object nvim_buf_get_option(Buffer buffer, String name, Arena *arena, Error *err) return (Object)OBJECT_INIT; } - return get_option_from(buf, SREQ_BUF, name, err); + return get_option_from(buf, kOptReqBuf, name, err); } /// Sets a buffer option value. Passing `nil` as value deletes the option (only @@ -591,7 +591,7 @@ void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, String name, Object return; } - set_option_to(channel_id, buf, SREQ_BUF, name, value, err); + set_option_to(channel_id, buf, kOptReqBuf, name, value, err); } /// Gets a window option value @@ -611,7 +611,7 @@ Object nvim_win_get_option(Window window, String name, Arena *arena, Error *err) return (Object)OBJECT_INIT; } - return get_option_from(win, SREQ_WIN, name, err); + return get_option_from(win, kOptReqWin, name, err); } /// Sets a window option value. Passing `nil` as value deletes the option (only @@ -633,76 +633,56 @@ void nvim_win_set_option(uint64_t channel_id, Window window, String name, Object return; } - set_option_to(channel_id, win, SREQ_WIN, name, value, err); + set_option_to(channel_id, win, kOptReqWin, name, value, err); } /// Gets the value of a global or local (buffer, window) option. /// -/// @param from If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer -/// to the window or buffer. -/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF` -/// @param name The option name -/// @param[out] err Details of an error that may have occurred -/// @return the option value -static Object get_option_from(void *from, int type, String name, Error *err) +/// @param[in] from Pointer to buffer or window for local option value. +/// @param req_scope Requested option scope. See OptReqScope in option.h. +/// @param name The option name. +/// @param[out] err Details of an error that may have occurred. +/// +/// @return the option value. +static Object get_option_from(void *from, OptReqScope req_scope, String name, Error *err) { - Object rv = OBJECT_INIT; - VALIDATE_S(name.size > 0, "option name", "", { - return rv; + return (Object)OBJECT_INIT; }); - // Return values - int64_t numval; - char *stringval = NULL; + OptVal value = get_option_value_strict(name.data, req_scope, from, err); + if (ERROR_SET(err)) { + return (Object)OBJECT_INIT; + } - int flags = get_option_value_strict(name.data, &numval, &stringval, type, from); - VALIDATE_S(flags != 0, "option name", name.data, { - return rv; + VALIDATE_S(value.type != kOptValTypeNil, "option name", name.data, { + return (Object)OBJECT_INIT; }); - if (flags & SOPT_BOOL) { - rv.type = kObjectTypeBoolean; - rv.data.boolean = numval ? true : false; - } else if (flags & SOPT_NUM) { - rv.type = kObjectTypeInteger; - rv.data.integer = numval; - } else if (flags & SOPT_STRING) { - if (!stringval) { - api_set_error(err, kErrorTypeException, "Failed to get option '%s'", name.data); - return rv; - } - rv.type = kObjectTypeString; - rv.data.string.data = stringval; - rv.data.string.size = strlen(stringval); - } else { - api_set_error(err, kErrorTypeException, "Unknown type for option '%s'", name.data); - } - - return rv; + return optval_as_object(value); } /// Sets the value of a global or local (buffer, window) option. /// -/// @param to If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer -/// to the window or buffer. -/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF` -/// @param name The option name -/// @param[out] err Details of an error that may have occurred -static void set_option_to(uint64_t channel_id, void *to, int type, String name, Object value, - Error *err) +/// @param[in] to Pointer to buffer or window for local option value. +/// @param req_scope Requested option scope. See OptReqScope in option.h. +/// @param name The option name. +/// @param value New option value. +/// @param[out] err Details of an error that may have occurred. +static void set_option_to(uint64_t channel_id, void *to, OptReqScope req_scope, String name, + Object value, Error *err) { VALIDATE_S(name.size > 0, "option name", "", { return; }); - int flags = get_option_value_strict(name.data, NULL, NULL, type, to); + int flags = get_option_attrs(name.data); VALIDATE_S(flags != 0, "option name", name.data, { return; }); if (value.type == kObjectTypeNil) { - if (type == SREQ_GLOBAL) { + if (req_scope == kOptReqGlobal) { api_set_error(err, kErrorTypeException, "Cannot unset option '%s'", name.data); return; } else if (!(flags & SOPT_GLOBAL)) { @@ -716,35 +696,23 @@ static void set_option_to(uint64_t channel_id, void *to, int type, String name, } } - OptVal optval; + bool error = false; + OptVal optval = object_as_optval(value, &error); - if (flags & SOPT_BOOL) { - VALIDATE(value.type == kObjectTypeBoolean, "Option '%s' value must be Boolean", name.data, { - return; - }); - optval = BOOLEAN_OPTVAL(value.data.boolean); - } else if (flags & SOPT_NUM) { - VALIDATE(value.type == kObjectTypeInteger, "Option '%s' value must be Integer", name.data, { - return; - }); - VALIDATE((value.data.integer <= INT_MAX && value.data.integer >= INT_MIN), - "Option '%s' value is out of range", name.data, { - return; - }); - optval = NUMBER_OPTVAL((OptInt)value.data.integer); - } else { - VALIDATE(value.type == kObjectTypeString, "Option '%s' value must be String", name.data, { - return; - }); - optval = STRING_OPTVAL(value.data.string); - } + // Handle invalid option value type. + // Don't use `name` in the error message here, because `name` can be any String. + // No need to check if value type actually matches the types for the option, as set_option_value() + // already handles that. + VALIDATE_EXP(!error, "value", "valid option type", api_typename(value.type), { + return; + }); // For global-win-local options -> setlocal // For win-local options -> setglobal and setlocal (opt_flags == 0) - const int opt_flags = (type == SREQ_WIN && !(flags & SOPT_GLOBAL)) ? 0 : - (type == SREQ_GLOBAL) ? OPT_GLOBAL : OPT_LOCAL; + const int opt_flags = (req_scope == kOptReqWin && !(flags & SOPT_GLOBAL)) ? 0 : + (req_scope == kOptReqGlobal) ? OPT_GLOBAL : OPT_LOCAL; WITH_SCRIPT_CONTEXT(channel_id, { - set_option_value_for(name.data, optval, opt_flags, type, to, err); + set_option_value_for(name.data, optval, opt_flags, req_scope, to, err); }); } diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 498638d606..5b1f61b9f6 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -26,8 +26,9 @@ # include "api/options.c.generated.h" #endif -static int validate_option_value_args(Dict(option) *opts, char *name, int *scope, int *opt_type, - void **from, char **filetype, Error *err) +static int validate_option_value_args(Dict(option) *opts, char *name, int *scope, + OptReqScope *req_scope, void **from, char **filetype, + Error *err) { #define HAS_KEY_X(d, v) HAS_KEY(d, option, v) if (HAS_KEY_X(opts, scope)) { @@ -42,14 +43,14 @@ static int validate_option_value_args(Dict(option) *opts, char *name, int *scope } } - *opt_type = SREQ_GLOBAL; + *req_scope = kOptReqGlobal; if (filetype != NULL && HAS_KEY_X(opts, filetype)) { *filetype = opts->filetype.data; } if (HAS_KEY_X(opts, win)) { - *opt_type = SREQ_WIN; + *req_scope = kOptReqWin; *from = find_window_by_handle(opts->win, err); if (ERROR_SET(err)) { return FAIL; @@ -58,7 +59,7 @@ static int validate_option_value_args(Dict(option) *opts, char *name, int *scope if (HAS_KEY_X(opts, buf)) { *scope = OPT_LOCAL; - *opt_type = SREQ_BUF; + *req_scope = kOptReqBuf; *from = find_buffer_by_handle(opts->buf, err); if (ERROR_SET(err)) { return FAIL; @@ -81,15 +82,15 @@ static int validate_option_value_args(Dict(option) *opts, char *name, int *scope return FAIL; }); - int flags = get_option_value_strict(name, NULL, NULL, 0, NULL); + int flags = get_option_attrs(name); if (flags == 0) { // hidden or unknown option api_set_error(err, kErrorTypeValidation, "Unknown option '%s'", name); - } else if (*opt_type & (SREQ_BUF | SREQ_WIN)) { + } else if (*req_scope == kOptReqBuf || *req_scope == kOptReqWin) { // if 'buf' or 'win' is passed, make sure the option supports it - int req_flags = *opt_type & SREQ_BUF ? SOPT_BUF : SOPT_WIN; + int req_flags = *req_scope == kOptReqBuf ? SOPT_BUF : SOPT_WIN; if (!(flags & req_flags)) { - char *tgt = *opt_type & SREQ_BUF ? "buf" : "win"; + char *tgt = *req_scope & kOptReqBuf ? "buf" : "win"; char *global = flags & SOPT_GLOBAL ? "global ": ""; char *req = flags & SOPT_BUF ? "buffer-local " : flags & SOPT_WIN ? "window-local " : ""; @@ -158,11 +159,11 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) OptVal value = NIL_OPTVAL; int scope = 0; - int opt_type = SREQ_GLOBAL; + OptReqScope req_scope = kOptReqGlobal; void *from = NULL; char *filetype = NULL; - if (!validate_option_value_args(opts, name.data, &scope, &opt_type, &from, &filetype, err)) { + if (!validate_option_value_args(opts, name.data, &scope, &req_scope, &from, &filetype, err)) { goto err; } @@ -179,7 +180,7 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) } bool hidden; - value = get_option_value_for(name.data, NULL, scope, &hidden, opt_type, from, err); + value = get_option_value_for(name.data, NULL, scope, &hidden, req_scope, from, err); if (ftbuf != NULL) { // restore curwin/curbuf and a few other things @@ -222,9 +223,9 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict( FUNC_API_SINCE(9) { int scope = 0; - int opt_type = SREQ_GLOBAL; + OptReqScope req_scope = kOptReqGlobal; void *to = NULL; - if (!validate_option_value_args(opts, name.data, &scope, &opt_type, &to, NULL, err)) { + if (!validate_option_value_args(opts, name.data, &scope, &req_scope, &to, NULL, err)) { return; } @@ -234,8 +235,8 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict( // - option is global or local to window (global-local) // // Then force scope to local since we don't want to change the global option - if (opt_type == SREQ_WIN && scope == 0) { - int flags = get_option_value_strict(name.data, NULL, NULL, opt_type, to); + if (req_scope == kOptReqWin && scope == 0) { + int flags = get_option_attrs(name.data); if (flags & SOPT_GLOBAL) { scope = OPT_LOCAL; } @@ -245,15 +246,15 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict( OptVal optval = object_as_optval(value, &error); // Handle invalid option value type. - if (error) { - // Don't use `name` in the error message here, because `name` can be any String. - VALIDATE_EXP(false, "value", "Integer/Boolean/String", api_typename(value.type), { - return; - }); - } + // Don't use `name` in the error message here, because `name` can be any String. + // No need to check if value type actually matches the types for the option, as set_option_value() + // already handles that. + VALIDATE_EXP(!error, "value", "valid option type", api_typename(value.type), { + return; + }); WITH_SCRIPT_CONTEXT(channel_id, { - set_option_value_for(name.data, optval, scope, opt_type, to, err); + set_option_value_for(name.data, optval, scope, req_scope, to, err); }); } @@ -308,30 +309,31 @@ Dictionary nvim_get_option_info2(String name, Dict(option) *opts, Error *err) FUNC_API_SINCE(11) { int scope = 0; - int opt_type = SREQ_GLOBAL; + OptReqScope req_scope = kOptReqGlobal; void *from = NULL; - if (!validate_option_value_args(opts, name.data, &scope, &opt_type, &from, NULL, err)) { + if (!validate_option_value_args(opts, name.data, &scope, &req_scope, &from, NULL, err)) { return (Dictionary)ARRAY_DICT_INIT; } - buf_T *buf = (opt_type == SREQ_BUF) ? (buf_T *)from : curbuf; - win_T *win = (opt_type == SREQ_WIN) ? (win_T *)from : curwin; + buf_T *buf = (req_scope == kOptReqBuf) ? (buf_T *)from : curbuf; + win_T *win = (req_scope == kOptReqWin) ? (win_T *)from : curwin; return get_vimoption(name, scope, buf, win, err); } /// Switch current context to get/set option value for window/buffer. /// -/// @param[out] ctx Current context. switchwin_T for window and aco_save_T for buffer. -/// @param[in] opt_type Option type. See SREQ_* in option_defs.h. -/// @param[in] from Target buffer/window. -/// @param[out] err Error message, if any. +/// @param[out] ctx Current context. switchwin_T for window and aco_save_T for buffer. +/// @param req_scope Requested option scope. See OptReqScope in option.h. +/// @param[in] from Target buffer/window. +/// @param[out] err Error message, if any. /// /// @return true if context was switched, false otherwise. -static bool switch_option_context(void *const ctx, int opt_type, void *const from, Error *err) +static bool switch_option_context(void *const ctx, OptReqScope req_scope, void *const from, + Error *err) { - switch (opt_type) { - case SREQ_WIN: { + switch (req_scope) { + case kOptReqWin: { win_T *const win = (win_T *)from; switchwin_T *const switchwin = (switchwin_T *)ctx; @@ -351,7 +353,7 @@ static bool switch_option_context(void *const ctx, int opt_type, void *const fro } return true; } - case SREQ_BUF: { + case kOptReqBuf: { buf_T *const buf = (buf_T *)from; aco_save_T *const aco = (aco_save_T *)ctx; @@ -361,51 +363,177 @@ static bool switch_option_context(void *const ctx, int opt_type, void *const fro aucmd_prepbuf(aco, buf); return true; } - case SREQ_GLOBAL: + case kOptReqGlobal: return false; - default: - abort(); // This should never happen. } + UNREACHABLE; } /// Restore context after getting/setting option for window/buffer. See switch_option_context() for /// params. -static void restore_option_context(void *const ctx, const int opt_type) +static void restore_option_context(void *const ctx, OptReqScope req_scope) { - switch (opt_type) { - case SREQ_WIN: + switch (req_scope) { + case kOptReqWin: restore_win_noblock((switchwin_T *)ctx, true); break; - case SREQ_BUF: + case kOptReqBuf: aucmd_restbuf((aco_save_T *)ctx); break; - case SREQ_GLOBAL: + case kOptReqGlobal: break; - default: - abort(); // This should never happen. } } +/// Get attributes for an option. +/// +/// @param name Option name. +/// +/// @return Option attributes. +/// 0 for hidden or unknown option. +/// See SOPT_* in option_defs.h for other flags. +int get_option_attrs(char *name) +{ + int opt_idx = findoption(name); + + if (opt_idx < 0) { + return 0; + } + + vimoption_T *opt = get_option(opt_idx); + + if (is_tty_option(opt->fullname)) { + return SOPT_STRING | SOPT_GLOBAL; + } + + // Hidden option + if (opt->var == NULL) { + return 0; + } + + int attrs = 0; + + if (opt->flags & P_BOOL) { + attrs |= SOPT_BOOL; + } else if (opt->flags & P_NUM) { + attrs |= SOPT_NUM; + } else if (opt->flags & P_STRING) { + attrs |= SOPT_STRING; + } + + if (opt->indir == PV_NONE || (opt->indir & PV_BOTH)) { + attrs |= SOPT_GLOBAL; + } + if (opt->indir & PV_WIN) { + attrs |= SOPT_WIN; + } else if (opt->indir & PV_BUF) { + attrs |= SOPT_BUF; + } + + return attrs; +} + +/// Check if option has a value in the requested scope. +/// +/// @param name Option name. +/// @param req_scope Requested option scope. See OptReqScope in option.h. +/// +/// @return true if option has a value in the requested scope, false otherwise. +static bool option_has_scope(char *name, OptReqScope req_scope) +{ + int opt_idx = findoption(name); + + if (opt_idx < 0) { + return false; + } + + vimoption_T *opt = get_option(opt_idx); + + // Hidden option. + if (opt->var == NULL) { + return false; + } + // TTY option. + if (is_tty_option(opt->fullname)) { + return req_scope == kOptReqGlobal; + } + + switch (req_scope) { + case kOptReqGlobal: + return opt->var != VAR_WIN; + case kOptReqBuf: + return opt->indir & PV_BUF; + case kOptReqWin: + return opt->indir & PV_WIN; + } + UNREACHABLE; +} + +/// Get the option value in the requested scope. +/// +/// @param name Option name. +/// @param req_scope Requested option scope. See OptReqScope in option.h. +/// @param[in] from Pointer to buffer or window for local option value. +/// @param[out] err Error message, if any. +/// +/// @return Option value in the requested scope. Returns a Nil option value if option is not found, +/// hidden or if it isn't present in the requested scope. (i.e. has no global, window-local or +/// buffer-local value depending on opt_scope). +OptVal get_option_value_strict(char *name, OptReqScope req_scope, void *from, Error *err) +{ + OptVal retv = NIL_OPTVAL; + + if (!option_has_scope(name, req_scope)) { + return retv; + } + if (get_tty_option(name, &retv.data.string.data)) { + retv.type = kOptValTypeString; + return retv; + } + + int opt_idx = findoption(name); + assert(opt_idx != 0); // option_has_scope() already verifies if option name is valid. + + vimoption_T *opt = get_option(opt_idx); + switchwin_T switchwin; + aco_save_T aco; + void *ctx = req_scope == kOptReqWin ? (void *)&switchwin + : (req_scope == kOptReqBuf ? (void *)&aco : NULL); + bool switched = switch_option_context(ctx, req_scope, from, err); + if (ERROR_SET(err)) { + return retv; + } + + char *varp = get_varp_scope(opt, req_scope == kOptReqGlobal ? OPT_GLOBAL : OPT_LOCAL); + retv = optval_from_varp(opt_idx, varp); + + if (switched) { + restore_option_context(ctx, req_scope); + } + + return retv; +} + /// Get option value for buffer / window. /// -/// @param[in] name Option name. -/// @param[out] flagsp Set to the option flags (P_xxxx) (if not NULL). -/// @param[in] scope Option scope (can be OPT_LOCAL, OPT_GLOBAL or a combination). -/// @param[out] hidden Whether option is hidden. -/// @param[in] opt_type Option type. See SREQ_* in option_defs.h. -/// @param[in] from Target buffer/window. -/// @param[out] err Error message, if any. +/// @param[in] name Option name. +/// @param[out] flagsp Set to the option flags (P_xxxx) (if not NULL). +/// @param[in] scope Option scope (can be OPT_LOCAL, OPT_GLOBAL or a combination). +/// @param[out] hidden Whether option is hidden. +/// @param req_scope Requested option scope. See OptReqScope in option.h. +/// @param[in] from Target buffer/window. +/// @param[out] err Error message, if any. /// /// @return Option value. Must be freed by caller. OptVal get_option_value_for(const char *const name, uint32_t *flagsp, int scope, bool *hidden, - const int opt_type, void *const from, Error *err) + const OptReqScope req_scope, void *const from, Error *err) { switchwin_T switchwin; aco_save_T aco; - void *ctx = opt_type == SREQ_WIN ? (void *)&switchwin - : (opt_type == SREQ_BUF ? (void *)&aco : NULL); + void *ctx = req_scope == kOptReqWin ? (void *)&switchwin + : (req_scope == kOptReqBuf ? (void *)&aco : NULL); - bool switched = switch_option_context(ctx, opt_type, from, err); + bool switched = switch_option_context(ctx, req_scope, from, err); if (ERROR_SET(err)) { return NIL_OPTVAL; } @@ -413,7 +541,7 @@ OptVal get_option_value_for(const char *const name, uint32_t *flagsp, int scope, OptVal retv = get_option_value(name, flagsp, scope, hidden); if (switched) { - restore_option_context(ctx, opt_type); + restore_option_context(ctx, req_scope); } return retv; @@ -421,21 +549,21 @@ OptVal get_option_value_for(const char *const name, uint32_t *flagsp, int scope, /// Set option value for buffer / window. /// -/// @param[in] name Option name. -/// @param[in] value Option value. -/// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both). -/// @param[in] opt_type Option type. See SREQ_* in option_defs.h. -/// @param[in] from Target buffer/window. -/// @param[out] err Error message, if any. +/// @param[in] name Option name. +/// @param[in] value Option value. +/// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both). +/// @param req_scope Requested option scope. See OptReqScope in option.h. +/// @param[in] from Target buffer/window. +/// @param[out] err Error message, if any. void set_option_value_for(const char *const name, OptVal value, const int opt_flags, - const int opt_type, void *const from, Error *err) + const OptReqScope req_scope, void *const from, Error *err) { switchwin_T switchwin; aco_save_T aco; - void *ctx = opt_type == SREQ_WIN ? (void *)&switchwin - : (opt_type == SREQ_BUF ? (void *)&aco : NULL); + void *ctx = req_scope == kOptReqWin ? (void *)&switchwin + : (req_scope == kOptReqBuf ? (void *)&aco : NULL); - bool switched = switch_option_context(ctx, opt_type, from, err); + bool switched = switch_option_context(ctx, req_scope, from, err); if (ERROR_SET(err)) { return; } @@ -446,6 +574,6 @@ void set_option_value_for(const char *const name, OptVal value, const int opt_fl } if (switched) { - restore_option_context(ctx, opt_type); + restore_option_context(ctx, req_scope); } } -- cgit From 5f03a1eaabfc8de2b3a9c666fcd604763f41e152 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Fri, 20 Oct 2023 15:10:33 +0200 Subject: build(lint): remove unnecessary clint.py rules Uncrustify is the source of truth where possible. Remove any redundant checks from clint.py. --- src/nvim/api/extmark.h | 4 ++-- src/nvim/api/private/helpers.h | 6 +++--- src/nvim/api/vim.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.h b/src/nvim/api/extmark.h index a7baad496f..7c300350e1 100644 --- a/src/nvim/api/extmark.h +++ b/src/nvim/api/extmark.h @@ -8,8 +8,8 @@ #include "nvim/map.h" #include "nvim/types.h" -EXTERN Map(String, int) namespace_ids INIT(= MAP_INIT); -EXTERN handle_T next_namespace_id INIT(= 1); +EXTERN Map(String, int) namespace_ids INIT( = MAP_INIT); +EXTERN handle_T next_namespace_id INIT( = 1); #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/extmark.h.generated.h" diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index e5ad30a10f..9cf4620acd 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -128,9 +128,9 @@ #define api_free_window(value) #define api_free_tabpage(value) -EXTERN PMap(int) buffer_handles INIT(= MAP_INIT); -EXTERN PMap(int) window_handles INIT(= MAP_INIT); -EXTERN PMap(int) tabpage_handles INIT(= MAP_INIT); +EXTERN PMap(int) buffer_handles INIT( = MAP_INIT); +EXTERN PMap(int) window_handles INIT( = MAP_INIT); +EXTERN PMap(int) tabpage_handles INIT( = MAP_INIT); #define handle_get_buffer(h) pmap_get(int)(&buffer_handles, (h)) #define handle_get_window(h) pmap_get(int)(&window_handles, (h)) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 6ce1f41e39..52022cba5d 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2197,8 +2197,8 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * } if (statuscol_lnum) { HlPriId line = { 0 }; - HlPriId cul = { 0 }; - HlPriId num = { 0 }; + HlPriId cul = { 0 }; + HlPriId num = { 0 }; linenr_T lnum = statuscol_lnum; int num_signs = buf_get_signattrs(wp->w_buffer, lnum, sattrs, &num, &line, &cul); decor_redraw_signs(wp->w_buffer, lnum - 1, &num_signs, sattrs, &num, &line, &cul); -- cgit From 684e93054b82c6b5b215db7d3ecbad803eb81f0e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 25 Oct 2023 09:59:02 +0800 Subject: fix(terminal): assign channel to terminal earlier (#25771) --- src/nvim/api/vim.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 52022cba5d..c3c619e206 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1034,9 +1034,12 @@ Integer nvim_open_term(Buffer buffer, DictionaryOf(LuaRef) opts, Error *err) topts.write_cb = term_write; topts.resize_cb = term_resize; topts.close_cb = term_close; - Terminal *term = terminal_open(buf, topts); - terminal_check_size(term); - chan->term = term; + channel_incref(chan); + terminal_open(&chan->term, buf, topts); + if (chan->term != NULL) { + terminal_check_size(chan->term); + } + channel_decref(chan); return (Integer)chan->id; } -- cgit From 0da27e9bdec14acf82731c4d5e0ad7d673697af7 Mon Sep 17 00:00:00 2001 From: Raphael Date: Sun, 29 Oct 2023 15:44:52 +0800 Subject: fix(api): load buffer first on nvim_buf_set_lines (#25823) Fix #22670 Fix #8659 --- src/nvim/api/buffer.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 64dddea5b8..86298efe08 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -359,6 +359,14 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ return; } + // loaded buffer first if it's not loaded + if (buf->b_ml.ml_mfp == NULL) { + if (!buf_ensure_loaded(buf)) { + api_set_error(err, kErrorTypeException, "Failed to load buffer"); + return; + } + } + bool oob = false; start = normalize_index(buf, start, true, &oob); end = normalize_index(buf, end, true, &oob); @@ -396,10 +404,6 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ goto end; } - if (!buf_ensure_loaded(buf)) { - goto end; - } - if (u_save_buf(buf, (linenr_T)(start - 1), (linenr_T)end) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to save undo information"); goto end; @@ -537,6 +541,14 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In return; } + // loaded buffer first if it's not loaded + if (buf->b_ml.ml_mfp == NULL) { + if (!buf_ensure_loaded(buf)) { + api_set_error(err, kErrorTypeException, "Failed to load buffer"); + return; + } + } + bool oob = false; // check range is ordered and everything! @@ -645,10 +657,6 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In goto end; } - if (!buf_ensure_loaded(buf)) { - goto end; - } - // Small note about undo states: unlike set_lines, we want to save the // undo state of one past the end_row, since end_row is inclusive. if (u_save_buf(buf, (linenr_T)start_row - 1, (linenr_T)end_row + 1) == FAIL) { -- cgit From 2dc9ceb99c018b15dcf0c443cad46efecccaf94e Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sun, 29 Oct 2023 09:02:32 +0100 Subject: docs: small fixes (#25585) Co-authored-by: tmummert Co-authored-by: parikshit adhikari --- src/nvim/api/buffer.c | 4 ++-- src/nvim/api/win_config.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 86298efe08..2c80f96953 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -359,7 +359,7 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ return; } - // loaded buffer first if it's not loaded + // load buffer first if it's not loaded if (buf->b_ml.ml_mfp == NULL) { if (!buf_ensure_loaded(buf)) { api_set_error(err, kErrorTypeException, "Failed to load buffer"); @@ -541,7 +541,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In return; } - // loaded buffer first if it's not loaded + // load buffer first if it's not loaded if (buf->b_ml.ml_mfp == NULL) { if (!buf_ensure_loaded(buf)) { api_set_error(err, kErrorTypeException, "Failed to load buffer"); diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 2fd30bc5a5..6f38989c96 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -135,7 +135,7 @@ /// - "solid": Adds padding by a single whitespace cell. /// - "shadow": A drop shadow effect by blending with the background. /// - If it is an array, it should have a length of eight or any divisor of -/// eight. The array will specifify the eight chars building up the border +/// eight. The array will specify the eight chars building up the border /// in a clockwise fashion starting with the top-left corner. As an /// example, the double box style could be specified as /// [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ]. -- cgit From e19cc9c9b715d8171f7940632b8855104b5290b6 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Sat, 14 Oct 2023 22:19:11 +0600 Subject: refactor(options)!: unify `set_option` and `set_string_option` While the interfaces for setting number and boolean options are now unified by #25394, there is still a separate `set_string_option` function that is used for setting a string option. This PR removes that function and merges it with set_option. BREAKING CHANGE: `v:option_old` is now the old global value for all global-local options, instead of just string global-local options. Local value for a global-local number/boolean option is now unset when the option is set (e.g. using `:set` or `nvim_set_option_value`) without a scope, which means they now behave the same way as string options. Ref: #25672 --- src/nvim/api/deprecated.c | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 31ba20f627..59b7fc18d6 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -681,21 +681,6 @@ static void set_option_to(uint64_t channel_id, void *to, OptReqScope req_scope, return; }); - if (value.type == kObjectTypeNil) { - if (req_scope == kOptReqGlobal) { - api_set_error(err, kErrorTypeException, "Cannot unset option '%s'", name.data); - return; - } else if (!(flags & SOPT_GLOBAL)) { - api_set_error(err, kErrorTypeException, - "Cannot unset option '%s' because it doesn't have a global value", - name.data); - return; - } else { - unset_global_local_option(name.data, to); - return; - } - } - bool error = false; OptVal optval = object_as_optval(value, &error); -- cgit From 4e6096a67fe9860994be38bcd155e7c47313205e Mon Sep 17 00:00:00 2001 From: George Harker Date: Tue, 31 Oct 2023 20:04:53 -0700 Subject: feat(server): allow embed with listen (#25709) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit connection from any channel or stdio will unblock remote_ui_wait_for_attach. Wait on stdio only if only —embed specified, if both —embed and —listen then wait on any channel. --- src/nvim/api/ui.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index e0b5e6ea57..b508a3ee94 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -126,18 +126,24 @@ void remote_ui_disconnect(uint64_t channel_id) xfree(ui); } -/// Wait until ui has connected on stdio channel. -void remote_ui_wait_for_attach(void) +/// Wait until ui has connected on stdio channel if only_stdio +/// is true, otherwise any channel. +void remote_ui_wait_for_attach(bool only_stdio) { - Channel *channel = find_channel(CHAN_STDIO); - if (!channel) { - // this function should only be called in --embed mode, stdio channel - // can be assumed. - abort(); - } + if (only_stdio) { + Channel *channel = find_channel(CHAN_STDIO); + if (!channel) { + // this function should only be called in --embed mode, stdio channel + // can be assumed. + abort(); + } - LOOP_PROCESS_EVENTS_UNTIL(&main_loop, channel->events, -1, - map_has(uint64_t, &connected_uis, CHAN_STDIO)); + LOOP_PROCESS_EVENTS_UNTIL(&main_loop, channel->events, -1, + map_has(uint64_t, &connected_uis, CHAN_STDIO)); + } else { + LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, -1, + ui_active()); + } } /// Activates UI events on the channel. -- cgit From 14c7bf391625d5f24096d3c06b48d955d78e9e5d Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Tue, 31 Oct 2023 23:53:52 +0100 Subject: refactor(extmarks): extmark_del() with MarkTreeIter --- src/nvim/api/extmark.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 14454b626e..0b372c57e5 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -862,7 +862,7 @@ Boolean nvim_buf_del_extmark(Buffer buffer, Integer ns_id, Integer id, Error *er return false; } - return extmark_del(buf, (uint32_t)ns_id, (uint32_t)id); + return extmark_del_id(buf, (uint32_t)ns_id, (uint32_t)id); } uint32_t src2ns(Integer *src_id) -- cgit From 68cb4a7405ea9f8841d1f25ee8997c49e77fa679 Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 3 Nov 2023 12:26:38 +0100 Subject: feat(extmarks): add "undo_restore" flag to opt out of undo-restoring It is a design goal of extmarks that they allow precise tracking of changes across undo/redo, including restore the exact positions after a do/undo or undo/redo cycle. However this behavior is not useful for all usecases. Many plugins won't keep marks around for long after text changes, but uses them more like a cache until some external source (like LSP semantic highlights) has fully updated to changed text and then will explicitly readjust/replace extmarks as needed. Add a "undo_restore" flag which is true by default (matches existing behavior) but can be set to false to opt-out of this behavior. Delete dead u_extmark_set() code. --- src/nvim/api/deprecated.c | 3 +-- src/nvim/api/extmark.c | 11 +++++++++-- src/nvim/api/keysets.h | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 59b7fc18d6..906edb7b44 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -172,8 +172,7 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A decor.virt_text_width = width; decor.priority = 0; - extmark_set(buf, ns_id, NULL, (int)line, 0, -1, -1, &decor, true, - false, kExtmarkNoUndo, NULL); + extmark_set(buf, ns_id, NULL, (int)line, 0, -1, -1, &decor, true, false, false, NULL); return src_id; } diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 0b372c57e5..3f1745df40 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -166,6 +166,10 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict PUT(dict, "end_right_gravity", BOOLEAN_OBJ(extmark->end_right_gravity)); } + if (extmark->no_undo) { + PUT(dict, "undo_restore", BOOLEAN_OBJ(false)); + } + const Decoration *decor = &extmark->decor; if (decor->hl_id) { PUT(dict, "hl_group", hl_group_name(decor->hl_id, hl_name)); @@ -519,6 +523,9 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// the extmark end position (if it exists) will be shifted /// in when new text is inserted (true for right, false /// for left). Defaults to false. +/// - undo_restore : Restore the exact position of the mark +/// if text around the mark was deleted and then restored by undo. +/// Defaults to true. /// - priority: a priority value for the highlight group or sign /// attribute. For example treesitter highlighting uses a /// value of 100. @@ -825,7 +832,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer extmark_set(buf, (uint32_t)ns_id, &id, (int)line, (colnr_T)col, line2, col2, has_decor ? &decor : NULL, right_gravity, end_right_gravity, - kExtmarkNoUndo, err); + !GET_BOOL_OR_TRUE(opts, set_extmark, undo_restore), err); if (ERROR_SET(err)) { goto error; } @@ -952,7 +959,7 @@ Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, In extmark_set(buf, ns, NULL, (int)line, (colnr_T)col_start, end_line, (colnr_T)col_end, - &decor, true, false, kExtmarkNoUndo, NULL); + &decor, true, false, false, NULL); return ns_id; } diff --git a/src/nvim/api/keysets.h b/src/nvim/api/keysets.h index 18f6d5368b..d435262ff3 100644 --- a/src/nvim/api/keysets.h +++ b/src/nvim/api/keysets.h @@ -48,6 +48,7 @@ typedef struct { String conceal; Boolean spell; Boolean ui_watched; + Boolean undo_restore; } Dict(set_extmark); typedef struct { -- cgit From 56627ca2423e9d6084f87f5bc4639f06d10ecf91 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Mon, 6 Nov 2023 12:42:40 -0600 Subject: feat(tui): use TermResponse event for OSC responses (#25868) When the terminal emulator sends an OSC sequence to Nvim (as a response to another OSC sequence that was first sent by Nvim), populate the OSC sequence in the v:termresponse variable and fire the TermResponse event. The escape sequence is also included in the "data" field of the autocommand callback when the autocommand is defined in Lua. This makes use of the already documented but unimplemented TermResponse event. This event exists in Vim but is only fired when Vim receives a primary device attributes response. Fixes: https://github.com/neovim/neovim/issues/25856 --- src/nvim/api/ui.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index b508a3ee94..99215f7b4f 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -16,6 +16,7 @@ #include "nvim/api/ui.h" #include "nvim/autocmd.h" #include "nvim/channel.h" +#include "nvim/eval.h" #include "nvim/event/loop.h" #include "nvim/event/wstream.h" #include "nvim/globals.h" @@ -524,6 +525,32 @@ void nvim_ui_pum_set_bounds(uint64_t channel_id, Float width, Float height, Floa ui->pum_pos = true; } +/// Tells Nvim when a terminal event has occurred. +/// +/// The following terminal events are supported: +/// +/// - "osc_response": The terminal sent a OSC response sequence to Nvim. The +/// payload is the received OSC sequence. +/// +/// @param channel_id +/// @param event Event name +/// @param payload Event payload +/// @param[out] err Error details, if any. +void nvim_ui_term_event(uint64_t channel_id, String event, Object value, Error *err) + FUNC_API_SINCE(12) FUNC_API_REMOTE_ONLY +{ + if (strequal("osc_response", event.data)) { + if (value.type != kObjectTypeString) { + api_set_error(err, kErrorTypeValidation, "osc_response must be a string"); + return; + } + + const String osc_response = value.data.string; + set_vim_var_string(VV_TERMRESPONSE, osc_response.data, (ptrdiff_t)osc_response.size); + apply_autocmds_group(EVENT_TERMRESPONSE, NULL, NULL, false, AUGROUP_ALL, NULL, NULL, &value); + } +} + static void flush_event(UIData *data) { if (data->cur_event) { -- cgit From 4e6f559b8c5f77924fdbe2e5abd9c6aa8efad13f Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Tue, 24 Oct 2023 13:32:00 +0200 Subject: feat(extmarks): add 'invalidate' property to extmarks Problem: No way to have extmarks automatically removed when the range it is attached to is deleted. Solution: Add new 'invalidate' property that will hide a mark when the entirety of its range is deleted. When "undo_restore" is set to false, delete the mark from the buffer instead. --- src/nvim/api/deprecated.c | 2 +- src/nvim/api/extmark.c | 23 ++++++++++++++++------- src/nvim/api/keysets.h | 1 + 3 files changed, 18 insertions(+), 8 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 906edb7b44..8edb6dbd4f 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -172,7 +172,7 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A decor.virt_text_width = width; decor.priority = 0; - extmark_set(buf, ns_id, NULL, (int)line, 0, -1, -1, &decor, true, false, false, NULL); + extmark_set(buf, ns_id, NULL, (int)line, 0, -1, -1, &decor, true, false, false, false, NULL); return src_id; } diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 3f1745df40..aeecab6bd0 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -170,6 +170,13 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict PUT(dict, "undo_restore", BOOLEAN_OBJ(false)); } + if (extmark->invalidate) { + PUT(dict, "invalidate", BOOLEAN_OBJ(true)); + } + if (extmark->invalid) { + PUT(dict, "invalid", BOOLEAN_OBJ(true)); + } + const Decoration *decor = &extmark->decor; if (decor->hl_id) { PUT(dict, "hl_group", hl_group_name(decor->hl_id, hl_name)); @@ -526,6 +533,9 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// - undo_restore : Restore the exact position of the mark /// if text around the mark was deleted and then restored by undo. /// Defaults to true. +/// - invalidate : boolean that indicates whether to hide the +/// extmark if the entirety of its range is deleted. If +/// "undo_restore" is false, the extmark is deleted instead. /// - priority: a priority value for the highlight group or sign /// attribute. For example treesitter highlighting uses a /// value of 100. @@ -759,8 +769,6 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer goto error; }); - bool end_right_gravity = opts->end_right_gravity; - size_t len = 0; if (!HAS_KEY(opts, set_extmark, spell)) { @@ -823,7 +831,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer // TODO(bfredl): synergize these two branches even more 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); + decor_push_ephemeral((int)line, (int)col, line2, col2, &decor, (uint64_t)ns_id, id); } else { if (opts->ephemeral) { api_set_error(err, kErrorTypeException, "not yet implemented"); @@ -831,8 +839,9 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } extmark_set(buf, (uint32_t)ns_id, &id, (int)line, (colnr_T)col, line2, col2, - has_decor ? &decor : NULL, right_gravity, end_right_gravity, - !GET_BOOL_OR_TRUE(opts, set_extmark, undo_restore), err); + has_decor ? &decor : NULL, right_gravity, opts->end_right_gravity, + !GET_BOOL_OR_TRUE(opts, set_extmark, undo_restore), + opts->invalidate, err); if (ERROR_SET(err)) { goto error; } @@ -959,7 +968,7 @@ Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, In extmark_set(buf, ns, NULL, (int)line, (colnr_T)col_start, end_line, (colnr_T)col_end, - &decor, true, false, false, NULL); + &decor, true, false, false, false, NULL); return ns_id; } @@ -1010,7 +1019,7 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, /// redrawn buffer. |nvim_buf_set_extmark()| can be called to add marks /// on a per-window or per-lines basis. Use the `ephemeral` key to only /// use the mark for the current screen redraw (the callback will be called -/// again for the next redraw ). +/// again for the next redraw). /// /// Note: this function should not be called often. Rather, the callbacks /// themselves can be used to throttle unneeded callbacks. the `on_start` diff --git a/src/nvim/api/keysets.h b/src/nvim/api/keysets.h index d435262ff3..0da2239847 100644 --- a/src/nvim/api/keysets.h +++ b/src/nvim/api/keysets.h @@ -32,6 +32,7 @@ typedef struct { Boolean virt_text_hide; Boolean hl_eol; String hl_mode; + Boolean invalidate; Boolean ephemeral; Integer priority; Boolean right_gravity; -- cgit From cd63a9addd6e1114c3524fa041ece560550cfe7b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 10 Nov 2023 08:39:21 +0800 Subject: refactor: change some xstrndup() and xstrnsave() to xmemdupz() (#25959) When the given length is exactly the number of bytes to copy, xmemdupz() makes the intention clearer. --- src/nvim/api/command.c | 2 +- src/nvim/api/private/helpers.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index f4c6f646eb..9d51f2a4dc 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -419,7 +419,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error VALIDATE_EXP(!string_iswhite(elem.data.string), "command arg", "non-whitespace", NULL, { goto end; }); - data_str = xstrndup(elem.data.string.data, elem.data.string.size); + data_str = string_to_cstr(elem.data.string); break; default: VALIDATE_EXP(false, "command arg", "valid type", api_typename(elem.type), { diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 9cf4620acd..8911e145e7 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -75,8 +75,6 @@ #define PUT_C(dict, k, v) \ kv_push_c(dict, ((KeyValuePair) { .key = cstr_as_string(k), .value = v })) -#define PUT_BOOL(dict, name, condition) PUT(dict, name, BOOLEAN_OBJ(condition)); - #define ADD(array, item) \ kv_push(array, item) -- cgit From e9b9a86cd5a555943b87f0ba40c4527561c3c124 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 11 Nov 2023 10:21:14 +0800 Subject: fix(context): don't crash on invalid arg to nvim_get_context (#25977) Note: The crash happens in the second test case when using uninitialized memory, and therefore doesn't happen with ASAN. --- src/nvim/api/private/converter.c | 4 +++- src/nvim/api/vim.c | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index 10152cb3c8..d9832abd76 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -261,7 +261,9 @@ Object vim_to_object(typval_T *obj) /// @param obj Object to convert from. /// @param tv Conversion result is placed here. On failure member v_type is /// set to VAR_UNKNOWN (no allocation was made for this variable). -/// returns true if conversion is successful, otherwise false. +/// @param err Error object. +/// +/// @returns true if conversion is successful, otherwise false. bool object_to_vim(Object obj, typval_T *tv, Error *err) { tv->v_type = VAR_UNKNOWN; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index c3c619e206..8446f5b383 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1402,7 +1402,7 @@ Dictionary nvim_get_context(Dict(context) *opts, Error *err) /// Sets the current editor state from the given |context| map. /// /// @param dict |Context| map. -Object nvim_load_context(Dictionary dict) +Object nvim_load_context(Dictionary dict, Error *err) FUNC_API_SINCE(6) { Context ctx = CONTEXT_INIT; @@ -1410,8 +1410,8 @@ Object nvim_load_context(Dictionary dict) int save_did_emsg = did_emsg; did_emsg = false; - ctx_from_dict(dict, &ctx); - if (!did_emsg) { + ctx_from_dict(dict, &ctx, err); + if (!ERROR_SET(err)) { ctx_restore(&ctx, kCtxAll); } -- cgit From 8e58d37f2e15ac8540377148e55ed08a039aadb6 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 11 Nov 2023 11:20:08 +0100 Subject: refactor: remove redundant casts --- src/nvim/api/vim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 8446f5b383..86e542a1c7 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -923,7 +923,7 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err) FUNC_API_SINCE(6) { try_start(); - buf_T *buf = buflist_new(NULL, NULL, (linenr_T)0, + buf_T *buf = buflist_new(NULL, NULL, 0, BLN_NOOPT | BLN_NEW | (listed ? BLN_LISTED : 0)); try_end(err); if (buf == NULL) { -- cgit From 592e4472da5f29edbddea3eb448e56b747044e67 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 11 Nov 2023 11:10:45 +0100 Subject: fix(PVS/V564): the '|' operator is applied to bool type value --- src/nvim/api/ui.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 99215f7b4f..d5bb474039 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -77,7 +77,7 @@ static void mpack_uint(char **buf, uint32_t val) static void mpack_bool(char **buf, bool val) { - mpack_w(buf, 0xc2 | val); + mpack_w(buf, 0xc2 | (val ? 1 : 0)); } static void mpack_array(char **buf, uint32_t len) -- cgit From 353a4be7e84fdc101318215bdcc8a7e780d737fe Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sun, 12 Nov 2023 13:13:58 +0100 Subject: build: remove PVS We already have an extensive suite of static analysis tools we use, which causes a fair bit of redundancy as we get duplicate warnings. PVS is also prone to give false warnings which creates a lot of work to identify and disable. --- src/nvim/api/autocmd.c | 3 --- src/nvim/api/buffer.c | 3 --- src/nvim/api/command.c | 3 --- src/nvim/api/deprecated.c | 3 --- src/nvim/api/extmark.c | 3 --- src/nvim/api/options.c | 3 --- src/nvim/api/private/converter.c | 3 --- src/nvim/api/private/dispatch.c | 3 --- src/nvim/api/private/helpers.c | 3 --- src/nvim/api/private/validate.c | 3 --- src/nvim/api/tabpage.c | 3 --- src/nvim/api/ui.c | 3 --- src/nvim/api/vim.c | 3 --- src/nvim/api/vimscript.c | 3 --- src/nvim/api/win_config.c | 3 --- src/nvim/api/window.c | 3 --- 16 files changed, 48 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index d0efb58cb6..c15095243d 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include #include diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 2c80f96953..0444deff40 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - // Some of this code was adapted from 'if_py_both.h' from the original // vim source diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 9d51f2a4dc..10d8b4c768 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include #include diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 8edb6dbd4f..8398a3a5b1 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include #include diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index aeecab6bd0..84b89a7428 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include #include diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 5b1f61b9f6..61debb70fe 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include #include diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index d9832abd76..1188b04bdc 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include #include diff --git a/src/nvim/api/private/dispatch.c b/src/nvim/api/private/dispatch.c index f427bba00e..53fcd148bd 100644 --- a/src/nvim/api/private/dispatch.c +++ b/src/nvim/api/private/dispatch.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include "nvim/api/private/defs.h" diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index eaee94786c..bbeaa452ba 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include #include diff --git a/src/nvim/api/private/validate.c b/src/nvim/api/private/validate.c index cede32f72c..17e9d081a6 100644 --- a/src/nvim/api/private/validate.c +++ b/src/nvim/api/private/validate.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include #include diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c index 21eb326c3b..d6bbff6747 100644 --- a/src/nvim/api/tabpage.c +++ b/src/nvim/api/tabpage.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index d5bb474039..3d013435f7 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include #include diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 86e542a1c7..1d5898c488 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include #include diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index b09e4d7d87..63c1f39fb7 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include #include diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 6f38989c96..83c8ba832c 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include #include diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 53095ab019..9a788e9ce4 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include #include -- cgit From 4f8941c1a5f1ef6caa410feeb52e343db22763ce Mon Sep 17 00:00:00 2001 From: dundargoc Date: Fri, 10 Nov 2023 12:23:42 +0100 Subject: refactor: replace manual header guards with #pragma once It is less error-prone than manually defining header guards. Pretty much all compilers support it even if it's not part of the C standard. --- src/nvim/api/autocmd.h | 4 +--- src/nvim/api/buffer.h | 4 +--- src/nvim/api/command.h | 4 +--- src/nvim/api/deprecated.h | 4 +--- src/nvim/api/extmark.h | 4 +--- src/nvim/api/keysets.h | 5 +---- src/nvim/api/options.h | 5 +---- src/nvim/api/private/converter.h | 5 +---- src/nvim/api/private/defs.h | 5 +---- src/nvim/api/private/dispatch.h | 5 +---- src/nvim/api/private/helpers.h | 5 +---- src/nvim/api/private/validate.h | 5 +---- src/nvim/api/tabpage.h | 4 +--- src/nvim/api/ui.h | 4 +--- src/nvim/api/ui_events.in.h | 4 +--- src/nvim/api/vim.h | 4 +--- src/nvim/api/vimscript.h | 4 +--- src/nvim/api/win_config.h | 4 +--- src/nvim/api/window.h | 4 +--- 19 files changed, 19 insertions(+), 64 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.h b/src/nvim/api/autocmd.h index 3273ca5759..8aefd45793 100644 --- a/src/nvim/api/autocmd.h +++ b/src/nvim/api/autocmd.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_AUTOCMD_H -#define NVIM_API_AUTOCMD_H +#pragma once #include @@ -9,4 +8,3 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/autocmd.h.generated.h" #endif -#endif // NVIM_API_AUTOCMD_H diff --git a/src/nvim/api/buffer.h b/src/nvim/api/buffer.h index db58239af8..0f18f5368e 100644 --- a/src/nvim/api/buffer.h +++ b/src/nvim/api/buffer.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_BUFFER_H -#define NVIM_API_BUFFER_H +#pragma once #include @@ -10,4 +9,3 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/buffer.h.generated.h" #endif -#endif // NVIM_API_BUFFER_H diff --git a/src/nvim/api/command.h b/src/nvim/api/command.h index f16bd0acde..78af5cbf64 100644 --- a/src/nvim/api/command.h +++ b/src/nvim/api/command.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_COMMAND_H -#define NVIM_API_COMMAND_H +#pragma once #include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" @@ -9,4 +8,3 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/command.h.generated.h" #endif -#endif // NVIM_API_COMMAND_H diff --git a/src/nvim/api/deprecated.h b/src/nvim/api/deprecated.h index 79095167e1..5541a4dac3 100644 --- a/src/nvim/api/deprecated.h +++ b/src/nvim/api/deprecated.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_DEPRECATED_H -#define NVIM_API_DEPRECATED_H +#pragma once #include @@ -8,4 +7,3 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/deprecated.h.generated.h" #endif -#endif // NVIM_API_DEPRECATED_H diff --git a/src/nvim/api/extmark.h b/src/nvim/api/extmark.h index 7c300350e1..88f1e9e8ad 100644 --- a/src/nvim/api/extmark.h +++ b/src/nvim/api/extmark.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_EXTMARK_H -#define NVIM_API_EXTMARK_H +#pragma once #include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" @@ -14,4 +13,3 @@ EXTERN handle_T next_namespace_id INIT( = 1); #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/extmark.h.generated.h" #endif -#endif // NVIM_API_EXTMARK_H diff --git a/src/nvim/api/keysets.h b/src/nvim/api/keysets.h index 0da2239847..e59eda5686 100644 --- a/src/nvim/api/keysets.h +++ b/src/nvim/api/keysets.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_KEYSETS_H -#define NVIM_API_KEYSETS_H +#pragma once #include "nvim/api/private/defs.h" @@ -314,5 +313,3 @@ typedef struct { typedef struct { Boolean output; } Dict(exec_opts); - -#endif // NVIM_API_KEYSETS_H diff --git a/src/nvim/api/options.h b/src/nvim/api/options.h index 7be72d3708..79aeead205 100644 --- a/src/nvim/api/options.h +++ b/src/nvim/api/options.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_OPTIONS_H -#define NVIM_API_OPTIONS_H +#pragma once #include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" @@ -8,5 +7,3 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/options.h.generated.h" #endif - -#endif // NVIM_API_OPTIONS_H diff --git a/src/nvim/api/private/converter.h b/src/nvim/api/private/converter.h index 28ae71983b..47e1d5a6bb 100644 --- a/src/nvim/api/private/converter.h +++ b/src/nvim/api/private/converter.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_PRIVATE_CONVERTER_H -#define NVIM_API_PRIVATE_CONVERTER_H +#pragma once #include "nvim/api/private/defs.h" #include "nvim/eval/typval_defs.h" @@ -7,5 +6,3 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/converter.h.generated.h" #endif - -#endif // NVIM_API_PRIVATE_CONVERTER_H diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index b467ce75a9..067592ed4e 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_PRIVATE_DEFS_H -#define NVIM_API_PRIVATE_DEFS_H +#pragma once #include #include @@ -139,5 +138,3 @@ typedef struct { } KeySetLink; typedef KeySetLink *(*FieldHashfn)(const char *str, size_t len); - -#endif // NVIM_API_PRIVATE_DEFS_H diff --git a/src/nvim/api/private/dispatch.h b/src/nvim/api/private/dispatch.h index 78fcf88d7b..49332bfecc 100644 --- a/src/nvim/api/private/dispatch.h +++ b/src/nvim/api/private/dispatch.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_PRIVATE_DISPATCH_H -#define NVIM_API_PRIVATE_DISPATCH_H +#pragma once #include #include @@ -30,5 +29,3 @@ extern const MsgpackRpcRequestHandler method_handlers[]; # include "api/private/dispatch_wrappers.h.generated.h" # include "keysets_defs.generated.h" #endif - -#endif // NVIM_API_PRIVATE_DISPATCH_H diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 8911e145e7..82c24b7c65 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_PRIVATE_HELPERS_H -#define NVIM_API_PRIVATE_HELPERS_H +#pragma once #include #include @@ -199,5 +198,3 @@ typedef struct { current_channel_id = save_channel_id; \ current_sctx = save_current_sctx; \ } while (0); - -#endif // NVIM_API_PRIVATE_HELPERS_H diff --git a/src/nvim/api/private/validate.h b/src/nvim/api/private/validate.h index 089b8d2f9c..29ca6242f3 100644 --- a/src/nvim/api/private/validate.h +++ b/src/nvim/api/private/validate.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_PRIVATE_VALIDATE_H -#define NVIM_API_PRIVATE_VALIDATE_H +#pragma once #include #include @@ -95,5 +94,3 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/validate.h.generated.h" #endif - -#endif // NVIM_API_PRIVATE_VALIDATE_H diff --git a/src/nvim/api/tabpage.h b/src/nvim/api/tabpage.h index 2689cf6ae6..b9357df10a 100644 --- a/src/nvim/api/tabpage.h +++ b/src/nvim/api/tabpage.h @@ -1,9 +1,7 @@ -#ifndef NVIM_API_TABPAGE_H -#define NVIM_API_TABPAGE_H +#pragma once #include "nvim/api/private/defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/tabpage.h.generated.h" #endif -#endif // NVIM_API_TABPAGE_H diff --git a/src/nvim/api/ui.h b/src/nvim/api/ui.h index b3fe0fa2bb..0101e5d31b 100644 --- a/src/nvim/api/ui.h +++ b/src/nvim/api/ui.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_UI_H -#define NVIM_API_UI_H +#pragma once #include @@ -11,4 +10,3 @@ # include "api/ui.h.generated.h" # include "ui_events_remote.h.generated.h" #endif -#endif // NVIM_API_UI_H diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 6ca5024a04..bda0c72423 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_UI_EVENTS_IN_H -#define NVIM_API_UI_EVENTS_IN_H +#pragma once // This file is not compiled, just parsed for definitions #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -170,4 +169,3 @@ void msg_history_clear(void) void error_exit(Integer status) FUNC_API_SINCE(12); -#endif // NVIM_API_UI_EVENTS_IN_H diff --git a/src/nvim/api/vim.h b/src/nvim/api/vim.h index c305749ba0..81cb563aaf 100644 --- a/src/nvim/api/vim.h +++ b/src/nvim/api/vim.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_VIM_H -#define NVIM_API_VIM_H +#pragma once #include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" @@ -7,4 +6,3 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/vim.h.generated.h" #endif -#endif // NVIM_API_VIM_H diff --git a/src/nvim/api/vimscript.h b/src/nvim/api/vimscript.h index 99ef43454b..ee056999ed 100644 --- a/src/nvim/api/vimscript.h +++ b/src/nvim/api/vimscript.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_VIMSCRIPT_H -#define NVIM_API_VIMSCRIPT_H +#pragma once #include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" @@ -7,4 +6,3 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/vimscript.h.generated.h" #endif -#endif // NVIM_API_VIMSCRIPT_H diff --git a/src/nvim/api/win_config.h b/src/nvim/api/win_config.h index 426a74fb3e..f9befa6806 100644 --- a/src/nvim/api/win_config.h +++ b/src/nvim/api/win_config.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_WIN_CONFIG_H -#define NVIM_API_WIN_CONFIG_H +#pragma once #include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" @@ -8,4 +7,3 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/win_config.h.generated.h" #endif -#endif // NVIM_API_WIN_CONFIG_H diff --git a/src/nvim/api/window.h b/src/nvim/api/window.h index 046d64c1a4..1a3da7be75 100644 --- a/src/nvim/api/window.h +++ b/src/nvim/api/window.h @@ -1,5 +1,4 @@ -#ifndef NVIM_API_WINDOW_H -#define NVIM_API_WINDOW_H +#pragma once #include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" @@ -7,4 +6,3 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/window.h.generated.h" #endif -#endif // NVIM_API_WINDOW_H -- cgit From ab102f188e86bdbfce1d4de2ef633092a906e8fe Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Mon, 6 Nov 2023 15:46:44 -0600 Subject: refactor: move background color detection into Lua --- src/nvim/api/ui.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 3d013435f7..a215317a83 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -348,15 +348,6 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e return; } - if (strequal(name.data, "term_background")) { - VALIDATE_T("term_background", kObjectTypeString, value.type, { - return; - }); - set_tty_background(value.data.string.data); - ui->term_background = string_to_cstr(value.data.string); - return; - } - if (strequal(name.data, "stdin_fd")) { VALIDATE_T("stdin_fd", kObjectTypeInteger, value.type, { return; -- cgit From 8d9789a0f3b748b75ac4ae1b8e43d27af40d49fe Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Tue, 7 Nov 2023 11:31:21 -0600 Subject: docs: deprecate the "term_background" UI field --- src/nvim/api/ui.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index a215317a83..e6d9035b0d 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -120,7 +120,6 @@ void remote_ui_disconnect(uint64_t channel_id) // Destroy `ui`. XFREE_CLEAR(ui->term_name); - XFREE_CLEAR(ui->term_background); xfree(ui); } -- cgit From b73a829837bbc05840ae00cbe514fb1786695614 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 14 Nov 2023 05:15:45 -0800 Subject: refactor: vim.ui.clipboard #26040 Problem: Platform-specific UI providers should live in `vim.ui.*`. #24164 Solution: - Move `vim.clipboard.osc52` module to `vim.ui.clipboard.osc52`. - TODO: move all of `clipboard.vim` to `vim.ui.clipboard`. ref #25872 --- src/nvim/api/ui.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index e6d9035b0d..c898925af8 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -512,7 +512,7 @@ void nvim_ui_pum_set_bounds(uint64_t channel_id, Float width, Float height, Floa ui->pum_pos = true; } -/// Tells Nvim when a terminal event has occurred. +/// Tells Nvim when a terminal event has occurred: sets |v:termresponse| and fires |TermResponse|. /// /// The following terminal events are supported: /// -- cgit From 326d46f690b383846f136f2a25523cffe2882f27 Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 16 Nov 2023 09:54:47 +0800 Subject: refactor: move some functions to winfloat.c (#26020) --- src/nvim/api/win_config.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 83c8ba832c..0e6daf6b95 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -25,6 +25,7 @@ #include "nvim/syntax.h" #include "nvim/ui.h" #include "nvim/window.h" +#include "nvim/winfloat.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/win_config.c.generated.h" -- cgit From bb4b4576e384c71890b4df4fa4f1ae76fad3a59d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 16 Nov 2023 10:55:54 +0800 Subject: refactor: iwyu (#26062) --- src/nvim/api/deprecated.c | 1 - src/nvim/api/options.c | 4 ++-- src/nvim/api/private/converter.c | 1 - src/nvim/api/ui.c | 1 + src/nvim/api/win_config.c | 1 - 5 files changed, 3 insertions(+), 5 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 8398a3a5b1..ff9f8ff18e 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 61debb70fe..b0053dbb34 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include "nvim/api/keysets.h" @@ -13,9 +12,10 @@ #include "nvim/buffer.h" #include "nvim/eval/window.h" #include "nvim/globals.h" +#include "nvim/macros.h" #include "nvim/memory.h" #include "nvim/option.h" -#include "nvim/types.h" +#include "nvim/option_vars.h" #include "nvim/vim.h" #include "nvim/window.h" diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index 1188b04bdc..6e6d054374 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -2,7 +2,6 @@ #include #include #include -#include #include "klib/kvec.h" #include "nvim/api/private/converter.h" diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index c898925af8..1483650739 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 0e6daf6b95..4b16e26103 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -1,5 +1,4 @@ #include -#include #include #include "klib/kvec.h" -- cgit From b4b7ca2d548a1cc1a2cd8c48e5c93478811bd275 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Thu, 16 Nov 2023 11:12:42 -0600 Subject: feat(tui): support DCS responses in TermResponse event (#26061) --- src/nvim/api/ui.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 1483650739..c1fc986029 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -513,12 +513,13 @@ void nvim_ui_pum_set_bounds(uint64_t channel_id, Float width, Float height, Floa ui->pum_pos = true; } -/// Tells Nvim when a terminal event has occurred: sets |v:termresponse| and fires |TermResponse|. +/// Tells Nvim when a terminal event has occurred /// /// The following terminal events are supported: /// -/// - "osc_response": The terminal sent a OSC response sequence to Nvim. The -/// payload is the received OSC sequence. +/// - "termresponse": The terminal sent an OSC or DCS response sequence to +/// Nvim. The payload is the received response. Sets +/// |v:termresponse| and fires |TermResponse|. /// /// @param channel_id /// @param event Event name @@ -527,14 +528,14 @@ void nvim_ui_pum_set_bounds(uint64_t channel_id, Float width, Float height, Floa void nvim_ui_term_event(uint64_t channel_id, String event, Object value, Error *err) FUNC_API_SINCE(12) FUNC_API_REMOTE_ONLY { - if (strequal("osc_response", event.data)) { + if (strequal("termresponse", event.data)) { if (value.type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, "osc_response must be a string"); + api_set_error(err, kErrorTypeValidation, "termresponse must be a string"); return; } - const String osc_response = value.data.string; - set_vim_var_string(VV_TERMRESPONSE, osc_response.data, (ptrdiff_t)osc_response.size); + const String termresponse = value.data.string; + set_vim_var_string(VV_TERMRESPONSE, termresponse.data, (ptrdiff_t)termresponse.size); apply_autocmds_group(EVENT_TERMRESPONSE, NULL, NULL, false, AUGROUP_ALL, NULL, NULL, &value); } } -- cgit From c4afb9788c4f139eb2e3b7aa4d6a6a20b67ba156 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Sat, 11 Nov 2023 00:52:50 +0100 Subject: refactor(sign): move legacy signs to extmarks Problem: The legacy signlist data structures and associated functions are redundant since the introduction of extmark signs. Solution: Store signs defined through the legacy commands in a hashmap, placed signs in the extmark tree. Replace signlist associated functions. Usage of the legacy sign commands should yield no change in behavior with the exception of: - "orphaned signs" are now always removed when the line it is placed on is deleted. This used to depend on the value of 'signcolumn'. - It is no longer possible to place multiple signs with the same identifier in a single group on multiple lines. This will now move the sign instead. Moreover, both signs placed through the legacy sign commands and through |nvim_buf_set_extmark()|: - Will show up in both |sign-place| and |nvim_buf_get_extmarks()|. - Are displayed by increasing sign identifier, left to right. Extmark signs used to be ordered decreasingly as opposed to legacy signs. --- src/nvim/api/extmark.c | 46 ++++++---------------------------------------- src/nvim/api/vim.c | 15 +++++++-------- 2 files changed, 13 insertions(+), 48 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 84b89a7428..efcdd0e7f7 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -22,6 +22,7 @@ #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/pos.h" +#include "nvim/sign.h" #include "nvim/strings.h" #include "nvim/vim.h" @@ -81,7 +82,7 @@ Dictionary nvim_get_namespaces(void) return retval; } -const char *describe_ns(NS ns_id) +const char *describe_ns(NS ns_id, const char *unknown) { String name; handle_T id; @@ -90,7 +91,7 @@ const char *describe_ns(NS ns_id) return name.data; } }) - return "(UNKNOWN PLUGIN)"; + return unknown; } // Is the Namespace in use? @@ -314,8 +315,8 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, return extmark_to_array(&extmark, false, details, hl_name); } -/// Gets |extmarks| in "traversal order" from a |charwise| region defined by -/// buffer positions (inclusive, 0-indexed |api-indexing|). +/// Gets |extmarks| (including |signs|) in "traversal order" from a |charwise| +/// region defined by buffer positions (inclusive, 0-indexed |api-indexing|). /// /// Region can be given as (row,col) tuples, or valid extmark ids (whose /// positions define the bounds). 0 and -1 are understood as (0,0) and (-1,-1) @@ -750,7 +751,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } if (HAS_KEY(opts, set_extmark, sign_text)) { - VALIDATE_S(init_sign_text(&decor.sign_text, opts->sign_text.data), + VALIDATE_S(init_sign_text(NULL, &decor.sign_text, opts->sign_text.data), "sign_text", "", { goto error; }); @@ -1150,41 +1151,6 @@ static bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, in }); } } -// adapted from sign.c:sign_define_init_text. -// TODO(lewis6991): Consider merging -static int init_sign_text(char **sign_text, char *text) -{ - char *s; - - char *endp = text + (int)strlen(text); - - // Count cells and check for non-printable chars - int cells = 0; - for (s = text; s < endp; s += utfc_ptr2len(s)) { - if (!vim_isprintc(utf_ptr2char(s))) { - break; - } - cells += utf_ptr2cells(s); - } - // Currently must be empty, one or two display cells - if (s != endp || cells > 2) { - return FAIL; - } - if (cells < 1) { - return OK; - } - - // Allocate one byte more if we need to pad up - // with a space. - size_t len = (size_t)(endp - text + ((cells == 1) ? 1 : 0)); - *sign_text = xstrnsave(text, len); - - if (cells == 1) { - STRCPY(*sign_text + len - 1, " "); - } - - return OK; -} VirtText parse_virt_text(Array chunks, Error *err, int *width) { diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 1d5898c488..88cbdbe1de 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2196,13 +2196,12 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * } } if (statuscol_lnum) { - HlPriId line = { 0 }; - HlPriId cul = { 0 }; - HlPriId num = { 0 }; + int line_id = 0; + int cul_id = 0; + int num_id = 0; linenr_T lnum = statuscol_lnum; - int num_signs = buf_get_signattrs(wp->w_buffer, lnum, sattrs, &num, &line, &cul); - decor_redraw_signs(wp->w_buffer, lnum - 1, &num_signs, sattrs, &num, &line, &cul); wp->w_scwidth = win_signcol_count(wp); + decor_redraw_signs(wp, wp->w_buffer, lnum - 1, sattrs, &line_id, &cul_id, &num_id); statuscol.sattrs = sattrs; statuscol.foldinfo = fold_info(wp, lnum); @@ -2215,9 +2214,9 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * statuscol.use_cul = lnum == wp->w_cursorline && (wp->w_p_culopt_flags & CULOPT_NBR); } - statuscol.sign_cul_id = statuscol.use_cul ? cul.hl_id : 0; - if (num.hl_id) { - stc_hl_id = num.hl_id; + statuscol.sign_cul_id = statuscol.use_cul ? cul_id : 0; + if (num_id) { + stc_hl_id = num_id; } else if (statuscol.use_cul) { stc_hl_id = HLF_CLN + 1; } else if (wp->w_p_rnu) { -- cgit From ec283e6b4ba85dcb61e97e089605e006e85cc273 Mon Sep 17 00:00:00 2001 From: bfredl Date: Sat, 18 Nov 2023 20:35:12 +0100 Subject: refactor(extmark): redundant ExtmarkInfo delenda est, use MTPair instead --- src/nvim/api/extmark.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index efcdd0e7f7..31fc01403a 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -142,40 +142,42 @@ Array virt_text_to_array(VirtText vt, bool hl_name) return chunks; } -static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict, bool hl_name) +static Array extmark_to_array(MTPair extmark, bool id, bool add_dict, bool hl_name) { + MTKey start = extmark.start; Array rv = ARRAY_DICT_INIT; if (id) { - ADD(rv, INTEGER_OBJ((Integer)extmark->mark_id)); + ADD(rv, INTEGER_OBJ((Integer)start.id)); } - ADD(rv, INTEGER_OBJ(extmark->row)); - ADD(rv, INTEGER_OBJ(extmark->col)); + ADD(rv, INTEGER_OBJ(start.pos.row)); + ADD(rv, INTEGER_OBJ(start.pos.col)); if (add_dict) { Dictionary dict = ARRAY_DICT_INIT; - PUT(dict, "ns_id", INTEGER_OBJ((Integer)extmark->ns_id)); + PUT(dict, "ns_id", INTEGER_OBJ((Integer)start.ns)); - PUT(dict, "right_gravity", BOOLEAN_OBJ(extmark->right_gravity)); + PUT(dict, "right_gravity", BOOLEAN_OBJ(mt_right(start))); - if (extmark->end_row >= 0) { - PUT(dict, "end_row", INTEGER_OBJ(extmark->end_row)); - PUT(dict, "end_col", INTEGER_OBJ(extmark->end_col)); - PUT(dict, "end_right_gravity", BOOLEAN_OBJ(extmark->end_right_gravity)); + if (extmark.end_pos.row >= 0) { + PUT(dict, "end_row", INTEGER_OBJ(extmark.end_pos.row)); + PUT(dict, "end_col", INTEGER_OBJ(extmark.end_pos.col)); + PUT(dict, "end_right_gravity", BOOLEAN_OBJ(extmark.end_right_gravity)); } - if (extmark->no_undo) { + if (mt_no_undo(start)) { PUT(dict, "undo_restore", BOOLEAN_OBJ(false)); } - if (extmark->invalidate) { + if (mt_invalidate(start)) { PUT(dict, "invalidate", BOOLEAN_OBJ(true)); } - if (extmark->invalid) { + if (mt_invalid(start)) { PUT(dict, "invalid", BOOLEAN_OBJ(true)); } - const Decoration *decor = &extmark->decor; + // pretend this is a pointer for a short while, Decoration will be factored away very soon + const Decoration decor[1] = { get_decor(start) }; if (decor->hl_id) { PUT(dict, "hl_group", hl_group_name(decor->hl_id, hl_name)); PUT(dict, "hl_eol", BOOLEAN_OBJ(decor->hl_eol)); @@ -308,11 +310,11 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, } } - ExtmarkInfo extmark = extmark_from_id(buf, (uint32_t)ns_id, (uint32_t)id); - if (extmark.row < 0) { + MTPair extmark = extmark_from_id(buf, (uint32_t)ns_id, (uint32_t)id); + if (extmark.start.pos.row < 0) { return rv; } - return extmark_to_array(&extmark, false, details, hl_name); + return extmark_to_array(extmark, false, details, hl_name); } /// Gets |extmarks| (including |signs|) in "traversal order" from a |charwise| @@ -432,7 +434,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e u_col, (int64_t)limit, reverse, type, opts->overlap); for (size_t i = 0; i < kv_size(marks); i++) { - ADD(rv, ARRAY_OBJ(extmark_to_array(&kv_A(marks, i), true, details, hl_name))); + ADD(rv, ARRAY_OBJ(extmark_to_array(kv_A(marks, i), true, details, hl_name))); } kv_destroy(marks); @@ -1121,13 +1123,13 @@ static bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, in }); } - ExtmarkInfo extmark = extmark_from_id(buf, (uint32_t)ns_id, (uint32_t)id); + MTPair extmark = extmark_from_id(buf, (uint32_t)ns_id, (uint32_t)id); - VALIDATE_INT((extmark.row >= 0), "mark id (not found)", id, { + VALIDATE_INT((extmark.start.pos.row >= 0), "mark id (not found)", id, { return false; }); - *row = extmark.row; - *col = extmark.col; + *row = extmark.start.pos.row; + *col = extmark.start.pos.col; return true; // Check if it is a position -- cgit From a6e3d93421ba13c407a96fac9cc01fa41ec7ad98 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Thu, 16 Nov 2023 10:59:11 +0100 Subject: refactor: enable formatting for ternaries This requires removing the "Inner expression should be aligned" rule from clint as it prevents essentially any formatting regarding ternary operators. --- src/nvim/api/command.c | 8 ++++---- src/nvim/api/deprecated.c | 5 +++-- src/nvim/api/options.c | 8 ++++---- src/nvim/api/vim.c | 11 ++++++----- 4 files changed, 17 insertions(+), 15 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 10d8b4c768..e1691bb910 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -379,8 +379,8 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error goto end; }); const char *fullname = IS_USER_CMDIDX(ea.cmdidx) - ? get_user_command_name(ea.useridx, ea.cmdidx) - : get_command_name(NULL, ea.cmdidx); + ? get_user_command_name(ea.useridx, ea.cmdidx) + : get_command_name(NULL, ea.cmdidx); VALIDATE(strncmp(fullname, cmdname, strlen(cmdname)) == 0, "Invalid command: \"%s\"", cmdname, { goto end; }); @@ -836,8 +836,8 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin offset += eap->arglens[i]; } // If there isn't an argument, make eap->arg point to end of cmdline. - eap->arg = argc > 0 ? eap->args[0] : - cmdline.items + cmdline.size - 1; // Subtract 1 to account for NUL + eap->arg = argc > 0 ? eap->args[0] + : cmdline.items + cmdline.size - 1; // Subtract 1 to account for NUL // Finally, make cmdlinep point to the cmdline string. *cmdlinep = cmdline.items; diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index ff9f8ff18e..849897b529 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -689,8 +689,9 @@ static void set_option_to(uint64_t channel_id, void *to, OptReqScope req_scope, // For global-win-local options -> setlocal // For win-local options -> setglobal and setlocal (opt_flags == 0) - const int opt_flags = (req_scope == kOptReqWin && !(flags & SOPT_GLOBAL)) ? 0 : - (req_scope == kOptReqGlobal) ? OPT_GLOBAL : OPT_LOCAL; + const int opt_flags = (req_scope == kOptReqWin && !(flags & SOPT_GLOBAL)) + ? 0 + : (req_scope == kOptReqGlobal) ? OPT_GLOBAL : OPT_LOCAL; WITH_SCRIPT_CONTEXT(channel_id, { set_option_value_for(name.data, optval, opt_flags, req_scope, to, err); diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index b0053dbb34..f1aa69f48b 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -88,9 +88,9 @@ static int validate_option_value_args(Dict(option) *opts, char *name, int *scope int req_flags = *req_scope == kOptReqBuf ? SOPT_BUF : SOPT_WIN; if (!(flags & req_flags)) { char *tgt = *req_scope & kOptReqBuf ? "buf" : "win"; - char *global = flags & SOPT_GLOBAL ? "global ": ""; - char *req = flags & SOPT_BUF ? "buffer-local " : - flags & SOPT_WIN ? "window-local " : ""; + char *global = flags & SOPT_GLOBAL ? "global " : ""; + char *req = flags & SOPT_BUF ? "buffer-local " + : flags & SOPT_WIN ? "window-local " : ""; api_set_error(err, kErrorTypeValidation, "'%s' cannot be passed for %s%soption '%s'", tgt, global, req, name); @@ -495,7 +495,7 @@ OptVal get_option_value_strict(char *name, OptReqScope req_scope, void *from, Er switchwin_T switchwin; aco_save_T aco; void *ctx = req_scope == kOptReqWin ? (void *)&switchwin - : (req_scope == kOptReqBuf ? (void *)&aco : NULL); + : (req_scope == kOptReqBuf ? (void *)&aco : NULL); bool switched = switch_option_context(ctx, req_scope, from, err); if (ERROR_SET(err)) { return retv; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 88cbdbe1de..27b48c0b28 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1301,9 +1301,9 @@ void nvim_subscribe(uint64_t channel_id, String event) void nvim_unsubscribe(uint64_t channel_id, String event) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY { - size_t length = (event.size < METHOD_MAXLEN ? - event.size : - METHOD_MAXLEN); + size_t length = (event.size < METHOD_MAXLEN + ? event.size + : METHOD_MAXLEN); char e[METHOD_MAXLEN + 1]; memcpy(e, event.data, length); e[length] = NUL; @@ -2235,8 +2235,9 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * maxwidth = (int)opts->maxwidth; } else { maxwidth = statuscol_lnum ? win_col_off(wp) - : (opts->use_tabline - || (!opts->use_winbar && global_stl_height() > 0)) ? Columns : wp->w_width; + : (opts->use_tabline + || (!opts->use_winbar + && global_stl_height() > 0)) ? Columns : wp->w_width; } char buf[MAXPATHL]; -- cgit From 0b38fe4dbb77c15ae6f5779174855acab25fc86c Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 8 Mar 2023 15:18:02 +0100 Subject: refactor(decorations): break up Decoration struct into smaller pieces Remove the monolithic Decoration struct. Before this change, each extmark could either represent just a hl_id + priority value as a inline decoration, or it would take a pointer to this monolitic 112 byte struct which has to be allocated. This change separates the decorations into two pieces: DecorSignHighlight for signs, highlights and simple set-flag decorations (like spell, ui-watched), and DecorVirtText for virtual text and lines. The main separation here is whether they are expected to allocate more memory. Currently this is not really true as sign text has to be an allocated string, but the plan is to get rid of this eventually (it can just be an array of two schar_T:s). Further refactors are expected to improve the representation of each decoration kind individually. The goal of this particular PR is to get things started by cutting the Gordian knot which was the monolithic struct Decoration. Now, each extmark can either contain chained indicies/pointers to these kinds of objects, or it can fit a subset of DecorSignHighlight inline. The point of this change is not only to make decorations smaller in memory. In fact, the main motivation is to later allow them to grow _larger_, but on a dynamic, on demand fashion. As a simple example, it would be possible to augment highlights to take a list of multiple `hl_group`:s, which then would trivially map to a chain of multiple DecorSignHighlight entries. One small feature improvement included with this refactor itself, is that the restriction that extmarks cannot be removed inside a decoration provider has been lifted. These are instead safely lifetime extended on a "to free" list until the current iteration of screen drawing is done. NB: flags is a mess. but DecorLevel is useless, this slightly less so --- src/nvim/api/deprecated.c | 22 ++-- src/nvim/api/extmark.c | 279 ++++++++++++++++++++++------------------------ 2 files changed, 144 insertions(+), 157 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 849897b529..b4aa6fe99e 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -154,21 +154,25 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A return 0; } - Decoration *existing = decor_find_virttext(buf, (int)line, ns_id); + DecorVirtText *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; + clear_virttext(&existing->data.virt_text); + existing->data.virt_text = virt_text; + existing->width = width; return src_id; } - Decoration decor = DECORATION_INIT; - decor.virt_text = virt_text; - decor.virt_text_width = width; - decor.priority = 0; + DecorVirtText *vt = xmalloc(sizeof *vt); + *vt = (DecorVirtText)DECOR_VIRT_TEXT_INIT; + vt->data.virt_text = virt_text; + vt->width = width; + vt->priority = 0; - extmark_set(buf, ns_id, NULL, (int)line, 0, -1, -1, &decor, true, false, false, false, NULL); + DecorInline decor = { .ext = true, .data.ext.vt = vt, .data.ext.sh_idx = DECOR_ID_INVALID }; + + extmark_set(buf, ns_id, NULL, (int)line, 0, -1, -1, decor, 0, true, + false, false, false, NULL); return src_id; } diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 31fc01403a..8a2cde8372 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -103,15 +103,6 @@ bool ns_initialized(uint32_t ns) return ns < (uint32_t)next_namespace_id; } -static Object hl_group_name(int hl_id, bool hl_name) -{ - if (hl_name) { - return CSTR_TO_OBJ(syn_id2name(hl_id)); - } else { - return INTEGER_OBJ(hl_id); - } -} - Array virt_text_to_array(VirtText vt, bool hl_name) { Array chunks = ARRAY_DICT_INIT; @@ -176,85 +167,9 @@ static Array extmark_to_array(MTPair extmark, bool id, bool add_dict, bool hl_na PUT(dict, "invalid", BOOLEAN_OBJ(true)); } - // pretend this is a pointer for a short while, Decoration will be factored away very soon - const Decoration decor[1] = { get_decor(start) }; - if (decor->hl_id) { - PUT(dict, "hl_group", hl_group_name(decor->hl_id, hl_name)); - PUT(dict, "hl_eol", BOOLEAN_OBJ(decor->hl_eol)); - } - if (decor->hl_mode) { - PUT(dict, "hl_mode", CSTR_TO_OBJ(hl_mode_str[decor->hl_mode])); - } - - if (kv_size(decor->virt_text)) { - Array chunks = virt_text_to_array(decor->virt_text, hl_name); - PUT(dict, "virt_text", ARRAY_OBJ(chunks)); - PUT(dict, "virt_text_hide", BOOLEAN_OBJ(decor->virt_text_hide)); - if (decor->virt_text_pos == kVTWinCol) { - PUT(dict, "virt_text_win_col", INTEGER_OBJ(decor->col)); - } - PUT(dict, "virt_text_pos", - CSTR_TO_OBJ(virt_text_pos_str[decor->virt_text_pos])); - } - - if (decor->ui_watched) { - PUT(dict, "ui_watched", BOOLEAN_OBJ(true)); - } - - if (kv_size(decor->virt_lines)) { - Array all_chunks = ARRAY_DICT_INIT; - bool virt_lines_leftcol = false; - for (size_t i = 0; i < kv_size(decor->virt_lines); i++) { - virt_lines_leftcol = kv_A(decor->virt_lines, i).left_col; - Array chunks = virt_text_to_array(kv_A(decor->virt_lines, i).line, hl_name); - ADD(all_chunks, ARRAY_OBJ(chunks)); - } - PUT(dict, "virt_lines", ARRAY_OBJ(all_chunks)); - PUT(dict, "virt_lines_above", BOOLEAN_OBJ(decor->virt_lines_above)); - PUT(dict, "virt_lines_leftcol", BOOLEAN_OBJ(virt_lines_leftcol)); - } - - if (decor->sign_text) { - PUT(dict, "sign_text", CSTR_TO_OBJ(decor->sign_text)); - } - - // uncrustify:off - - struct { char *name; const int val; } hls[] = { - { "sign_hl_group" , decor->sign_hl_id }, - { "number_hl_group" , decor->number_hl_id }, - { "line_hl_group" , decor->line_hl_id }, - { "cursorline_hl_group", decor->cursorline_hl_id }, - { NULL, 0 }, - }; - - // uncrustify:on - - for (int j = 0; hls[j].name; j++) { - if (hls[j].val) { - PUT(dict, hls[j].name, hl_group_name(hls[j].val, hl_name)); - } - } - - if (decor->sign_text - || decor->hl_id - || kv_size(decor->virt_text) - || decor->ui_watched) { - PUT(dict, "priority", INTEGER_OBJ(decor->priority)); - } - - if (decor->conceal) { - String name = cstr_to_string((char *)&decor->conceal_char); - PUT(dict, "conceal", STRING_OBJ(name)); - } - - if (decor->spell != kNone) { - PUT(dict, "spell", BOOLEAN_OBJ(decor->spell == kTrue)); - } + decor_to_dict_legacy(&dict, mt_decor(start), hl_name); - if (dict.size) { - ADD(rv, DICTIONARY_OBJ(dict)); - } + ADD(rv, DICTIONARY_OBJ(dict)); } return rv; @@ -581,8 +496,14 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer Dict(set_extmark) *opts, Error *err) FUNC_API_SINCE(7) { - Decoration decor = DECORATION_INIT; - bool has_decor = false; + DecorHighlightInline hl = DECOR_HIGHLIGHT_INLINE_INIT; + // TODO(bfredl): in principle signs with max one (1) hl group and max 4 bytes of text. + // should be a candidate for inlining as well. + DecorSignHighlight sign = DECOR_SIGN_HIGHLIGHT_INIT; + DecorVirtText virt_text = DECOR_VIRT_TEXT_INIT; + DecorVirtText virt_lines = DECOR_VIRT_LINES_INIT; + bool has_hl = false; + String conceal_char_large = STRING_INIT; buf_T *buf = find_buffer_by_handle(buffer, err); if (!buf) { @@ -643,11 +564,11 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer Object *opt; int *dest; } hls[] = { - { "hl_group" , &opts->hl_group , &decor.hl_id }, - { "sign_hl_group" , &opts->sign_hl_group , &decor.sign_hl_id }, - { "number_hl_group" , &opts->number_hl_group , &decor.number_hl_id }, - { "line_hl_group" , &opts->line_hl_group , &decor.line_hl_id }, - { "cursorline_hl_group", &opts->cursorline_hl_group, &decor.cursorline_hl_id }, + { "hl_group" , &opts->hl_group , &hl.hl_id }, + { "sign_hl_group" , &opts->sign_hl_group , &sign.hl_id }, + { "number_hl_group" , &opts->number_hl_group , &sign.number_hl_id }, + { "line_hl_group" , &opts->line_hl_group , &sign.line_hl_id }, + { "cursorline_hl_group", &opts->cursorline_hl_group, &sign.cursorline_hl_id }, { NULL, NULL, NULL }, }; @@ -655,26 +576,33 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer for (int j = 0; hls[j].name && hls[j].dest; j++) { if (hls[j].opt->type != kObjectTypeNil) { + if (j > 0) { + sign.flags |= kSHIsSign; + } else { + has_hl = true; + } *hls[j].dest = object_to_hl_id(*hls[j].opt, hls[j].name, err); if (ERROR_SET(err)) { goto error; } - has_decor = true; } } if (HAS_KEY(opts, set_extmark, conceal)) { + hl.flags |= kSHConceal; + has_hl = true; String c = opts->conceal; - decor.conceal = true; - if (c.size) { - decor.conceal_char = utf_ptr2char(c.data); + if (c.size > 0) { + if (c.size <= 4) { + memcpy(hl.conceal_char, c.data, c.size + (c.size < 4 ? 1 : 0)); + } else { + conceal_char_large = c; + } } - has_decor = true; } 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; + virt_text.data.virt_text = parse_virt_text(opts->virt_text, err, &virt_text.width); if (ERROR_SET(err)) { goto error; } @@ -683,13 +611,13 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer 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; + virt_text.pos = kVPosEndOfLine; } else if (strequal("overlay", str.data)) { - decor.virt_text_pos = kVTOverlay; + virt_text.pos = kVPosOverlay; } else if (strequal("right_align", str.data)) { - decor.virt_text_pos = kVTRightAlign; + virt_text.pos = kVPosRightAlign; } else if (strequal("inline", str.data)) { - decor.virt_text_pos = kVTInline; + virt_text.pos = kVPosInline; } else { VALIDATE_S(false, "virt_text_pos", str.data, { goto error; @@ -698,26 +626,26 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } if (HAS_KEY(opts, set_extmark, virt_text_win_col)) { - decor.col = (int)opts->virt_text_win_col; - decor.virt_text_pos = kVTWinCol; + virt_text.col = (int)opts->virt_text_win_col; + virt_text.pos = kVPosWinCol; } - decor.hl_eol = opts->hl_eol; - decor.virt_text_hide = opts->virt_text_hide; + hl.flags |= opts->hl_eol ? kSHHlEol : 0; + virt_text.flags |= opts->virt_text_hide ? kVTHide : 0; if (HAS_KEY(opts, set_extmark, hl_mode)) { String str = opts->hl_mode; if (strequal("replace", str.data)) { - decor.hl_mode = kHlModeReplace; + virt_text.hl_mode = kHlModeReplace; } else if (strequal("combine", str.data)) { - decor.hl_mode = kHlModeCombine; + virt_text.hl_mode = kHlModeCombine; } else if (strequal("blend", str.data)) { - if (decor.virt_text_pos == kVTInline) { + if (virt_text.pos == kVPosInline) { VALIDATE(false, "%s", "cannot use 'blend' hl_mode with inline virtual text", { goto error; }); } - decor.hl_mode = kHlModeBlend; + virt_text.hl_mode = kHlModeBlend; } else { VALIDATE_S(false, "hl_mode", str.data, { goto error; @@ -735,29 +663,32 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer }); int dummig; VirtText jtem = parse_virt_text(a.items[j].data.array, err, &dummig); - kv_push(decor.virt_lines, ((struct virt_line){ jtem, virt_lines_leftcol })); + kv_push(virt_lines.data.virt_lines, ((struct virt_line){ jtem, virt_lines_leftcol })); if (ERROR_SET(err)) { goto error; } - has_decor = true; } } - decor.virt_lines_above = opts->virt_lines_above; + virt_lines.flags |= opts->virt_lines_above ? kVTLinesAbove : 0; if (HAS_KEY(opts, set_extmark, priority)) { VALIDATE_RANGE((opts->priority >= 0 && opts->priority <= UINT16_MAX), "priority", { goto error; }); - decor.priority = (DecorPriority)opts->priority; + hl.priority = (DecorPriority)opts->priority; + sign.priority = (DecorPriority)opts->priority; + virt_text.priority = (DecorPriority)opts->priority; + virt_lines.priority = (DecorPriority)opts->priority; } if (HAS_KEY(opts, set_extmark, sign_text)) { - VALIDATE_S(init_sign_text(NULL, &decor.sign_text, opts->sign_text.data), + sign.text.ptr = NULL; + VALIDATE_S(init_sign_text(NULL, &sign.text.ptr, opts->sign_text.data), "sign_text", "", { goto error; }); - has_decor = true; + sign.flags |= kSHIsSign; } bool right_gravity = GET_BOOL_OR_TRUE(opts, set_extmark, right_gravity); @@ -771,16 +702,18 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer size_t len = 0; - if (!HAS_KEY(opts, set_extmark, spell)) { - decor.spell = kNone; - } else { - decor.spell = opts->spell ? kTrue : kFalse; - has_decor = true; + if (HAS_KEY(opts, set_extmark, spell)) { + hl.flags |= (opts->spell) ? kSHSpellOn : kSHSpellOff; + has_hl = true; } - decor.ui_watched = opts->ui_watched; - if (decor.ui_watched) { - has_decor = true; + if (opts->ui_watched) { + hl.flags |= kSHUIWatched; + if (virt_text.pos == kVPosOverlay) { + // TODO(bfredl): in a revised interface this should be the default. + hl.flags |= kSHUIWatchedOverlay; + } + has_hl = true; } VALIDATE_RANGE((line >= 0), "line", { @@ -829,28 +762,90 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer col2 = 0; } - // TODO(bfredl): synergize these two branches even more if (opts->ephemeral && decor_state.win && decor_state.win->w_buffer == buf) { - decor_push_ephemeral((int)line, (int)col, line2, col2, &decor, (uint64_t)ns_id, id); + int r = (int)line; + int c = (int)col; + if (line2 == -1) { + line2 = r; + col2 = c; + } + + if (kv_size(virt_text.data.virt_text)) { + decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_text, NULL), true); + } + if (kv_size(virt_lines.data.virt_lines)) { + decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_lines, NULL), true); + } + if (has_hl) { + DecorSignHighlight sh = decor_sh_from_inline(hl, conceal_char_large); + decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, (uint32_t)ns_id, id); + } + if (sign.flags & kSHIsSign) { + decor_range_add_sh(&decor_state, r, c, line2, col2, &sign, true, (uint32_t)ns_id, id); + } } else { if (opts->ephemeral) { api_set_error(err, kErrorTypeException, "not yet implemented"); goto error; } + uint16_t decor_flags = 0; + + DecorVirtText *decor_alloc = NULL; + if (kv_size(virt_text.data.virt_text)) { + decor_alloc = decor_put_vt(virt_text, decor_alloc); + if (virt_text.pos == kVPosInline) { + decor_flags |= MT_FLAG_DECOR_VIRT_TEXT_INLINE; + } + } + if (kv_size(virt_lines.data.virt_lines)) { + decor_alloc = decor_put_vt(virt_lines, decor_alloc); + decor_flags |= MT_FLAG_DECOR_VIRT_LINES; + } + + uint32_t decor_indexed = DECOR_ID_INVALID; + if (sign.flags & kSHIsSign) { + decor_indexed = decor_put_sh(sign); + if (sign.text.ptr != NULL) { + decor_flags |= MT_FLAG_DECOR_SIGNTEXT; + } + if (sign.number_hl_id || sign.line_hl_id || sign.cursorline_hl_id) { + decor_flags |= MT_FLAG_DECOR_SIGNHL; + } + } + + DecorInline decor = DECOR_INLINE_INIT; + if (decor_alloc || decor_indexed != DECOR_ID_INVALID || conceal_char_large.size) { + if (has_hl) { + DecorSignHighlight sh = decor_sh_from_inline(hl, conceal_char_large); + sh.next = decor_indexed; + decor_indexed = decor_put_sh(sh); + } + decor.ext = true; + decor.data.ext = (DecorExt){ .sh_idx = decor_indexed, .vt = decor_alloc }; + } else { + decor.data.hl = hl; + } + + if (has_hl) { + decor_flags |= MT_FLAG_DECOR_HL; + } + extmark_set(buf, (uint32_t)ns_id, &id, (int)line, (colnr_T)col, line2, col2, - has_decor ? &decor : NULL, right_gravity, opts->end_right_gravity, + decor, decor_flags, right_gravity, opts->end_right_gravity, !GET_BOOL_OR_TRUE(opts, set_extmark, undo_restore), opts->invalidate, err); if (ERROR_SET(err)) { - goto error; + decor_free(decor); + return 0; } } return (Integer)id; error: - decor_clear(&decor); + clear_virttext(&virt_text.data.virt_text); + clear_virtlines(&virt_lines.data.virt_lines); return 0; } @@ -873,11 +868,6 @@ Boolean nvim_buf_del_extmark(Buffer buffer, Integer ns_id, Integer id, Error *er return false; }); - if (decor_state.running_on_lines) { - api_set_error(err, kErrorTypeValidation, "Cannot remove extmarks during on_line callbacks"); - return false; - } - return extmark_del_id(buf, (uint32_t)ns_id, (uint32_t)id); } @@ -962,13 +952,11 @@ Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, In end_line++; } - Decoration decor = DECORATION_INIT; - decor.hl_id = hl_id; + DecorInline decor = DECOR_INLINE_INIT; + decor.data.hl.hl_id = hl_id; - extmark_set(buf, ns, NULL, - (int)line, (colnr_T)col_start, - end_line, (colnr_T)col_end, - &decor, true, false, false, false, NULL); + extmark_set(buf, ns, NULL, (int)line, (colnr_T)col_start, end_line, (colnr_T)col_end, + decor, MT_FLAG_DECOR_HL, true, false, false, false, NULL); return ns_id; } @@ -997,11 +985,6 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, return; }); - if (decor_state.running_on_lines) { - api_set_error(err, kErrorTypeValidation, "Cannot remove extmarks during on_line callbacks"); - return; - } - if (line_end < 0 || line_end > MAXLNUM) { line_end = MAXLNUM; } -- cgit From a827003e3052c6d9ee7bdb71518182e9bd76317d Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 25 Nov 2023 11:32:32 +0100 Subject: build: rework IWYU mapping files Create mapping to most of the C spec and some POSIX specific functions. This is more robust than relying files shipped with IWYU. --- src/nvim/api/deprecated.c | 2 +- src/nvim/api/extmark.c | 3 +-- src/nvim/api/win_config.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index b4aa6fe99e..9ea0de4b89 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -13,6 +13,7 @@ #include "nvim/api/vimscript.h" #include "nvim/buffer_defs.h" #include "nvim/decoration.h" +#include "nvim/decoration_defs.h" #include "nvim/extmark.h" #include "nvim/globals.h" #include "nvim/highlight.h" @@ -21,7 +22,6 @@ #include "nvim/memory.h" #include "nvim/option.h" #include "nvim/pos.h" -#include "nvim/types.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/deprecated.c.generated.h" diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 8a2cde8372..d2e387f478 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -13,6 +13,7 @@ #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/decoration.h" +#include "nvim/decoration_defs.h" #include "nvim/decoration_provider.h" #include "nvim/drawscreen.h" #include "nvim/extmark.h" @@ -23,8 +24,6 @@ #include "nvim/memory.h" #include "nvim/pos.h" #include "nvim/sign.h" -#include "nvim/strings.h" -#include "nvim/vim.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/extmark.c.generated.h" diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 4b16e26103..a35ad57d8f 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -11,8 +11,8 @@ #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/decoration.h" +#include "nvim/decoration_defs.h" #include "nvim/drawscreen.h" -#include "nvim/extmark_defs.h" #include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/highlight_group.h" -- cgit From 6361806aa28edca55ad3316a58bc3e936df9c0eb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 26 Nov 2023 22:58:52 +0800 Subject: refactor: move garray_T to garray_defs.h (#26227) --- src/nvim/api/deprecated.c | 1 - src/nvim/api/extmark.c | 1 - src/nvim/api/win_config.c | 1 - 3 files changed, 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 9ea0de4b89..47d3e1146c 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -13,7 +13,6 @@ #include "nvim/api/vimscript.h" #include "nvim/buffer_defs.h" #include "nvim/decoration.h" -#include "nvim/decoration_defs.h" #include "nvim/extmark.h" #include "nvim/globals.h" #include "nvim/highlight.h" diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index d2e387f478..5112d2474d 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -13,7 +13,6 @@ #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/decoration.h" -#include "nvim/decoration_defs.h" #include "nvim/decoration_provider.h" #include "nvim/drawscreen.h" #include "nvim/extmark.h" diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index a35ad57d8f..de26c1255c 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -11,7 +11,6 @@ #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/decoration.h" -#include "nvim/decoration_defs.h" #include "nvim/drawscreen.h" #include "nvim/globals.h" #include "nvim/grid.h" -- cgit From 7e2387f41be7cd8304fe48bfa089f2bea155dd5a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 Nov 2023 08:34:06 +0800 Subject: build(clint): more precise check for "defs" headers (#26236) --- src/nvim/api/deprecated.h | 4 ++-- src/nvim/api/private/converter.h | 4 ++-- src/nvim/api/tabpage.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/deprecated.h b/src/nvim/api/deprecated.h index 5541a4dac3..e20d8304e0 100644 --- a/src/nvim/api/deprecated.h +++ b/src/nvim/api/deprecated.h @@ -1,8 +1,8 @@ #pragma once -#include +#include // IWYU pragma: keep -#include "nvim/api/private/defs.h" +#include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/deprecated.h.generated.h" diff --git a/src/nvim/api/private/converter.h b/src/nvim/api/private/converter.h index 47e1d5a6bb..fc82abf332 100644 --- a/src/nvim/api/private/converter.h +++ b/src/nvim/api/private/converter.h @@ -1,7 +1,7 @@ #pragma once -#include "nvim/api/private/defs.h" -#include "nvim/eval/typval_defs.h" +#include "nvim/api/private/defs.h" // IWYU pragma: keep +#include "nvim/eval/typval_defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/converter.h.generated.h" diff --git a/src/nvim/api/tabpage.h b/src/nvim/api/tabpage.h index b9357df10a..2f19845bd9 100644 --- a/src/nvim/api/tabpage.h +++ b/src/nvim/api/tabpage.h @@ -1,6 +1,6 @@ #pragma once -#include "nvim/api/private/defs.h" +#include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/tabpage.h.generated.h" -- cgit From 09541d514dd18bf86f673d3784d406236fcbdad8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 Nov 2023 09:51:26 +0800 Subject: build(IWYU): replace public-to-public mappings with pragmas (#26237) --- src/nvim/api/ui.c | 1 - src/nvim/api/vim.c | 1 - 2 files changed, 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index c1fc986029..52165420b2 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -26,7 +26,6 @@ #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/msgpack_rpc/channel.h" -#include "nvim/msgpack_rpc/channel_defs.h" #include "nvim/msgpack_rpc/helpers.h" #include "nvim/option.h" #include "nvim/types.h" diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 27b48c0b28..b4e9af491f 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -48,7 +48,6 @@ #include "nvim/message.h" #include "nvim/move.h" #include "nvim/msgpack_rpc/channel.h" -#include "nvim/msgpack_rpc/channel_defs.h" #include "nvim/msgpack_rpc/unpacker.h" #include "nvim/ops.h" #include "nvim/option.h" -- cgit From 574d25642fc9ca65b396633aeab6e2d32778b642 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 Nov 2023 17:21:58 +0800 Subject: refactor: move Arena and ArenaMem to memory_defs.h (#26240) --- src/nvim/api/autocmd.c | 2 +- src/nvim/api/autocmd.h | 4 ++-- src/nvim/api/buffer.h | 5 +++-- src/nvim/api/command.c | 3 +-- src/nvim/api/command.h | 6 +++--- src/nvim/api/extmark.c | 2 +- src/nvim/api/extmark.h | 6 ++++-- src/nvim/api/options.c | 1 - src/nvim/api/options.h | 6 ++++-- src/nvim/api/ui.h | 6 ++++-- src/nvim/api/vim.c | 2 +- src/nvim/api/vim.h | 4 +++- src/nvim/api/vimscript.h | 4 +++- src/nvim/api/win_config.c | 4 ++-- src/nvim/api/win_config.h | 5 +++-- src/nvim/api/window.h | 2 +- 16 files changed, 36 insertions(+), 26 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index c15095243d..15a76cb8b0 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -6,7 +7,6 @@ #include #include "klib/kvec.h" -#include "lauxlib.h" #include "nvim/api/autocmd.h" #include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" diff --git a/src/nvim/api/autocmd.h b/src/nvim/api/autocmd.h index 8aefd45793..c2ba59734f 100644 --- a/src/nvim/api/autocmd.h +++ b/src/nvim/api/autocmd.h @@ -1,9 +1,9 @@ #pragma once -#include +#include // IWYU pragma: keep #include "nvim/api/keysets.h" -#include "nvim/api/private/defs.h" +#include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/autocmd.h.generated.h" diff --git a/src/nvim/api/buffer.h b/src/nvim/api/buffer.h index 0f18f5368e..927afe61d0 100644 --- a/src/nvim/api/buffer.h +++ b/src/nvim/api/buffer.h @@ -1,9 +1,10 @@ #pragma once -#include +#include // IWYU pragma: keep +#include // IWYU pragma: keep #include "nvim/api/keysets.h" -#include "nvim/api/private/defs.h" +#include "nvim/api/private/defs.h" // IWYU pragma: keep #include "nvim/buffer_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index e1691bb910..5e46797ca4 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -1,10 +1,10 @@ #include +#include #include #include #include #include "klib/kvec.h" -#include "lauxlib.h" #include "nvim/api/command.h" #include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" @@ -15,7 +15,6 @@ #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/cmdexpand_defs.h" -#include "nvim/decoration.h" #include "nvim/ex_cmds.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" diff --git a/src/nvim/api/command.h b/src/nvim/api/command.h index 78af5cbf64..7f8c35f89a 100644 --- a/src/nvim/api/command.h +++ b/src/nvim/api/command.h @@ -1,9 +1,9 @@ #pragma once +#include // IWYU pragma: keep + #include "nvim/api/keysets.h" -#include "nvim/api/private/defs.h" -#include "nvim/decoration.h" -#include "nvim/ex_cmds.h" +#include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/command.h.generated.h" diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 5112d2474d..28fcf7dd0f 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -1,10 +1,10 @@ #include +#include #include #include #include #include "klib/kvec.h" -#include "lauxlib.h" #include "nvim/api/extmark.h" #include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" diff --git a/src/nvim/api/extmark.h b/src/nvim/api/extmark.h index 88f1e9e8ad..d41a9828be 100644 --- a/src/nvim/api/extmark.h +++ b/src/nvim/api/extmark.h @@ -1,8 +1,10 @@ #pragma once +#include // IWYU pragma: keep + #include "nvim/api/keysets.h" -#include "nvim/api/private/defs.h" -#include "nvim/decoration.h" +#include "nvim/api/private/defs.h" // IWYU pragma: keep +#include "nvim/decoration_defs.h" // IWYU pragma: keep #include "nvim/macros.h" #include "nvim/map.h" #include "nvim/types.h" diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index f1aa69f48b..4cd5359cab 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -1,5 +1,4 @@ #include -#include #include #include diff --git a/src/nvim/api/options.h b/src/nvim/api/options.h index 79aeead205..2a7385eb56 100644 --- a/src/nvim/api/options.h +++ b/src/nvim/api/options.h @@ -1,8 +1,10 @@ #pragma once +#include // IWYU pragma: keep + #include "nvim/api/keysets.h" -#include "nvim/api/private/defs.h" -#include "nvim/option.h" +#include "nvim/api/private/defs.h" // IWYU pragma: keep +#include "nvim/option_defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/options.h.generated.h" diff --git a/src/nvim/api/ui.h b/src/nvim/api/ui.h index 0101e5d31b..ecfbb2d9f6 100644 --- a/src/nvim/api/ui.h +++ b/src/nvim/api/ui.h @@ -1,8 +1,10 @@ #pragma once -#include +#include // IWYU pragma: keep -#include "nvim/api/private/defs.h" +#include "nvim/api/private/defs.h" // IWYU pragma: keep +#include "nvim/grid_defs.h" // IWYU pragma: keep +#include "nvim/highlight_defs.h" // IWYU pragma: keep #include "nvim/map.h" #include "nvim/ui.h" diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index b4e9af491f..7279cb9b1a 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -8,7 +9,6 @@ #include #include "klib/kvec.h" -#include "lauxlib.h" #include "nvim/api/buffer.h" #include "nvim/api/deprecated.h" #include "nvim/api/keysets.h" diff --git a/src/nvim/api/vim.h b/src/nvim/api/vim.h index 81cb563aaf..eb165f285f 100644 --- a/src/nvim/api/vim.h +++ b/src/nvim/api/vim.h @@ -1,7 +1,9 @@ #pragma once +#include // IWYU pragma: keep + #include "nvim/api/keysets.h" -#include "nvim/api/private/defs.h" +#include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/vim.h.generated.h" diff --git a/src/nvim/api/vimscript.h b/src/nvim/api/vimscript.h index ee056999ed..d782f63aec 100644 --- a/src/nvim/api/vimscript.h +++ b/src/nvim/api/vimscript.h @@ -1,7 +1,9 @@ #pragma once +#include // IWYU pragma: keep + #include "nvim/api/keysets.h" -#include "nvim/api/private/defs.h" +#include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/vimscript.h.generated.h" diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index de26c1255c..8b9f73ae87 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -255,8 +255,8 @@ void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err) } } -Dictionary config_put_bordertext(Dictionary config, FloatConfig *fconfig, - BorderTextType bordertext_type) +static Dictionary config_put_bordertext(Dictionary config, FloatConfig *fconfig, + BorderTextType bordertext_type) { VirtText vt; AlignTextPos align; diff --git a/src/nvim/api/win_config.h b/src/nvim/api/win_config.h index f9befa6806..36f0e2bcf7 100644 --- a/src/nvim/api/win_config.h +++ b/src/nvim/api/win_config.h @@ -1,8 +1,9 @@ #pragma once +#include // IWYU pragma: keep + #include "nvim/api/keysets.h" -#include "nvim/api/private/defs.h" -#include "nvim/buffer_defs.h" +#include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/win_config.h.generated.h" diff --git a/src/nvim/api/window.h b/src/nvim/api/window.h index 1a3da7be75..0255193ac7 100644 --- a/src/nvim/api/window.h +++ b/src/nvim/api/window.h @@ -1,7 +1,7 @@ #pragma once #include "nvim/api/keysets.h" -#include "nvim/api/private/defs.h" +#include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/window.h.generated.h" -- cgit From acf525287950277e7b83794184e3df5dcfdecc48 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 Nov 2023 18:37:35 +0800 Subject: refactor: remove vim.h from more headers (#26244) --- src/nvim/api/private/helpers.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 82c24b7c65..56ca9b2057 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -2,11 +2,13 @@ #include #include +#include #include "klib/kvec.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/decoration.h" +#include "nvim/eval/typval_defs.h" #include "nvim/ex_eval_defs.h" #include "nvim/getchar.h" #include "nvim/gettext.h" @@ -14,7 +16,7 @@ #include "nvim/macros.h" #include "nvim/map.h" #include "nvim/memory.h" -#include "nvim/vim.h" +#include "nvim/message.h" #define OBJECT_OBJ(o) o -- cgit From 38a20dd89f91c45ec8589bf1c50d50732882d38a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 Nov 2023 20:58:37 +0800 Subject: build(IWYU): replace most private mappings with pragmas (#26247) --- src/nvim/api/private/helpers.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index bbeaa452ba..828362c10e 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1,10 +1,10 @@ #include -#include #include #include #include #include #include +#include #include #include #include @@ -17,6 +17,7 @@ #include "nvim/ascii.h" #include "nvim/buffer_defs.h" #include "nvim/eval/typval.h" +#include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" #include "nvim/ex_eval.h" #include "nvim/garray.h" -- cgit From 8b428ca8b79ebb7b36c3e403ff3bcb6924a635a6 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 16:00:21 +0100 Subject: build(IWYU): fix includes for func_attr.h --- src/nvim/api/autocmd.c | 1 + src/nvim/api/buffer.c | 1 + src/nvim/api/command.c | 1 + src/nvim/api/deprecated.c | 1 + src/nvim/api/extmark.c | 1 + src/nvim/api/options.c | 1 + src/nvim/api/private/converter.c | 1 + src/nvim/api/private/helpers.c | 1 + src/nvim/api/tabpage.c | 1 + src/nvim/api/ui.c | 1 + src/nvim/api/vim.c | 1 + src/nvim/api/vimscript.c | 1 + src/nvim/api/win_config.c | 1 + src/nvim/api/window.c | 1 + 14 files changed, 14 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 15a76cb8b0..ab33bc6801 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -16,6 +16,7 @@ #include "nvim/buffer.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds_defs.h" +#include "nvim/func_attr.h" #include "nvim/globals.h" #include "nvim/lua/executor.h" #include "nvim/memory.h" diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 0444deff40..5a9ddaae41 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -24,6 +24,7 @@ #include "nvim/drawscreen.h" #include "nvim/ex_cmds.h" #include "nvim/extmark.h" +#include "nvim/func_attr.h" #include "nvim/globals.h" #include "nvim/lua/executor.h" #include "nvim/mapping.h" diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 5e46797ca4..4af475d400 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -18,6 +18,7 @@ #include "nvim/ex_cmds.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" +#include "nvim/func_attr.h" #include "nvim/garray.h" #include "nvim/globals.h" #include "nvim/lua/executor.h" diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 47d3e1146c..b57cf80c9f 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -14,6 +14,7 @@ #include "nvim/buffer_defs.h" #include "nvim/decoration.h" #include "nvim/extmark.h" +#include "nvim/func_attr.h" #include "nvim/globals.h" #include "nvim/highlight.h" #include "nvim/highlight_group.h" diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 28fcf7dd0f..b7bc57e52c 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -16,6 +16,7 @@ #include "nvim/decoration_provider.h" #include "nvim/drawscreen.h" #include "nvim/extmark.h" +#include "nvim/func_attr.h" #include "nvim/highlight_group.h" #include "nvim/marktree.h" #include "nvim/mbyte.h" diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 4cd5359cab..f151a635ab 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -10,6 +10,7 @@ #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/eval/window.h" +#include "nvim/func_attr.h" #include "nvim/globals.h" #include "nvim/macros.h" #include "nvim/memory.h" diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index 6e6d054374..228172fd28 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -11,6 +11,7 @@ #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" +#include "nvim/func_attr.h" #include "nvim/lua/executor.h" #include "nvim/memory.h" #include "nvim/types.h" diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 828362c10e..fac23dfaaa 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -20,6 +20,7 @@ #include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" #include "nvim/ex_eval.h" +#include "nvim/func_attr.h" #include "nvim/garray.h" #include "nvim/globals.h" #include "nvim/highlight_group.h" diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c index d6bbff6747..c854a22477 100644 --- a/src/nvim/api/tabpage.c +++ b/src/nvim/api/tabpage.c @@ -6,6 +6,7 @@ #include "nvim/api/tabpage.h" #include "nvim/api/vim.h" #include "nvim/buffer_defs.h" +#include "nvim/func_attr.h" #include "nvim/globals.h" #include "nvim/memory.h" #include "nvim/window.h" diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 52165420b2..7366e24703 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -17,6 +17,7 @@ #include "nvim/eval.h" #include "nvim/event/loop.h" #include "nvim/event/wstream.h" +#include "nvim/func_attr.h" #include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/highlight.h" diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 7279cb9b1a..2823319b06 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -31,6 +31,7 @@ #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" #include "nvim/fold.h" +#include "nvim/func_attr.h" #include "nvim/getchar.h" #include "nvim/globals.h" #include "nvim/grid.h" diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 63c1f39fb7..b68eba1005 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -15,6 +15,7 @@ #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" #include "nvim/ex_docmd.h" +#include "nvim/func_attr.h" #include "nvim/garray.h" #include "nvim/globals.h" #include "nvim/memory.h" diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 8b9f73ae87..72a1c952b0 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -12,6 +12,7 @@ #include "nvim/buffer_defs.h" #include "nvim/decoration.h" #include "nvim/drawscreen.h" +#include "nvim/func_attr.h" #include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/highlight_group.h" diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 9a788e9ce4..08cd6f881f 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -14,6 +14,7 @@ #include "nvim/drawscreen.h" #include "nvim/eval/window.h" #include "nvim/ex_docmd.h" +#include "nvim/func_attr.h" #include "nvim/gettext.h" #include "nvim/globals.h" #include "nvim/lua/executor.h" -- cgit From f4aedbae4cb1f206f5b7c6142697b71dd473059b Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 18:39:38 +0100 Subject: build(IWYU): fix includes for undo_defs.h --- src/nvim/api/buffer.c | 2 +- src/nvim/api/command.c | 2 +- src/nvim/api/deprecated.c | 2 +- src/nvim/api/extmark.c | 2 +- src/nvim/api/private/helpers.c | 2 +- src/nvim/api/vim.c | 2 +- src/nvim/api/win_config.c | 2 +- src/nvim/api/window.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 5a9ddaae41..6bf0aeb4a7 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -33,7 +33,7 @@ #include "nvim/memory.h" #include "nvim/move.h" #include "nvim/ops.h" -#include "nvim/pos.h" +#include "nvim/pos_defs.h" #include "nvim/types.h" #include "nvim/undo.h" #include "nvim/vim.h" diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 4af475d400..e44e4052ca 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -26,7 +26,7 @@ #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/ops.h" -#include "nvim/pos.h" +#include "nvim/pos_defs.h" #include "nvim/regexp.h" #include "nvim/strings.h" #include "nvim/types.h" diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index b57cf80c9f..cac7d1ded9 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -21,7 +21,7 @@ #include "nvim/lua/executor.h" #include "nvim/memory.h" #include "nvim/option.h" -#include "nvim/pos.h" +#include "nvim/pos_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/deprecated.c.generated.h" diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index b7bc57e52c..98074da139 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -22,7 +22,7 @@ #include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/memory.h" -#include "nvim/pos.h" +#include "nvim/pos_defs.h" #include "nvim/sign.h" #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index fac23dfaaa..33defa63ef 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -31,7 +31,7 @@ #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/msgpack_rpc/helpers.h" -#include "nvim/pos.h" +#include "nvim/pos_defs.h" #include "nvim/types.h" #include "nvim/ui.h" #include "nvim/version.h" diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 2823319b06..5a206471fa 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -58,7 +58,7 @@ #include "nvim/os/os_defs.h" #include "nvim/os/process.h" #include "nvim/popupmenu.h" -#include "nvim/pos.h" +#include "nvim/pos_defs.h" #include "nvim/runtime.h" #include "nvim/sign.h" #include "nvim/state.h" diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 72a1c952b0..bec369b907 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -20,7 +20,7 @@ #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/option.h" -#include "nvim/pos.h" +#include "nvim/pos_defs.h" #include "nvim/syntax.h" #include "nvim/ui.h" #include "nvim/window.h" diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 08cd6f881f..1fb7eaba95 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -22,7 +22,7 @@ #include "nvim/message.h" #include "nvim/move.h" #include "nvim/plines.h" -#include "nvim/pos.h" +#include "nvim/pos_defs.h" #include "nvim/types.h" #include "nvim/window.h" -- cgit From e38a05369293293b5b510b1b0014fcc2e7cb87f4 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 18:46:03 +0100 Subject: build(IWYU): export generated headers --- src/nvim/api/autocmd.c | 1 + src/nvim/api/extmark.c | 1 + src/nvim/api/options.c | 1 + src/nvim/api/private/dispatch.h | 2 +- src/nvim/api/ui.h | 2 +- src/nvim/api/win_config.c | 1 + src/nvim/api/window.c | 1 + 7 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index ab33bc6801..d2475150f7 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -10,6 +10,7 @@ #include "nvim/api/autocmd.h" #include "nvim/api/keysets.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/autocmd.h" diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 98074da139..a05d75e3e6 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -8,6 +8,7 @@ #include "nvim/api/extmark.h" #include "nvim/api/keysets.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" diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index f151a635ab..6b9d3d1130 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -5,6 +5,7 @@ #include "nvim/api/keysets.h" #include "nvim/api/options.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/autocmd.h" diff --git a/src/nvim/api/private/dispatch.h b/src/nvim/api/private/dispatch.h index 49332bfecc..0a651ebd1c 100644 --- a/src/nvim/api/private/dispatch.h +++ b/src/nvim/api/private/dispatch.h @@ -26,6 +26,6 @@ extern const MsgpackRpcRequestHandler method_handlers[]; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/dispatch.h.generated.h" -# include "api/private/dispatch_wrappers.h.generated.h" +# include "api/private/dispatch_wrappers.h.generated.h" // IWYU pragma: export # include "keysets_defs.generated.h" #endif diff --git a/src/nvim/api/ui.h b/src/nvim/api/ui.h index ecfbb2d9f6..3d9152e0a4 100644 --- a/src/nvim/api/ui.h +++ b/src/nvim/api/ui.h @@ -10,5 +10,5 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/ui.h.generated.h" -# include "ui_events_remote.h.generated.h" +# include "ui_events_remote.h.generated.h" // IWYU pragma: export #endif diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index bec369b907..ee9e75f183 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -5,6 +5,7 @@ #include "nvim/api/extmark.h" #include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" +#include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" #include "nvim/api/win_config.h" #include "nvim/ascii.h" diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 1fb7eaba95..44c1c5595c 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -5,6 +5,7 @@ #include "nvim/api/keysets.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/api/window.h" -- cgit From e3f735ef101d670555f44226614a5c3557053b1f Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 20:13:32 +0100 Subject: refactor: fix includes for api/autocmd.h --- src/nvim/api/autocmd.c | 2 +- src/nvim/api/autocmd.h | 2 +- src/nvim/api/buffer.c | 2 +- src/nvim/api/buffer.h | 2 +- src/nvim/api/command.c | 2 +- src/nvim/api/command.h | 2 +- src/nvim/api/deprecated.c | 2 +- src/nvim/api/extmark.c | 2 +- src/nvim/api/extmark.h | 2 +- src/nvim/api/keysets.h | 315 -------------------------------------------- src/nvim/api/keysets_defs.h | 315 ++++++++++++++++++++++++++++++++++++++++++++ src/nvim/api/options.c | 2 +- src/nvim/api/options.h | 2 +- src/nvim/api/vim.c | 2 +- src/nvim/api/vim.h | 2 +- src/nvim/api/vimscript.c | 2 +- src/nvim/api/vimscript.h | 2 +- src/nvim/api/win_config.c | 2 +- src/nvim/api/win_config.h | 2 +- src/nvim/api/window.c | 2 +- src/nvim/api/window.h | 2 +- 21 files changed, 334 insertions(+), 334 deletions(-) delete mode 100644 src/nvim/api/keysets.h create mode 100644 src/nvim/api/keysets_defs.h (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index d2475150f7..96d330f92b 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -8,7 +8,7 @@ #include "klib/kvec.h" #include "nvim/api/autocmd.h" -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" diff --git a/src/nvim/api/autocmd.h b/src/nvim/api/autocmd.h index c2ba59734f..4ab3ddb943 100644 --- a/src/nvim/api/autocmd.h +++ b/src/nvim/api/autocmd.h @@ -2,7 +2,7 @@ #include // IWYU pragma: keep -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" // IWYU pragma: keep #include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 6bf0aeb4a7..ec667a8953 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -10,7 +10,7 @@ #include "klib/kvec.h" #include "lua.h" #include "nvim/api/buffer.h" -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/api/private/validate.h" diff --git a/src/nvim/api/buffer.h b/src/nvim/api/buffer.h index 927afe61d0..557cf8db0c 100644 --- a/src/nvim/api/buffer.h +++ b/src/nvim/api/buffer.h @@ -3,7 +3,7 @@ #include // IWYU pragma: keep #include // IWYU pragma: keep -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/defs.h" // IWYU pragma: keep #include "nvim/buffer_defs.h" diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index e44e4052ca..2d3bc26e62 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -6,7 +6,7 @@ #include "klib/kvec.h" #include "nvim/api/command.h" -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" diff --git a/src/nvim/api/command.h b/src/nvim/api/command.h index 7f8c35f89a..95f0e05993 100644 --- a/src/nvim/api/command.h +++ b/src/nvim/api/command.h @@ -2,7 +2,7 @@ #include // IWYU pragma: keep -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index cac7d1ded9..2ec11236d7 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -5,7 +5,7 @@ #include "nvim/api/buffer.h" #include "nvim/api/deprecated.h" #include "nvim/api/extmark.h" -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/options.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index a05d75e3e6..9a4dfe6788 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -6,7 +6,7 @@ #include "klib/kvec.h" #include "nvim/api/extmark.h" -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" diff --git a/src/nvim/api/extmark.h b/src/nvim/api/extmark.h index d41a9828be..0a28be98c5 100644 --- a/src/nvim/api/extmark.h +++ b/src/nvim/api/extmark.h @@ -2,7 +2,7 @@ #include // IWYU pragma: keep -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/defs.h" // IWYU pragma: keep #include "nvim/decoration_defs.h" // IWYU pragma: keep #include "nvim/macros.h" diff --git a/src/nvim/api/keysets.h b/src/nvim/api/keysets.h deleted file mode 100644 index e59eda5686..0000000000 --- a/src/nvim/api/keysets.h +++ /dev/null @@ -1,315 +0,0 @@ -#pragma once - -#include "nvim/api/private/defs.h" - -typedef struct { - OptionalKeys is_set__context_; - Array types; -} Dict(context); - -typedef struct { - OptionalKeys is_set__set_decoration_provider_; - LuaRef on_start; - LuaRef on_buf; - LuaRef on_win; - LuaRef on_line; - LuaRef on_end; - LuaRef _on_hl_def; - LuaRef _on_spell_nav; -} Dict(set_decoration_provider); - -typedef struct { - OptionalKeys is_set__set_extmark_; - Integer id; - Integer end_line; - Integer end_row; - Integer end_col; - Object hl_group; - Array virt_text; - String virt_text_pos; - Integer virt_text_win_col; - Boolean virt_text_hide; - Boolean hl_eol; - String hl_mode; - Boolean invalidate; - Boolean ephemeral; - Integer priority; - Boolean right_gravity; - Boolean end_right_gravity; - Array virt_lines; - Boolean virt_lines_above; - Boolean virt_lines_leftcol; - Boolean strict; - String sign_text; - Object sign_hl_group; - Object number_hl_group; - Object line_hl_group; - Object cursorline_hl_group; - String conceal; - Boolean spell; - Boolean ui_watched; - Boolean undo_restore; -} Dict(set_extmark); - -typedef struct { - OptionalKeys is_set__get_extmarks_; - Integer limit; - Boolean details; - Boolean hl_name; - Boolean overlap; - String type; -} Dict(get_extmarks); - -typedef struct { - OptionalKeys is_set__keymap_; - Boolean noremap; - Boolean nowait; - Boolean silent; - Boolean script; - Boolean expr; - Boolean unique; - LuaRef callback; - String desc; - Boolean replace_keycodes; -} Dict(keymap); - -typedef struct { - Boolean builtin; -} Dict(get_commands); - -typedef struct { - OptionalKeys is_set__user_command_; - Object addr; - Boolean bang; - Boolean bar; - Object complete; - Object count; - Object desc; - Boolean force; - Boolean keepscript; - Object nargs; - Object preview; - Object range; - Boolean register_; -} Dict(user_command); - -typedef struct { - OptionalKeys is_set__float_config_; - Float row; - Float col; - Integer width; - Integer height; - String anchor; - String relative; - Window win; - Array bufpos; - Boolean external; - Boolean focusable; - Integer zindex; - Object border; - Object title; - String title_pos; - Object footer; - String footer_pos; - String style; - Boolean noautocmd; - Boolean fixed; - Boolean hide; -} Dict(float_config); - -typedef struct { - Boolean is_lua; - Boolean do_source; -} Dict(runtime); - -typedef struct { - OptionalKeys is_set__eval_statusline_; - Window winid; - Integer maxwidth; - String fillchar; - Boolean highlights; - Boolean use_winbar; - Boolean use_tabline; - Integer use_statuscol_lnum; -} Dict(eval_statusline); - -typedef struct { - OptionalKeys is_set__option_; - String scope; - Window win; - Buffer buf; - String filetype; -} Dict(option); - -typedef struct { - OptionalKeys is_set__highlight_; - Boolean bold; - Boolean standout; - Boolean strikethrough; - Boolean underline; - Boolean undercurl; - Boolean underdouble; - Boolean underdotted; - Boolean underdashed; - Boolean italic; - Boolean reverse; - Boolean altfont; - Boolean nocombine; - Boolean default_; - Object cterm; - Object foreground; - Object fg; - Object background; - Object bg; - Object ctermfg; - Object ctermbg; - Object special; - Object sp; - Object link; - Object global_link; - Boolean fallback; - Integer blend; - Boolean fg_indexed; - Boolean bg_indexed; - Boolean force; -} Dict(highlight); - -typedef struct { - Boolean bold; - Boolean standout; - Boolean strikethrough; - Boolean underline; - Boolean undercurl; - Boolean underdouble; - Boolean underdotted; - Boolean underdashed; - Boolean italic; - Boolean reverse; - Boolean altfont; - Boolean nocombine; -} Dict(highlight_cterm); - -typedef struct { - OptionalKeys is_set__get_highlight_; - Integer id; - String name; - Boolean link; - Boolean create; -} Dict(get_highlight); - -typedef struct { - OptionalKeys is_set__get_ns_; - Window winid; -} Dict(get_ns); - -typedef struct { - OptionalKeys is_set__win_text_height_; - Integer start_row; - Integer end_row; - Integer start_vcol; - Integer end_vcol; -} Dict(win_text_height); - -typedef struct { - OptionalKeys is_set__clear_autocmds_; - Buffer buffer; - Object event; - Object group; - Object pattern; -} Dict(clear_autocmds); - -typedef struct { - OptionalKeys is_set__create_autocmd_; - Buffer buffer; - Object callback; - String command; - String desc; - Object group; - Boolean nested; - Boolean once; - Object pattern; -} Dict(create_autocmd); - -typedef struct { - OptionalKeys is_set__exec_autocmds_; - Buffer buffer; - Object group; - Boolean modeline; - Object pattern; - Object data; -} Dict(exec_autocmds); - -typedef struct { - OptionalKeys is_set__get_autocmds_; - Object event; - Object group; - Object pattern; - Object buffer; -} Dict(get_autocmds); - -typedef struct { - Object clear; -} Dict(create_augroup); - -typedef struct { - OptionalKeys is_set__cmd_; - String cmd; - Array range; - Integer count; - String reg; - Boolean bang; - Array args; - Dictionary magic; - Dictionary mods; - Object nargs; - Object addr; - Object nextcmd; -} Dict(cmd); - -typedef struct { - OptionalKeys is_set__cmd_magic_; - Boolean file; - Boolean bar; -} Dict(cmd_magic); - -typedef struct { - OptionalKeys is_set__cmd_mods_; - Boolean silent; - Boolean emsg_silent; - Boolean unsilent; - Dictionary filter; - Boolean sandbox; - Boolean noautocmd; - Boolean browse; - Boolean confirm; - Boolean hide; - Boolean horizontal; - Boolean keepalt; - Boolean keepjumps; - Boolean keepmarks; - Boolean keeppatterns; - Boolean lockmarks; - Boolean noswapfile; - Integer tab; - Integer verbose; - Boolean vertical; - String split; -} Dict(cmd_mods); - -typedef struct { - OptionalKeys is_set__cmd_mods_filter_; - String pattern; - Boolean force; -} Dict(cmd_mods_filter); - -typedef struct { - Boolean output; -} Dict(cmd_opts); - -typedef struct { - Boolean verbose; -} Dict(echo_opts); - -typedef struct { - Boolean output; -} Dict(exec_opts); diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h new file mode 100644 index 0000000000..e59eda5686 --- /dev/null +++ b/src/nvim/api/keysets_defs.h @@ -0,0 +1,315 @@ +#pragma once + +#include "nvim/api/private/defs.h" + +typedef struct { + OptionalKeys is_set__context_; + Array types; +} Dict(context); + +typedef struct { + OptionalKeys is_set__set_decoration_provider_; + LuaRef on_start; + LuaRef on_buf; + LuaRef on_win; + LuaRef on_line; + LuaRef on_end; + LuaRef _on_hl_def; + LuaRef _on_spell_nav; +} Dict(set_decoration_provider); + +typedef struct { + OptionalKeys is_set__set_extmark_; + Integer id; + Integer end_line; + Integer end_row; + Integer end_col; + Object hl_group; + Array virt_text; + String virt_text_pos; + Integer virt_text_win_col; + Boolean virt_text_hide; + Boolean hl_eol; + String hl_mode; + Boolean invalidate; + Boolean ephemeral; + Integer priority; + Boolean right_gravity; + Boolean end_right_gravity; + Array virt_lines; + Boolean virt_lines_above; + Boolean virt_lines_leftcol; + Boolean strict; + String sign_text; + Object sign_hl_group; + Object number_hl_group; + Object line_hl_group; + Object cursorline_hl_group; + String conceal; + Boolean spell; + Boolean ui_watched; + Boolean undo_restore; +} Dict(set_extmark); + +typedef struct { + OptionalKeys is_set__get_extmarks_; + Integer limit; + Boolean details; + Boolean hl_name; + Boolean overlap; + String type; +} Dict(get_extmarks); + +typedef struct { + OptionalKeys is_set__keymap_; + Boolean noremap; + Boolean nowait; + Boolean silent; + Boolean script; + Boolean expr; + Boolean unique; + LuaRef callback; + String desc; + Boolean replace_keycodes; +} Dict(keymap); + +typedef struct { + Boolean builtin; +} Dict(get_commands); + +typedef struct { + OptionalKeys is_set__user_command_; + Object addr; + Boolean bang; + Boolean bar; + Object complete; + Object count; + Object desc; + Boolean force; + Boolean keepscript; + Object nargs; + Object preview; + Object range; + Boolean register_; +} Dict(user_command); + +typedef struct { + OptionalKeys is_set__float_config_; + Float row; + Float col; + Integer width; + Integer height; + String anchor; + String relative; + Window win; + Array bufpos; + Boolean external; + Boolean focusable; + Integer zindex; + Object border; + Object title; + String title_pos; + Object footer; + String footer_pos; + String style; + Boolean noautocmd; + Boolean fixed; + Boolean hide; +} Dict(float_config); + +typedef struct { + Boolean is_lua; + Boolean do_source; +} Dict(runtime); + +typedef struct { + OptionalKeys is_set__eval_statusline_; + Window winid; + Integer maxwidth; + String fillchar; + Boolean highlights; + Boolean use_winbar; + Boolean use_tabline; + Integer use_statuscol_lnum; +} Dict(eval_statusline); + +typedef struct { + OptionalKeys is_set__option_; + String scope; + Window win; + Buffer buf; + String filetype; +} Dict(option); + +typedef struct { + OptionalKeys is_set__highlight_; + Boolean bold; + Boolean standout; + Boolean strikethrough; + Boolean underline; + Boolean undercurl; + Boolean underdouble; + Boolean underdotted; + Boolean underdashed; + Boolean italic; + Boolean reverse; + Boolean altfont; + Boolean nocombine; + Boolean default_; + Object cterm; + Object foreground; + Object fg; + Object background; + Object bg; + Object ctermfg; + Object ctermbg; + Object special; + Object sp; + Object link; + Object global_link; + Boolean fallback; + Integer blend; + Boolean fg_indexed; + Boolean bg_indexed; + Boolean force; +} Dict(highlight); + +typedef struct { + Boolean bold; + Boolean standout; + Boolean strikethrough; + Boolean underline; + Boolean undercurl; + Boolean underdouble; + Boolean underdotted; + Boolean underdashed; + Boolean italic; + Boolean reverse; + Boolean altfont; + Boolean nocombine; +} Dict(highlight_cterm); + +typedef struct { + OptionalKeys is_set__get_highlight_; + Integer id; + String name; + Boolean link; + Boolean create; +} Dict(get_highlight); + +typedef struct { + OptionalKeys is_set__get_ns_; + Window winid; +} Dict(get_ns); + +typedef struct { + OptionalKeys is_set__win_text_height_; + Integer start_row; + Integer end_row; + Integer start_vcol; + Integer end_vcol; +} Dict(win_text_height); + +typedef struct { + OptionalKeys is_set__clear_autocmds_; + Buffer buffer; + Object event; + Object group; + Object pattern; +} Dict(clear_autocmds); + +typedef struct { + OptionalKeys is_set__create_autocmd_; + Buffer buffer; + Object callback; + String command; + String desc; + Object group; + Boolean nested; + Boolean once; + Object pattern; +} Dict(create_autocmd); + +typedef struct { + OptionalKeys is_set__exec_autocmds_; + Buffer buffer; + Object group; + Boolean modeline; + Object pattern; + Object data; +} Dict(exec_autocmds); + +typedef struct { + OptionalKeys is_set__get_autocmds_; + Object event; + Object group; + Object pattern; + Object buffer; +} Dict(get_autocmds); + +typedef struct { + Object clear; +} Dict(create_augroup); + +typedef struct { + OptionalKeys is_set__cmd_; + String cmd; + Array range; + Integer count; + String reg; + Boolean bang; + Array args; + Dictionary magic; + Dictionary mods; + Object nargs; + Object addr; + Object nextcmd; +} Dict(cmd); + +typedef struct { + OptionalKeys is_set__cmd_magic_; + Boolean file; + Boolean bar; +} Dict(cmd_magic); + +typedef struct { + OptionalKeys is_set__cmd_mods_; + Boolean silent; + Boolean emsg_silent; + Boolean unsilent; + Dictionary filter; + Boolean sandbox; + Boolean noautocmd; + Boolean browse; + Boolean confirm; + Boolean hide; + Boolean horizontal; + Boolean keepalt; + Boolean keepjumps; + Boolean keepmarks; + Boolean keeppatterns; + Boolean lockmarks; + Boolean noswapfile; + Integer tab; + Integer verbose; + Boolean vertical; + String split; +} Dict(cmd_mods); + +typedef struct { + OptionalKeys is_set__cmd_mods_filter_; + String pattern; + Boolean force; +} Dict(cmd_mods_filter); + +typedef struct { + Boolean output; +} Dict(cmd_opts); + +typedef struct { + Boolean verbose; +} Dict(echo_opts); + +typedef struct { + Boolean output; +} Dict(exec_opts); diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 6b9d3d1130..d08a44b0ad 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -2,7 +2,7 @@ #include #include -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/options.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" diff --git a/src/nvim/api/options.h b/src/nvim/api/options.h index 2a7385eb56..e44ed44c80 100644 --- a/src/nvim/api/options.h +++ b/src/nvim/api/options.h @@ -2,7 +2,7 @@ #include // IWYU pragma: keep -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/defs.h" // IWYU pragma: keep #include "nvim/option_defs.h" // IWYU pragma: keep diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 5a206471fa..73001cfb6a 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -11,7 +11,7 @@ #include "klib/kvec.h" #include "nvim/api/buffer.h" #include "nvim/api/deprecated.h" -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/converter.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" diff --git a/src/nvim/api/vim.h b/src/nvim/api/vim.h index eb165f285f..b2ebacb309 100644 --- a/src/nvim/api/vim.h +++ b/src/nvim/api/vim.h @@ -2,7 +2,7 @@ #include // IWYU pragma: keep -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index b68eba1005..233da2dd9f 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -5,7 +5,7 @@ #include #include "klib/kvec.h" -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/converter.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" diff --git a/src/nvim/api/vimscript.h b/src/nvim/api/vimscript.h index d782f63aec..c068542311 100644 --- a/src/nvim/api/vimscript.h +++ b/src/nvim/api/vimscript.h @@ -2,7 +2,7 @@ #include // IWYU pragma: keep -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index ee9e75f183..f980c277d1 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -3,7 +3,7 @@ #include "klib/kvec.h" #include "nvim/api/extmark.h" -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" diff --git a/src/nvim/api/win_config.h b/src/nvim/api/win_config.h index 36f0e2bcf7..47e441a592 100644 --- a/src/nvim/api/win_config.h +++ b/src/nvim/api/win_config.h @@ -2,7 +2,7 @@ #include // IWYU pragma: keep -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 44c1c5595c..15460ec368 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -3,7 +3,7 @@ #include #include -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" diff --git a/src/nvim/api/window.h b/src/nvim/api/window.h index 0255193ac7..600d6956b5 100644 --- a/src/nvim/api/window.h +++ b/src/nvim/api/window.h @@ -1,6 +1,6 @@ #pragma once -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS -- cgit From 6c14ae6bfaf51415b555e9a6b85d1d280976358d Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 20:27:32 +0100 Subject: refactor: rename types.h to types_defs.h --- src/nvim/api/buffer.c | 2 +- src/nvim/api/command.c | 2 +- src/nvim/api/extmark.h | 2 +- src/nvim/api/private/converter.c | 2 +- src/nvim/api/private/defs.h | 2 +- src/nvim/api/private/dispatch.h | 2 +- src/nvim/api/private/helpers.c | 2 +- src/nvim/api/ui.c | 2 +- src/nvim/api/vim.c | 2 +- src/nvim/api/window.c | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index ec667a8953..3f4ab2760d 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -34,7 +34,7 @@ #include "nvim/move.h" #include "nvim/ops.h" #include "nvim/pos_defs.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" #include "nvim/undo.h" #include "nvim/vim.h" diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 2d3bc26e62..f9e2c58dd9 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -29,7 +29,7 @@ #include "nvim/pos_defs.h" #include "nvim/regexp.h" #include "nvim/strings.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" #include "nvim/usercmd.h" #include "nvim/vim.h" #include "nvim/window.h" diff --git a/src/nvim/api/extmark.h b/src/nvim/api/extmark.h index 0a28be98c5..2989dee53d 100644 --- a/src/nvim/api/extmark.h +++ b/src/nvim/api/extmark.h @@ -7,7 +7,7 @@ #include "nvim/decoration_defs.h" // IWYU pragma: keep #include "nvim/macros.h" #include "nvim/map.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" EXTERN Map(String, int) namespace_ids INIT( = MAP_INIT); EXTERN handle_T next_namespace_id INIT( = 1); diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index 228172fd28..40ec680184 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -14,7 +14,7 @@ #include "nvim/func_attr.h" #include "nvim/lua/executor.h" #include "nvim/memory.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" #include "nvim/vim.h" /// Helper structure for vim_to_object diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index 067592ed4e..25c8377518 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -6,7 +6,7 @@ #include "klib/kvec.h" #include "nvim/func_attr.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" #define ARRAY_DICT_INIT KV_INITIAL_VALUE #define STRING_INIT { .data = NULL, .size = 0 } diff --git a/src/nvim/api/private/dispatch.h b/src/nvim/api/private/dispatch.h index 0a651ebd1c..3d12b941f4 100644 --- a/src/nvim/api/private/dispatch.h +++ b/src/nvim/api/private/dispatch.h @@ -5,7 +5,7 @@ #include "nvim/api/private/defs.h" #include "nvim/memory.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" typedef Object (*ApiDispatchWrapper)(uint64_t channel_id, Array args, Arena *arena, Error *error); diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 33defa63ef..2599850452 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -32,7 +32,7 @@ #include "nvim/message.h" #include "nvim/msgpack_rpc/helpers.h" #include "nvim/pos_defs.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" #include "nvim/ui.h" #include "nvim/version.h" diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 7366e24703..9eb1cc675f 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -29,7 +29,7 @@ #include "nvim/msgpack_rpc/channel.h" #include "nvim/msgpack_rpc/helpers.h" #include "nvim/option.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" #include "nvim/ui.h" #include "nvim/vim.h" diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 73001cfb6a..858fda68b9 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -65,7 +65,7 @@ #include "nvim/statusline.h" #include "nvim/strings.h" #include "nvim/terminal.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" #include "nvim/ui.h" #include "nvim/vim.h" #include "nvim/window.h" diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 15460ec368..de5b40940f 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -24,7 +24,7 @@ #include "nvim/move.h" #include "nvim/plines.h" #include "nvim/pos_defs.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" #include "nvim/window.h" /// Gets the current buffer in a window -- cgit From 718053b7a97c4e2fbaa6077d3c9f4dc7012c8aad Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 28 Nov 2023 07:47:36 +0800 Subject: refactor: fix runtime_defs.h (#26259) --- src/nvim/api/buffer.h | 4 ++-- src/nvim/api/command.h | 2 +- src/nvim/api/extmark.h | 2 +- src/nvim/api/options.h | 2 +- src/nvim/api/private/dispatch.h | 2 +- src/nvim/api/vim.h | 2 +- src/nvim/api/vimscript.h | 2 +- src/nvim/api/win_config.h | 2 +- src/nvim/api/window.h | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.h b/src/nvim/api/buffer.h index 557cf8db0c..f3971c1d30 100644 --- a/src/nvim/api/buffer.h +++ b/src/nvim/api/buffer.h @@ -3,9 +3,9 @@ #include // IWYU pragma: keep #include // IWYU pragma: keep -#include "nvim/api/keysets_defs.h" +#include "nvim/api/keysets_defs.h" // IWYU pragma: keep #include "nvim/api/private/defs.h" // IWYU pragma: keep -#include "nvim/buffer_defs.h" +#include "nvim/buffer_defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/buffer.h.generated.h" diff --git a/src/nvim/api/command.h b/src/nvim/api/command.h index 95f0e05993..1cccbfb4c7 100644 --- a/src/nvim/api/command.h +++ b/src/nvim/api/command.h @@ -2,7 +2,7 @@ #include // IWYU pragma: keep -#include "nvim/api/keysets_defs.h" +#include "nvim/api/keysets_defs.h" // IWYU pragma: keep #include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/extmark.h b/src/nvim/api/extmark.h index 2989dee53d..491e468d95 100644 --- a/src/nvim/api/extmark.h +++ b/src/nvim/api/extmark.h @@ -2,7 +2,7 @@ #include // IWYU pragma: keep -#include "nvim/api/keysets_defs.h" +#include "nvim/api/keysets_defs.h" // IWYU pragma: keep #include "nvim/api/private/defs.h" // IWYU pragma: keep #include "nvim/decoration_defs.h" // IWYU pragma: keep #include "nvim/macros.h" diff --git a/src/nvim/api/options.h b/src/nvim/api/options.h index e44ed44c80..c16c6088b3 100644 --- a/src/nvim/api/options.h +++ b/src/nvim/api/options.h @@ -2,7 +2,7 @@ #include // IWYU pragma: keep -#include "nvim/api/keysets_defs.h" +#include "nvim/api/keysets_defs.h" // IWYU pragma: keep #include "nvim/api/private/defs.h" // IWYU pragma: keep #include "nvim/option_defs.h" // IWYU pragma: keep diff --git a/src/nvim/api/private/dispatch.h b/src/nvim/api/private/dispatch.h index 3d12b941f4..6a2c9eaf54 100644 --- a/src/nvim/api/private/dispatch.h +++ b/src/nvim/api/private/dispatch.h @@ -4,7 +4,7 @@ #include #include "nvim/api/private/defs.h" -#include "nvim/memory.h" +#include "nvim/memory_defs.h" #include "nvim/types_defs.h" typedef Object (*ApiDispatchWrapper)(uint64_t channel_id, Array args, Arena *arena, Error *error); diff --git a/src/nvim/api/vim.h b/src/nvim/api/vim.h index b2ebacb309..b620158751 100644 --- a/src/nvim/api/vim.h +++ b/src/nvim/api/vim.h @@ -2,7 +2,7 @@ #include // IWYU pragma: keep -#include "nvim/api/keysets_defs.h" +#include "nvim/api/keysets_defs.h" // IWYU pragma: keep #include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/vimscript.h b/src/nvim/api/vimscript.h index c068542311..c315e932e9 100644 --- a/src/nvim/api/vimscript.h +++ b/src/nvim/api/vimscript.h @@ -2,7 +2,7 @@ #include // IWYU pragma: keep -#include "nvim/api/keysets_defs.h" +#include "nvim/api/keysets_defs.h" // IWYU pragma: keep #include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/win_config.h b/src/nvim/api/win_config.h index 47e441a592..6df8ed13fa 100644 --- a/src/nvim/api/win_config.h +++ b/src/nvim/api/win_config.h @@ -2,7 +2,7 @@ #include // IWYU pragma: keep -#include "nvim/api/keysets_defs.h" +#include "nvim/api/keysets_defs.h" // IWYU pragma: keep #include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/window.h b/src/nvim/api/window.h index 600d6956b5..a5c9f86225 100644 --- a/src/nvim/api/window.h +++ b/src/nvim/api/window.h @@ -1,6 +1,6 @@ #pragma once -#include "nvim/api/keysets_defs.h" +#include "nvim/api/keysets_defs.h" // IWYU pragma: keep #include "nvim/api/private/defs.h" // IWYU pragma: keep #ifdef INCLUDE_GENERATED_DECLARATIONS -- cgit From ae3685798deaf51f14422c568998998c03f91f2c Mon Sep 17 00:00:00 2001 From: bfredl Date: Sun, 26 Nov 2023 21:07:29 +0100 Subject: feat(decoration): allow conceal_char to be a composing char decor->text.str pointer must go. This removes it for conceal char, in preparation for a larger PR which will also handle the sign case. By actually allowing composing chars for a conceal chars, this becomes a feature and not just a refactor, as a bonus. --- src/nvim/api/extmark.c | 17 +++++++++-------- src/nvim/api/vim.c | 5 ++++- 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 9a4dfe6788..d9e41f2448 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -18,6 +18,7 @@ #include "nvim/drawscreen.h" #include "nvim/extmark.h" #include "nvim/func_attr.h" +#include "nvim/grid.h" #include "nvim/highlight_group.h" #include "nvim/marktree.h" #include "nvim/mbyte.h" @@ -503,7 +504,6 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer DecorVirtText virt_text = DECOR_VIRT_TEXT_INIT; DecorVirtText virt_lines = DECOR_VIRT_LINES_INIT; bool has_hl = false; - String conceal_char_large = STRING_INIT; buf_T *buf = find_buffer_by_handle(buffer, err); if (!buf) { @@ -593,10 +593,11 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer has_hl = true; String c = opts->conceal; if (c.size > 0) { - if (c.size <= 4) { - memcpy(hl.conceal_char, c.data, c.size + (c.size < 4 ? 1 : 0)); - } else { - conceal_char_large = c; + int ch; + hl.conceal_char = utfc_ptr2schar_len(c.data, (int)c.size, &ch); + if (!hl.conceal_char || !vim_isprintc(ch)) { + api_set_error(err, kErrorTypeValidation, "conceal char has to be printable"); + goto error; } } } @@ -777,7 +778,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_lines, NULL), true); } if (has_hl) { - DecorSignHighlight sh = decor_sh_from_inline(hl, conceal_char_large); + DecorSignHighlight sh = decor_sh_from_inline(hl); decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, (uint32_t)ns_id, id); } if (sign.flags & kSHIsSign) { @@ -815,9 +816,9 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } DecorInline decor = DECOR_INLINE_INIT; - if (decor_alloc || decor_indexed != DECOR_ID_INVALID || conceal_char_large.size) { + if (decor_alloc || decor_indexed != DECOR_ID_INVALID || schar_high(hl.conceal_char)) { if (has_hl) { - DecorSignHighlight sh = decor_sh_from_inline(hl, conceal_char_large); + DecorSignHighlight sh = decor_sh_from_inline(hl); sh.next = decor_indexed; decor_indexed = decor_put_sh(sh); } diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 858fda68b9..ad111510e5 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1999,9 +1999,12 @@ void nvim__screenshot(String path) ui_call_screenshot(path); } +/// For testing. The condition in schar_cache_clear_if_full is hard to +/// reach, so this function can be used to force a cache clear in a test. void nvim__invalidate_glyph_cache(void) { - schar_cache_clear_force(); + schar_cache_clear(); + must_redraw = UPD_CLEAR; } Object nvim__unpack(String str, Error *err) -- cgit From c9f53d0e40815644bbf7c57a0792f2c793c954aa Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 28 Nov 2023 19:00:14 +0800 Subject: refactor: iwyu (#26269) --- src/nvim/api/ui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.h b/src/nvim/api/ui.h index 3d9152e0a4..051153de83 100644 --- a/src/nvim/api/ui.h +++ b/src/nvim/api/ui.h @@ -3,9 +3,9 @@ #include // IWYU pragma: keep #include "nvim/api/private/defs.h" // IWYU pragma: keep -#include "nvim/grid_defs.h" // IWYU pragma: keep #include "nvim/highlight_defs.h" // IWYU pragma: keep #include "nvim/map.h" +#include "nvim/types_defs.h" // IWYU pragma: keep #include "nvim/ui.h" #ifdef INCLUDE_GENERATED_DECLARATIONS -- cgit From 79b6ff28ad1204fbb4199b9092f5c578d88cb28e Mon Sep 17 00:00:00 2001 From: dundargoc Date: Tue, 28 Nov 2023 20:31:00 +0100 Subject: refactor: fix headers with IWYU --- src/nvim/api/autocmd.c | 2 +- src/nvim/api/buffer.c | 4 ++-- src/nvim/api/command.c | 6 +++--- src/nvim/api/extmark.h | 4 ++-- src/nvim/api/options.c | 4 ++-- src/nvim/api/private/converter.c | 4 ++-- src/nvim/api/private/helpers.c | 4 ++-- src/nvim/api/private/helpers.h | 4 ++-- src/nvim/api/private/validate.c | 2 +- src/nvim/api/private/validate.h | 4 ++-- src/nvim/api/ui.c | 6 +++--- src/nvim/api/ui.h | 2 +- src/nvim/api/vim.c | 6 +++--- src/nvim/api/vimscript.c | 4 ++-- src/nvim/api/win_config.c | 4 ++-- 15 files changed, 30 insertions(+), 30 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 96d330f92b..08d9d8e117 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -21,7 +21,7 @@ #include "nvim/globals.h" #include "nvim/lua/executor.h" #include "nvim/memory.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/autocmd.c.generated.h" diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 3f4ab2760d..96e0e240f2 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -14,7 +14,7 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/api/private/validate.h" -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" @@ -36,7 +36,7 @@ #include "nvim/pos_defs.h" #include "nvim/types_defs.h" #include "nvim/undo.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/buffer.c.generated.h" diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index f9e2c58dd9..2a57ce9a19 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -11,7 +11,7 @@ #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" #include "nvim/api/private/validate.h" -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/cmdexpand_defs.h" @@ -22,7 +22,7 @@ #include "nvim/garray.h" #include "nvim/globals.h" #include "nvim/lua/executor.h" -#include "nvim/macros.h" +#include "nvim/macros_defs.h" #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/ops.h" @@ -31,7 +31,7 @@ #include "nvim/strings.h" #include "nvim/types_defs.h" #include "nvim/usercmd.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" #include "nvim/window.h" #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/extmark.h b/src/nvim/api/extmark.h index 491e468d95..124feaabfb 100644 --- a/src/nvim/api/extmark.h +++ b/src/nvim/api/extmark.h @@ -5,8 +5,8 @@ #include "nvim/api/keysets_defs.h" // IWYU pragma: keep #include "nvim/api/private/defs.h" // IWYU pragma: keep #include "nvim/decoration_defs.h" // IWYU pragma: keep -#include "nvim/macros.h" -#include "nvim/map.h" +#include "nvim/macros_defs.h" +#include "nvim/map_defs.h" #include "nvim/types_defs.h" EXTERN Map(String, int) namespace_ids INIT( = MAP_INIT); diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index d08a44b0ad..c012a69c7b 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -13,11 +13,11 @@ #include "nvim/eval/window.h" #include "nvim/func_attr.h" #include "nvim/globals.h" -#include "nvim/macros.h" +#include "nvim/macros_defs.h" #include "nvim/memory.h" #include "nvim/option.h" #include "nvim/option_vars.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" #include "nvim/window.h" #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index 40ec680184..90023171e5 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -7,7 +7,7 @@ #include "nvim/api/private/converter.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" -#include "nvim/assert.h" +#include "nvim/assert_defs.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" @@ -15,7 +15,7 @@ #include "nvim/lua/executor.h" #include "nvim/memory.h" #include "nvim/types_defs.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" /// Helper structure for vim_to_object typedef struct { diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 2599850452..be39836a5b 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -14,7 +14,7 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/api/private/validate.h" -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -25,7 +25,7 @@ #include "nvim/globals.h" #include "nvim/highlight_group.h" #include "nvim/lua/executor.h" -#include "nvim/map.h" +#include "nvim/map_defs.h" #include "nvim/mark.h" #include "nvim/memline.h" #include "nvim/memory.h" diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 56ca9b2057..e61dd5f992 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -13,8 +13,8 @@ #include "nvim/getchar.h" #include "nvim/gettext.h" #include "nvim/globals.h" -#include "nvim/macros.h" -#include "nvim/map.h" +#include "nvim/macros_defs.h" +#include "nvim/map_defs.h" #include "nvim/memory.h" #include "nvim/message.h" diff --git a/src/nvim/api/private/validate.c b/src/nvim/api/private/validate.c index 17e9d081a6..e198c671eb 100644 --- a/src/nvim/api/private/validate.c +++ b/src/nvim/api/private/validate.c @@ -5,7 +5,7 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/api/private/validate.h" -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/globals.h" /// Creates "Invalid …" message and sets it on `err`. diff --git a/src/nvim/api/private/validate.h b/src/nvim/api/private/validate.h index 29ca6242f3..d1c977cd6e 100644 --- a/src/nvim/api/private/validate.h +++ b/src/nvim/api/private/validate.h @@ -5,8 +5,8 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" -#include "nvim/assert.h" -#include "nvim/macros.h" +#include "nvim/assert_defs.h" +#include "nvim/macros_defs.h" #define VALIDATE(cond, fmt_, fmt_arg1, code) \ do { \ diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 9eb1cc675f..bf554a8829 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -21,9 +21,9 @@ #include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/highlight.h" -#include "nvim/macros.h" +#include "nvim/macros_defs.h" #include "nvim/main.h" -#include "nvim/map.h" +#include "nvim/map_defs.h" #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/msgpack_rpc/channel.h" @@ -31,7 +31,7 @@ #include "nvim/option.h" #include "nvim/types_defs.h" #include "nvim/ui.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" #define BUF_POS(data) ((size_t)((data)->buf_wptr - (data)->buf)) diff --git a/src/nvim/api/ui.h b/src/nvim/api/ui.h index 051153de83..26a91d0dbc 100644 --- a/src/nvim/api/ui.h +++ b/src/nvim/api/ui.h @@ -4,7 +4,7 @@ #include "nvim/api/private/defs.h" // IWYU pragma: keep #include "nvim/highlight_defs.h" // IWYU pragma: keep -#include "nvim/map.h" +#include "nvim/map_defs.h" #include "nvim/types_defs.h" // IWYU pragma: keep #include "nvim/ui.h" diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index ad111510e5..fdf12cba9e 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -18,7 +18,7 @@ #include "nvim/api/private/helpers.h" #include "nvim/api/private/validate.h" #include "nvim/api/vim.h" -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/channel.h" @@ -40,7 +40,7 @@ #include "nvim/keycodes.h" #include "nvim/log.h" #include "nvim/lua/executor.h" -#include "nvim/macros.h" +#include "nvim/macros_defs.h" #include "nvim/mapping.h" #include "nvim/mark.h" #include "nvim/mbyte.h" @@ -67,7 +67,7 @@ #include "nvim/terminal.h" #include "nvim/types_defs.h" #include "nvim/ui.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" #include "nvim/window.h" #define LINE_BUFFER_MIN_SIZE 4096 diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 233da2dd9f..c75bf21572 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -10,7 +10,7 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/api/vimscript.h" -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" @@ -20,7 +20,7 @@ #include "nvim/globals.h" #include "nvim/memory.h" #include "nvim/runtime.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" #include "nvim/viml/parser/expressions.h" #include "nvim/viml/parser/parser.h" diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index f980c277d1..874be200ee 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -8,7 +8,7 @@ #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" #include "nvim/api/win_config.h" -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/decoration.h" @@ -17,7 +17,7 @@ #include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/highlight_group.h" -#include "nvim/macros.h" +#include "nvim/macros_defs.h" #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/option.h" -- cgit From a0e9ef09d7af8274c754ca6c368ef4a6f7411510 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Wed, 29 Nov 2023 02:17:16 +0100 Subject: fix(decorations): do not apply sign highlight id as range attr id --- src/nvim/api/extmark.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index d9e41f2448..d71498d6ed 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -781,9 +781,6 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer DecorSignHighlight sh = decor_sh_from_inline(hl); decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, (uint32_t)ns_id, id); } - if (sign.flags & kSHIsSign) { - decor_range_add_sh(&decor_state, r, c, line2, col2, &sign, true, (uint32_t)ns_id, id); - } } else { if (opts->ephemeral) { api_set_error(err, kErrorTypeException, "not yet implemented"); -- cgit From 64b53b71ba5d804b2c8cf186be68931b2621f53c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 29 Nov 2023 12:10:42 +0800 Subject: refactor(IWYU): create normal_defs.h (#26293) --- src/nvim/api/vim.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index fdf12cba9e..d631b10af9 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -55,7 +55,6 @@ #include "nvim/option_vars.h" #include "nvim/optionstr.h" #include "nvim/os/input.h" -#include "nvim/os/os_defs.h" #include "nvim/os/process.h" #include "nvim/popupmenu.h" #include "nvim/pos_defs.h" -- cgit From a6cba103cebce535279db197f9efeb34e9d1171f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 29 Nov 2023 20:32:40 +0800 Subject: refactor: move some constants out of vim_defs.h (#26298) --- src/nvim/api/buffer.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 96e0e240f2..0df231868d 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -34,6 +34,7 @@ #include "nvim/move.h" #include "nvim/ops.h" #include "nvim/pos_defs.h" +#include "nvim/state_defs.h" #include "nvim/types_defs.h" #include "nvim/undo.h" #include "nvim/vim_defs.h" -- cgit From 86cc791debba09c8ed1aa0d863be844108866a38 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 29 Nov 2023 23:10:21 +0800 Subject: refactor: move function macros out of vim_defs.h (#26300) --- src/nvim/api/ui.c | 1 - src/nvim/api/win_config.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index bf554a8829..836a68546c 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -31,7 +31,6 @@ #include "nvim/option.h" #include "nvim/types_defs.h" #include "nvim/ui.h" -#include "nvim/vim_defs.h" #define BUF_POS(data) ((size_t)((data)->buf_wptr - (data)->buf)) diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 874be200ee..4e23717dc6 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -22,6 +22,7 @@ #include "nvim/memory.h" #include "nvim/option.h" #include "nvim/pos_defs.h" +#include "nvim/strings.h" #include "nvim/syntax.h" #include "nvim/ui.h" #include "nvim/window.h" -- cgit