aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/api')
-rw-r--r--src/nvim/api/autocmd.c46
-rw-r--r--src/nvim/api/extmark.c14
-rw-r--r--src/nvim/api/keysets.lua1
-rw-r--r--src/nvim/api/ui.h1
-rw-r--r--src/nvim/api/ui_events.in.h4
-rw-r--r--src/nvim/api/vim.c202
-rw-r--r--src/nvim/api/vimscript.c229
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;
+}