diff options
Diffstat (limited to 'src/nvim/api')
-rw-r--r-- | src/nvim/api/autocmd.c | 46 | ||||
-rw-r--r-- | src/nvim/api/extmark.c | 14 | ||||
-rw-r--r-- | src/nvim/api/keysets.lua | 1 | ||||
-rw-r--r-- | src/nvim/api/ui.h | 1 | ||||
-rw-r--r-- | src/nvim/api/ui_events.in.h | 4 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 202 | ||||
-rw-r--r-- | src/nvim/api/vimscript.c | 229 |
7 files changed, 270 insertions, 227 deletions
diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 0db9a63e7a..010c03e505 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -23,9 +23,9 @@ // 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_u *__next_ev; \ + char *__next_ev; \ event_T event_nr = \ - event_name2nr((char_u *)event_str.data.string.data, &__next_ev); \ + event_name2nr(event_str.data.string.data, &__next_ev); \ if (event_nr >= NUM_EVENTS) { \ api_set_error(err, kErrorTypeValidation, "unexpected event"); \ goto goto_name; \ @@ -78,8 +78,8 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) // TODO(tjdevries): Would be cool to add nvim_get_autocmds({ id = ... }) Array autocmd_list = ARRAY_DICT_INIT; - char_u *pattern_filters[AUCMD_MAX_PATTERNS]; - char_u pattern_buflocal[BUFLOCAL_PAT_LEN]; + char *pattern_filters[AUCMD_MAX_PATTERNS]; + char pattern_buflocal[BUFLOCAL_PAT_LEN]; Array buffers = ARRAY_DICT_INIT; @@ -148,7 +148,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) if (opts->pattern.type != kObjectTypeNil) { Object v = opts->pattern; if (v.type == kObjectTypeString) { - pattern_filters[pattern_filter_count] = (char_u *)v.data.string.data; + 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) { @@ -164,7 +164,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) goto cleanup; } - pattern_filters[pattern_filter_count] = (char_u *)item.data.string.data; + pattern_filters[pattern_filter_count] = item.data.string.data; pattern_filter_count += 1; }); } else { @@ -211,7 +211,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) } FOREACH_ITEM(buffers, bufnr, { - pattern_filters[pattern_filter_count] = (char_u *)bufnr.data.string.data; + pattern_filters[pattern_filter_count] = bufnr.data.string.data; pattern_filter_count += 1; }); @@ -237,7 +237,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) assert(i < AUCMD_MAX_PATTERNS); assert(pattern_filters[i]); - char_u *pat = pattern_filters[i]; + char *pat = pattern_filters[i]; int patlen = (int)STRLEN(pat); if (aupat_is_buflocal(pat, patlen)) { @@ -249,7 +249,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) pat = pattern_buflocal; } - if (strequal((char *)ap->pat, (char *)pat)) { + if (strequal(ap->pat, pat)) { passed = true; break; } @@ -474,7 +474,7 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc Object *command = &opts->command; if (command->type == kObjectTypeString) { aucmd.type = CALLABLE_EX; - aucmd.callable.cmd = (char_u *)string_to_cstr(command->data.string); + aucmd.callable.cmd = string_to_cstr(command->data.string); } else { api_set_error(err, kErrorTypeValidation, @@ -531,7 +531,7 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc WITH_SCRIPT_CONTEXT(channel_id, { retval = autocmd_register(autocmd_id, event_nr, - (char_u *)pat.data.string.data, + pat.data.string.data, (int)pat.data.string.size, au_group, is_once, @@ -635,8 +635,8 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err) if (event_array.size == 0) { FOR_ALL_AUEVENTS(event) { FOREACH_ITEM(patterns, pat_object, { - char_u *pat = (char_u *)pat_object.data.string.data; - if (!clear_autocmd(event, pat, au_group, err)) { + char *pat = pat_object.data.string.data; + if (!clear_autocmd(event, (char *)pat, au_group, err)) { goto cleanup; } }); @@ -646,8 +646,8 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err) GET_ONE_EVENT(event_nr, event_str, cleanup); FOREACH_ITEM(patterns, pat_object, { - char_u *pat = (char_u *)pat_object.data.string.data; - if (!clear_autocmd(event_nr, pat, au_group, err)) { + char *pat = pat_object.data.string.data; + if (!clear_autocmd(event_nr, (char *)pat, au_group, err)) { goto cleanup; } }); @@ -657,8 +657,6 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err) cleanup: api_free_array(event_array); api_free_array(patterns); - - return; } /// Create or get an autocommand group |autocmd-groups|. @@ -759,7 +757,7 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err) buf_T *buf = curbuf; bool set_buf = false; - char_u *pattern = NULL; + char *pattern = NULL; bool set_pattern = false; Array event_array = ARRAY_DICT_INIT; @@ -814,7 +812,7 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err) goto cleanup; } - pattern = (char_u *)string_to_cstr(opts->pattern.data.string); + pattern = string_to_cstr(opts->pattern.data.string); set_pattern = true; } @@ -922,7 +920,7 @@ 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) { - const char_u pattern_buflocal[BUFLOCAL_PAT_LEN]; + const char pattern_buflocal[BUFLOCAL_PAT_LEN]; if (pattern.type != kObjectTypeNil && buffer.type != kObjectTypeNil) { api_set_error(err, kErrorTypeValidation, @@ -932,7 +930,7 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob Object *v = &pattern; if (v->type == kObjectTypeString) { - char_u *pat = (char_u *)v->data.string.data; + 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))); @@ -947,7 +945,7 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob Array array = v->data.array; for (size_t i = 0; i < array.size; i++) { - char_u *pat = (char_u *)array.items[i].data.string.data; + char *pat = array.items[i].data.string.data; size_t patlen = aucmd_pattern_length(pat); while (patlen) { ADD(*patterns, STRING_OBJ(cbuf_to_string((char *)pat, patlen))); @@ -982,9 +980,9 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob return true; } -static bool clear_autocmd(event_T event, char_u *pat, int au_group, Error *err) +static bool clear_autocmd(event_T event, char *pat, int au_group, Error *err) { - if (do_autocmd_event(event, pat, false, false, (char_u *)"", true, au_group) == FAIL) { + if (do_autocmd_event(event, pat, false, false, "", true, au_group) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to clear autocmd"); return false; } diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index e408d88854..fa6923e6d5 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -146,6 +146,10 @@ static Array extmark_to_array(ExtmarkInfo extmark, bool id, bool add_dict) STRING_OBJ(cstr_to_string(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; @@ -170,7 +174,7 @@ static Array extmark_to_array(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)) { + if (decor->hl_id || kv_size(decor->virt_text) || decor->ui_watched) { PUT(dict, "priority", INTEGER_OBJ(decor->priority)); } @@ -472,6 +476,10 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// When a character is supplied it is used as |:syn-cchar|. /// "hl_group" is used as highlight for the cchar if provided, /// otherwise it defaults to |hl-Conceal|. +/// - ui_watched: boolean that indicates the mark should be drawn +/// by a UI. When set, the UI will receive win_extmark events. +/// Note: the mark is positioned by virt_text attributes. Can be +/// used together with virt_text. /// /// @param[out] err Error details, if any /// @return Id of the created/updated extmark @@ -709,6 +717,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer bool ephemeral = false; OPTION_TO_BOOL(ephemeral, ephemeral, false); + OPTION_TO_BOOL(decor.ui_watched, ui_watched, false); + if (line < 0) { api_set_error(err, kErrorTypeValidation, "line value outside range"); goto error; @@ -762,7 +772,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) { - decor_add_ephemeral((int)line, (int)col, line2, col2, &decor); + decor_add_ephemeral((int)line, (int)col, line2, col2, &decor, (uint64_t)ns_id, id); } else { if (ephemeral) { api_set_error(err, kErrorTypeException, "not yet implemented"); diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua index 8ad4dae928..5baffaf505 100644 --- a/src/nvim/api/keysets.lua +++ b/src/nvim/api/keysets.lua @@ -28,6 +28,7 @@ return { "line_hl_group"; "cursorline_hl_group"; "conceal"; + "ui_watched"; }; keymap = { "noremap"; diff --git a/src/nvim/api/ui.h b/src/nvim/api/ui.h index b3af14f8a8..bc70406acb 100644 --- a/src/nvim/api/ui.h +++ b/src/nvim/api/ui.h @@ -4,6 +4,7 @@ #include <stdint.h> #include "nvim/api/private/defs.h" +#include "nvim/map.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/ui.h.generated.h" diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index db348359eb..63aaaae38a 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -123,6 +123,10 @@ void win_viewport(Integer grid, Window win, Integer topline, Integer line_count) FUNC_API_SINCE(7) FUNC_API_REMOTE_ONLY; +void win_extmark(Integer grid, Window win, Integer ns_id, Integer mark_id, + Integer row, Integer col) + FUNC_API_SINCE(10) FUNC_API_REMOTE_ONLY; + void popupmenu_show(Array items, Integer selected, Integer row, Integer col, Integer grid) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index d9ab097316..2323b8db47 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2210,7 +2210,7 @@ Array nvim_get_mark(String name, Dictionary opts, Error *err) allocated = true; // Marks comes from shada } else { - filename = (char *)mark.fname; + filename = mark.fname; bufnr = 0; } @@ -2461,203 +2461,3 @@ void nvim_del_user_command(String name, Error *err) { nvim_buf_del_user_command(-1, name, err); } - -/// Parse command line. -/// -/// Doesn't check the validity of command arguments. -/// -/// @param str Command line string to parse. Cannot contain "\n". -/// @param opts Optional parameters. Reserved for future use. -/// @param[out] err Error details, if any. -/// @return Dictionary containing command information, with these keys: -/// - cmd: (string) Command name. -/// - line1: (number) Starting line of command range. Only applicable if command can take a -/// range. -/// - line2: (number) Final line of command range. Only applicable if command can take a -/// range. -/// - bang: (boolean) Whether command contains a bang (!) modifier. -/// - args: (array) Command arguments. -/// - addr: (string) Value of |:command-addr|. Uses short name. -/// - nargs: (string) Value of |:command-nargs|. -/// - nextcmd: (string) Next command if there are multiple commands separated by a |:bar|. -/// Empty if there isn't a next command. -/// - magic: (dictionary) Which characters have special meaning in the command arguments. -/// - file: (boolean) The command expands filenames. Which means characters such as "%", -/// "#" and wildcards are expanded. -/// - bar: (boolean) The "|" character is treated as a command separator and the double -/// quote character (\") is treated as the start of a comment. -/// - mods: (dictionary) |:command-modifiers|. -/// - silent: (boolean) |:silent|. -/// - emsg_silent: (boolean) |:silent!|. -/// - sandbox: (boolean) |:sandbox|. -/// - noautocmd: (boolean) |:noautocmd|. -/// - browse: (boolean) |:browse|. -/// - confirm: (boolean) |:confirm|. -/// - hide: (boolean) |:hide|. -/// - keepalt: (boolean) |:keepalt|. -/// - keepjumps: (boolean) |:keepjumps|. -/// - keepmarks: (boolean) |:keepmarks|. -/// - keeppatterns: (boolean) |:keeppatterns|. -/// - lockmarks: (boolean) |:lockmarks|. -/// - noswapfile: (boolean) |:noswapfile|. -/// - tab: (integer) |:tab|. -/// - verbose: (integer) |:verbose|. -/// - vertical: (boolean) |:vertical|. -/// - split: (string) Split modifier string, is an empty string when there's no split -/// modifier. If there is a split modifier it can be one of: -/// - "aboveleft": |:aboveleft|. -/// - "belowright": |:belowright|. -/// - "topleft": |:topleft|. -/// - "botright": |:botright|. -Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) - FUNC_API_SINCE(10) FUNC_API_FAST -{ - Dictionary result = ARRAY_DICT_INIT; - - if (opts.size > 0) { - api_set_error(err, kErrorTypeValidation, "opts dict isn't empty"); - return result; - } - - // Parse command line - exarg_T ea; - CmdParseInfo cmdinfo; - char_u *cmdline = (char_u *)string_to_cstr(str); - - if (!parse_cmdline(cmdline, &ea, &cmdinfo)) { - api_set_error(err, kErrorTypeException, "Error while parsing command line"); - goto end; - } - - // Parse arguments - Array args = ARRAY_DICT_INIT; - size_t length = STRLEN(ea.arg); - - // For nargs = 1 or '?', pass the entire argument list as a single argument, - // 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))); - } - } else { - size_t end = 0; - size_t len = 0; - char *buf = xcalloc(length, sizeof(char)); - bool done = false; - - while (!done) { - done = uc_split_args_iter(ea.arg, length, &end, buf, &len); - if (len > 0) { - ADD(args, STRING_OBJ(cstrn_to_string(buf, len))); - } - } - - xfree(buf); - } - - if (ea.cmdidx == CMD_USER) { - PUT(result, "cmd", CSTR_TO_OBJ((char *)USER_CMD(ea.useridx)->uc_name)); - } else if (ea.cmdidx == CMD_USER_BUF) { - PUT(result, "cmd", CSTR_TO_OBJ((char *)USER_CMD_GA(&curbuf->b_ucmds, ea.useridx)->uc_name)); - } else { - PUT(result, "cmd", CSTR_TO_OBJ((char *)get_command_name(NULL, ea.cmdidx))); - } - PUT(result, "line1", INTEGER_OBJ(ea.line1)); - PUT(result, "line2", INTEGER_OBJ(ea.line2)); - PUT(result, "bang", BOOLEAN_OBJ(ea.forceit)); - PUT(result, "args", ARRAY_OBJ(args)); - - char nargs[2]; - if (ea.argt & EX_EXTRA) { - if (ea.argt & EX_NOSPC) { - if (ea.argt & EX_NEEDARG) { - nargs[0] = '1'; - } else { - nargs[0] = '?'; - } - } else if (ea.argt & EX_NEEDARG) { - nargs[0] = '+'; - } else { - nargs[0] = '*'; - } - } else { - nargs[0] = '0'; - } - nargs[1] = '\0'; - PUT(result, "nargs", CSTR_TO_OBJ(nargs)); - - const char *addr; - switch (ea.addr_type) { - case ADDR_LINES: - addr = "line"; - break; - case ADDR_ARGUMENTS: - addr = "arg"; - break; - case ADDR_BUFFERS: - addr = "buf"; - break; - case ADDR_LOADED_BUFFERS: - addr = "load"; - break; - case ADDR_WINDOWS: - addr = "win"; - break; - case ADDR_TABS: - addr = "tab"; - break; - case ADDR_QUICKFIX: - addr = "qf"; - break; - case ADDR_NONE: - addr = "none"; - break; - default: - addr = "?"; - break; - } - PUT(result, "addr", CSTR_TO_OBJ(addr)); - PUT(result, "nextcmd", CSTR_TO_OBJ((char *)ea.nextcmd)); - - Dictionary mods = ARRAY_DICT_INIT; - PUT(mods, "silent", BOOLEAN_OBJ(cmdinfo.silent)); - PUT(mods, "emsg_silent", BOOLEAN_OBJ(cmdinfo.emsg_silent)); - PUT(mods, "sandbox", BOOLEAN_OBJ(cmdinfo.sandbox)); - PUT(mods, "noautocmd", BOOLEAN_OBJ(cmdinfo.noautocmd)); - PUT(mods, "tab", INTEGER_OBJ(cmdinfo.cmdmod.tab)); - PUT(mods, "verbose", INTEGER_OBJ(cmdinfo.verbose)); - PUT(mods, "browse", BOOLEAN_OBJ(cmdinfo.cmdmod.browse)); - PUT(mods, "confirm", BOOLEAN_OBJ(cmdinfo.cmdmod.confirm)); - PUT(mods, "hide", BOOLEAN_OBJ(cmdinfo.cmdmod.hide)); - PUT(mods, "keepalt", BOOLEAN_OBJ(cmdinfo.cmdmod.keepalt)); - PUT(mods, "keepjumps", BOOLEAN_OBJ(cmdinfo.cmdmod.keepjumps)); - PUT(mods, "keepmarks", BOOLEAN_OBJ(cmdinfo.cmdmod.keepmarks)); - PUT(mods, "keeppatterns", BOOLEAN_OBJ(cmdinfo.cmdmod.keeppatterns)); - PUT(mods, "lockmarks", BOOLEAN_OBJ(cmdinfo.cmdmod.lockmarks)); - PUT(mods, "noswapfile", BOOLEAN_OBJ(cmdinfo.cmdmod.noswapfile)); - PUT(mods, "vertical", BOOLEAN_OBJ(cmdinfo.cmdmod.split & WSP_VERT)); - - const char *split; - if (cmdinfo.cmdmod.split & WSP_BOT) { - split = "botright"; - } else if (cmdinfo.cmdmod.split & WSP_TOP) { - split = "topleft"; - } else if (cmdinfo.cmdmod.split & WSP_BELOW) { - split = "belowright"; - } else if (cmdinfo.cmdmod.split & WSP_ABOVE) { - split = "aboveleft"; - } else { - split = ""; - } - PUT(mods, "split", CSTR_TO_OBJ(split)); - - PUT(result, "mods", DICTIONARY_OBJ(mods)); - - Dictionary magic = ARRAY_DICT_INIT; - PUT(magic, "file", BOOLEAN_OBJ(cmdinfo.magic.file)); - PUT(magic, "bar", BOOLEAN_OBJ(cmdinfo.magic.bar)); - PUT(result, "magic", DICTIONARY_OBJ(magic)); -end: - xfree(cmdline); - return result; -} diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 40ac0b8b64..acd89119f9 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -16,6 +16,7 @@ #include "nvim/ex_cmds2.h" #include "nvim/viml/parser/expressions.h" #include "nvim/viml/parser/parser.h" +#include "nvim/window.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/vimscript.c.generated.h" @@ -736,3 +737,231 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E viml_parser_destroy(&pstate); return ret; } + +/// Parse command line. +/// +/// Doesn't check the validity of command arguments. +/// +/// @param str Command line string to parse. Cannot contain "\n". +/// @param opts Optional parameters. Reserved for future use. +/// @param[out] err Error details, if any. +/// @return Dictionary containing command information, with these keys: +/// - cmd: (string) Command name. +/// - range: (number) Number of items in the command |<range>|. Can be 0, 1 or 2. +/// - line1: (number) Starting line of command |<range>|. -1 if command cannot take a range. +/// |<line1>| +/// - line2: (number) Final line of command |<range>|. -1 if command cannot take a range. +/// |<line2>| +/// - count: (number) Any |<count>| that was supplied to the command. -1 if command cannot +/// take a count. +/// - reg: (number) The optional command |<register>|, if specified. Empty string if not +/// specified or if command cannot take a register. +/// - bang: (boolean) Whether command contains a |<bang>| (!) modifier. +/// - args: (array) Command arguments. +/// - addr: (string) Value of |:command-addr|. Uses short name. +/// - nargs: (string) Value of |:command-nargs|. +/// - nextcmd: (string) Next command if there are multiple commands separated by a |:bar|. +/// Empty if there isn't a next command. +/// - magic: (dictionary) Which characters have special meaning in the command arguments. +/// - file: (boolean) The command expands filenames. Which means characters such as "%", +/// "#" and wildcards are expanded. +/// - bar: (boolean) The "|" character is treated as a command separator and the double +/// quote character (\") is treated as the start of a comment. +/// - mods: (dictionary) |:command-modifiers|. +/// - silent: (boolean) |:silent|. +/// - emsg_silent: (boolean) |:silent!|. +/// - sandbox: (boolean) |:sandbox|. +/// - noautocmd: (boolean) |:noautocmd|. +/// - browse: (boolean) |:browse|. +/// - confirm: (boolean) |:confirm|. +/// - hide: (boolean) |:hide|. +/// - keepalt: (boolean) |:keepalt|. +/// - keepjumps: (boolean) |:keepjumps|. +/// - keepmarks: (boolean) |:keepmarks|. +/// - keeppatterns: (boolean) |:keeppatterns|. +/// - lockmarks: (boolean) |:lockmarks|. +/// - noswapfile: (boolean) |:noswapfile|. +/// - tab: (integer) |:tab|. +/// - verbose: (integer) |:verbose|. -1 when omitted. +/// - vertical: (boolean) |:vertical|. +/// - split: (string) Split modifier string, is an empty string when there's no split +/// modifier. If there is a split modifier it can be one of: +/// - "aboveleft": |:aboveleft|. +/// - "belowright": |:belowright|. +/// - "topleft": |:topleft|. +/// - "botright": |:botright|. +Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) + FUNC_API_SINCE(10) FUNC_API_FAST +{ + Dictionary result = ARRAY_DICT_INIT; + + if (opts.size > 0) { + api_set_error(err, kErrorTypeValidation, "opts dict isn't empty"); + return result; + } + + // Parse command line + exarg_T ea; + CmdParseInfo cmdinfo; + char_u *cmdline = (char_u *)string_to_cstr(str); + + if (!parse_cmdline(cmdline, &ea, &cmdinfo)) { + api_set_error(err, kErrorTypeException, "Error while parsing command line"); + goto end; + } + + // Parse arguments + Array args = ARRAY_DICT_INIT; + size_t length = STRLEN(ea.arg); + + // For nargs = 1 or '?', pass the entire argument list as a single argument, + // 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))); + } + } else { + size_t end = 0; + size_t len = 0; + char *buf = xcalloc(length, sizeof(char)); + bool done = false; + + while (!done) { + done = uc_split_args_iter((char_u *)ea.arg, length, &end, buf, &len); + if (len > 0) { + ADD(args, STRING_OBJ(cstrn_to_string(buf, len))); + } + } + + xfree(buf); + } + + ucmd_T *cmd = NULL; + if (ea.cmdidx == CMD_USER) { + cmd = USER_CMD(ea.useridx); + } else if (ea.cmdidx == CMD_USER_BUF) { + cmd = USER_CMD_GA(&curbuf->b_ucmds, ea.useridx); + } + + if (cmd != NULL) { + PUT(result, "cmd", CSTR_TO_OBJ((char *)cmd->uc_name)); + } else { + PUT(result, "cmd", CSTR_TO_OBJ((char *)get_command_name(NULL, ea.cmdidx))); + } + + PUT(result, "range", INTEGER_OBJ(ea.addr_count)); + PUT(result, "line1", INTEGER_OBJ((ea.argt & EX_RANGE) ? ea.line1 : -1)); + PUT(result, "line2", INTEGER_OBJ((ea.argt & EX_RANGE) ? ea.line2 : -1)); + + if (ea.argt & EX_COUNT) { + if (ea.addr_count > 0 || cmd == NULL) { + PUT(result, "count", INTEGER_OBJ(ea.line2)); + } else { + PUT(result, "count", INTEGER_OBJ(cmd->uc_def)); + } + } else { + PUT(result, "count", INTEGER_OBJ(-1)); + } + + char reg[2]; + reg[0] = (char)ea.regname; + reg[1] = '\0'; + PUT(result, "reg", CSTR_TO_OBJ(reg)); + + PUT(result, "bang", BOOLEAN_OBJ(ea.forceit)); + PUT(result, "args", ARRAY_OBJ(args)); + + char nargs[2]; + if (ea.argt & EX_EXTRA) { + if (ea.argt & EX_NOSPC) { + if (ea.argt & EX_NEEDARG) { + nargs[0] = '1'; + } else { + nargs[0] = '?'; + } + } else if (ea.argt & EX_NEEDARG) { + nargs[0] = '+'; + } else { + nargs[0] = '*'; + } + } else { + nargs[0] = '0'; + } + nargs[1] = '\0'; + PUT(result, "nargs", CSTR_TO_OBJ(nargs)); + + const char *addr; + switch (ea.addr_type) { + case ADDR_LINES: + addr = "line"; + break; + case ADDR_ARGUMENTS: + addr = "arg"; + break; + case ADDR_BUFFERS: + addr = "buf"; + break; + case ADDR_LOADED_BUFFERS: + addr = "load"; + break; + case ADDR_WINDOWS: + addr = "win"; + break; + case ADDR_TABS: + addr = "tab"; + break; + case ADDR_QUICKFIX: + addr = "qf"; + break; + case ADDR_NONE: + addr = "none"; + break; + default: + addr = "?"; + break; + } + PUT(result, "addr", CSTR_TO_OBJ(addr)); + PUT(result, "nextcmd", CSTR_TO_OBJ((char *)ea.nextcmd)); + + Dictionary mods = ARRAY_DICT_INIT; + PUT(mods, "silent", BOOLEAN_OBJ(cmdinfo.silent)); + PUT(mods, "emsg_silent", BOOLEAN_OBJ(cmdinfo.emsg_silent)); + PUT(mods, "sandbox", BOOLEAN_OBJ(cmdinfo.sandbox)); + PUT(mods, "noautocmd", BOOLEAN_OBJ(cmdinfo.noautocmd)); + PUT(mods, "tab", INTEGER_OBJ(cmdinfo.cmdmod.tab)); + PUT(mods, "verbose", INTEGER_OBJ(cmdinfo.verbose)); + PUT(mods, "browse", BOOLEAN_OBJ(cmdinfo.cmdmod.browse)); + PUT(mods, "confirm", BOOLEAN_OBJ(cmdinfo.cmdmod.confirm)); + PUT(mods, "hide", BOOLEAN_OBJ(cmdinfo.cmdmod.hide)); + PUT(mods, "keepalt", BOOLEAN_OBJ(cmdinfo.cmdmod.keepalt)); + PUT(mods, "keepjumps", BOOLEAN_OBJ(cmdinfo.cmdmod.keepjumps)); + PUT(mods, "keepmarks", BOOLEAN_OBJ(cmdinfo.cmdmod.keepmarks)); + PUT(mods, "keeppatterns", BOOLEAN_OBJ(cmdinfo.cmdmod.keeppatterns)); + PUT(mods, "lockmarks", BOOLEAN_OBJ(cmdinfo.cmdmod.lockmarks)); + PUT(mods, "noswapfile", BOOLEAN_OBJ(cmdinfo.cmdmod.noswapfile)); + PUT(mods, "vertical", BOOLEAN_OBJ(cmdinfo.cmdmod.split & WSP_VERT)); + + const char *split; + if (cmdinfo.cmdmod.split & WSP_BOT) { + split = "botright"; + } else if (cmdinfo.cmdmod.split & WSP_TOP) { + split = "topleft"; + } else if (cmdinfo.cmdmod.split & WSP_BELOW) { + split = "belowright"; + } else if (cmdinfo.cmdmod.split & WSP_ABOVE) { + split = "aboveleft"; + } else { + split = ""; + } + PUT(mods, "split", CSTR_TO_OBJ(split)); + + PUT(result, "mods", DICTIONARY_OBJ(mods)); + + Dictionary magic = ARRAY_DICT_INIT; + PUT(magic, "file", BOOLEAN_OBJ(cmdinfo.magic.file)); + PUT(magic, "bar", BOOLEAN_OBJ(cmdinfo.magic.bar)); + PUT(result, "magic", DICTIONARY_OBJ(magic)); +end: + xfree(cmdline); + return result; +} |