mirror of
https://github.com/neovim/neovim.git
synced 2025-09-11 13:58:18 +00:00
refactor(api): move command related API to separate file
This commit is contained in:
@@ -959,7 +959,6 @@ ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf, bool from_lua)
|
||||
return mappings;
|
||||
}
|
||||
|
||||
|
||||
/// Force obj to bool.
|
||||
/// If it fails, returns false and sets err
|
||||
/// @param obj The object to coerce to a boolean
|
||||
@@ -1108,212 +1107,6 @@ const char *get_default_stl_hl(win_T *wp, bool use_winbar)
|
||||
}
|
||||
}
|
||||
|
||||
void create_user_command(String name, Object command, Dict(user_command) *opts, int flags,
|
||||
Error *err)
|
||||
{
|
||||
uint32_t argt = 0;
|
||||
long def = -1;
|
||||
cmd_addr_T addr_type_arg = ADDR_NONE;
|
||||
int compl = EXPAND_NOTHING;
|
||||
char *compl_arg = NULL;
|
||||
char *rep = NULL;
|
||||
LuaRef luaref = LUA_NOREF;
|
||||
LuaRef compl_luaref = LUA_NOREF;
|
||||
LuaRef preview_luaref = LUA_NOREF;
|
||||
|
||||
if (!uc_validate_name(name.data)) {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid command name");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (mb_islower(name.data[0])) {
|
||||
api_set_error(err, kErrorTypeValidation, "'name' must begin with an uppercase letter");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (HAS_KEY(opts->range) && HAS_KEY(opts->count)) {
|
||||
api_set_error(err, kErrorTypeValidation, "'range' and 'count' are mutually exclusive");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (opts->nargs.type == kObjectTypeInteger) {
|
||||
switch (opts->nargs.data.integer) {
|
||||
case 0:
|
||||
// Default value, nothing to do
|
||||
break;
|
||||
case 1:
|
||||
argt |= EX_EXTRA | EX_NOSPC | EX_NEEDARG;
|
||||
break;
|
||||
default:
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'");
|
||||
goto err;
|
||||
}
|
||||
} else if (opts->nargs.type == kObjectTypeString) {
|
||||
if (opts->nargs.data.string.size > 1) {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'");
|
||||
goto err;
|
||||
}
|
||||
|
||||
switch (opts->nargs.data.string.data[0]) {
|
||||
case '*':
|
||||
argt |= EX_EXTRA;
|
||||
break;
|
||||
case '?':
|
||||
argt |= EX_EXTRA | EX_NOSPC;
|
||||
break;
|
||||
case '+':
|
||||
argt |= EX_EXTRA | EX_NEEDARG;
|
||||
break;
|
||||
default:
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'");
|
||||
goto err;
|
||||
}
|
||||
} else if (HAS_KEY(opts->nargs)) {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (HAS_KEY(opts->complete) && !argt) {
|
||||
api_set_error(err, kErrorTypeValidation, "'complete' used without 'nargs'");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (opts->range.type == kObjectTypeBoolean) {
|
||||
if (opts->range.data.boolean) {
|
||||
argt |= EX_RANGE;
|
||||
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'");
|
||||
goto err;
|
||||
}
|
||||
} else if (opts->range.type == kObjectTypeInteger) {
|
||||
argt |= EX_RANGE | EX_ZEROR;
|
||||
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;
|
||||
}
|
||||
|
||||
if (opts->count.type == kObjectTypeBoolean) {
|
||||
if (opts->count.data.boolean) {
|
||||
argt |= EX_COUNT | EX_ZEROR | EX_RANGE;
|
||||
addr_type_arg = ADDR_OTHER;
|
||||
def = 0;
|
||||
}
|
||||
} else if (opts->count.type == kObjectTypeInteger) {
|
||||
argt |= EX_COUNT | EX_ZEROR | EX_RANGE;
|
||||
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;
|
||||
}
|
||||
|
||||
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'");
|
||||
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)) {
|
||||
argt |= EX_BANG;
|
||||
} else if (ERROR_SET(err)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (api_object_to_bool(opts->bar, "bar", false, err)) {
|
||||
argt |= EX_TRLBAR;
|
||||
} else if (ERROR_SET(err)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (api_object_to_bool(opts->register_, "register", false, err)) {
|
||||
argt |= EX_REGSTR;
|
||||
} else if (ERROR_SET(err)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (api_object_to_bool(opts->keepscript, "keepscript", false, err)) {
|
||||
argt |= EX_KEEPSCRIPT;
|
||||
} else if (ERROR_SET(err)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
bool force = api_object_to_bool(opts->force, "force", true, err);
|
||||
if (ERROR_SET(err)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (opts->complete.type == kObjectTypeLuaRef) {
|
||||
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'");
|
||||
goto err;
|
||||
}
|
||||
} else if (HAS_KEY(opts->complete)) {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid value for 'complete'");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (opts->preview.type == kObjectTypeLuaRef) {
|
||||
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) {
|
||||
case kObjectTypeLuaRef:
|
||||
luaref = api_new_luaref(command.data.luaref);
|
||||
if (opts->desc.type == kObjectTypeString) {
|
||||
rep = opts->desc.data.string.data;
|
||||
} else {
|
||||
snprintf((char *)IObuff, IOSIZE, "<Lua function %d>", luaref);
|
||||
rep = (char *)IObuff;
|
||||
}
|
||||
break;
|
||||
case kObjectTypeString:
|
||||
rep = command.data.string.data;
|
||||
break;
|
||||
default:
|
||||
api_set_error(err, kErrorTypeValidation, "'command' must be a string or Lua function");
|
||||
goto err;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
err:
|
||||
NLUA_CLEAR_REF(luaref);
|
||||
NLUA_CLEAR_REF(compl_luaref);
|
||||
xfree(compl_arg);
|
||||
}
|
||||
|
||||
int find_sid(uint64_t channel_id)
|
||||
{
|
||||
switch (channel_id) {
|
||||
@@ -1343,136 +1136,3 @@ sctx_T api_set_sctx(uint64_t channel_id)
|
||||
}
|
||||
return old_current_sctx;
|
||||
}
|
||||
|
||||
/// Check if a string contains only whitespace characters.
|
||||
bool string_iswhite(String str)
|
||||
{
|
||||
for (size_t i = 0; i < str.size; i++) {
|
||||
if (!ascii_iswhite(str.data[i])) {
|
||||
// Found a non-whitespace character
|
||||
return false;
|
||||
} else if (str.data[i] == NUL) {
|
||||
// Terminate at first occurence of a NUL character
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Build cmdline string for command, used by `nvim_cmd()`.
|
||||
///
|
||||
/// @return OK or FAIL.
|
||||
void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdinfo, char **args,
|
||||
size_t argc)
|
||||
{
|
||||
StringBuilder cmdline = KV_INITIAL_VALUE;
|
||||
|
||||
// Add command modifiers
|
||||
if (cmdinfo->cmdmod.tab != 0) {
|
||||
kv_printf(cmdline, "%dtab ", cmdinfo->cmdmod.tab - 1);
|
||||
}
|
||||
if (cmdinfo->verbose != -1) {
|
||||
kv_printf(cmdline, "%ldverbose ", cmdinfo->verbose);
|
||||
}
|
||||
|
||||
if (cmdinfo->emsg_silent) {
|
||||
kv_concat(cmdline, "silent! ");
|
||||
} else if (cmdinfo->silent) {
|
||||
kv_concat(cmdline, "silent ");
|
||||
}
|
||||
|
||||
switch (cmdinfo->cmdmod.split & (WSP_ABOVE | WSP_BELOW | WSP_TOP | WSP_BOT)) {
|
||||
case WSP_ABOVE:
|
||||
kv_concat(cmdline, "aboveleft ");
|
||||
break;
|
||||
case WSP_BELOW:
|
||||
kv_concat(cmdline, "belowright ");
|
||||
break;
|
||||
case WSP_TOP:
|
||||
kv_concat(cmdline, "topleft ");
|
||||
break;
|
||||
case WSP_BOT:
|
||||
kv_concat(cmdline, "botright ");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#define CMDLINE_APPEND_IF(cond, str) \
|
||||
do { \
|
||||
if (cond) { \
|
||||
kv_concat(cmdline, str); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
CMDLINE_APPEND_IF(cmdinfo->cmdmod.split & WSP_VERT, "vertical ");
|
||||
CMDLINE_APPEND_IF(cmdinfo->sandbox, "sandbox ");
|
||||
CMDLINE_APPEND_IF(cmdinfo->noautocmd, "noautocmd ");
|
||||
CMDLINE_APPEND_IF(cmdinfo->cmdmod.browse, "browse ");
|
||||
CMDLINE_APPEND_IF(cmdinfo->cmdmod.confirm, "confirm ");
|
||||
CMDLINE_APPEND_IF(cmdinfo->cmdmod.hide, "hide ");
|
||||
CMDLINE_APPEND_IF(cmdinfo->cmdmod.keepalt, "keepalt ");
|
||||
CMDLINE_APPEND_IF(cmdinfo->cmdmod.keepjumps, "keepjumps ");
|
||||
CMDLINE_APPEND_IF(cmdinfo->cmdmod.keepmarks, "keepmarks ");
|
||||
CMDLINE_APPEND_IF(cmdinfo->cmdmod.keeppatterns, "keeppatterns ");
|
||||
CMDLINE_APPEND_IF(cmdinfo->cmdmod.lockmarks, "lockmarks ");
|
||||
CMDLINE_APPEND_IF(cmdinfo->cmdmod.noswapfile, "noswapfile ");
|
||||
#undef CMDLINE_APPEND_IF
|
||||
|
||||
// Command range / count.
|
||||
if (eap->argt & EX_RANGE) {
|
||||
if (eap->addr_count == 1) {
|
||||
kv_printf(cmdline, "%" PRIdLINENR, eap->line2);
|
||||
} else if (eap->addr_count > 1) {
|
||||
kv_printf(cmdline, "%" PRIdLINENR ",%" PRIdLINENR, eap->line1, eap->line2);
|
||||
eap->addr_count = 2; // Make sure address count is not greater than 2
|
||||
}
|
||||
}
|
||||
|
||||
// Keep the index of the position where command name starts, so eap->cmd can point to it.
|
||||
size_t cmdname_idx = cmdline.size;
|
||||
kv_printf(cmdline, "%s", eap->cmd);
|
||||
|
||||
// Command bang.
|
||||
if (eap->argt & EX_BANG && eap->forceit) {
|
||||
kv_printf(cmdline, "!");
|
||||
}
|
||||
|
||||
// Command register.
|
||||
if (eap->argt & EX_REGSTR && eap->regname) {
|
||||
kv_printf(cmdline, " %c", eap->regname);
|
||||
}
|
||||
|
||||
// Iterate through each argument and store the starting index and length of each argument
|
||||
size_t *argidx = xcalloc(argc, sizeof(size_t));
|
||||
eap->argc = argc;
|
||||
eap->arglens = xcalloc(argc, sizeof(size_t));
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
argidx[i] = cmdline.size + 1; // add 1 to account for the space.
|
||||
eap->arglens[i] = STRLEN(args[i]);
|
||||
kv_printf(cmdline, " %s", args[i]);
|
||||
}
|
||||
|
||||
// Now that all the arguments are appended, use the command index and argument indices to set the
|
||||
// values of eap->cmd, eap->arg and eap->args.
|
||||
eap->cmd = cmdline.items + cmdname_idx;
|
||||
eap->args = xcalloc(argc, sizeof(char *));
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
eap->args[i] = cmdline.items + argidx[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;
|
||||
|
||||
// Finally, make cmdlinep point to the cmdline string.
|
||||
*cmdlinep = cmdline.items;
|
||||
xfree(argidx);
|
||||
|
||||
// Replace, :make and :grep with 'makeprg' and 'grepprg'.
|
||||
char *p = replace_makeprg(eap, eap->arg, cmdlinep);
|
||||
if (p != eap->arg) {
|
||||
// If replace_makeprg modified the cmdline string, correct the argument pointers.
|
||||
assert(argc == 1);
|
||||
eap->arg = p;
|
||||
eap->args[0] = p;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user