aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api/private/helpers.c
diff options
context:
space:
mode:
authorGregory Anders <greg@gpanders.com>2021-12-22 11:40:21 -0700
committerGregory Anders <greg@gpanders.com>2021-12-28 14:08:44 -0700
commiteff11b3c3fcb9aa777deafb0a33b1523aa05b603 (patch)
treeff517e6b769f8604a1a6f24826405594859ec95b /src/nvim/api/private/helpers.c
parent9804a2870f6f308f788f939f52958e3fbd2adaac (diff)
downloadrneovim-eff11b3c3fcb9aa777deafb0a33b1523aa05b603.tar.gz
rneovim-eff11b3c3fcb9aa777deafb0a33b1523aa05b603.tar.bz2
rneovim-eff11b3c3fcb9aa777deafb0a33b1523aa05b603.zip
feat(api): implement nvim_{add,del}_user_command
Add support for adding and removing custom user commands with the Nvim API.
Diffstat (limited to 'src/nvim/api/private/helpers.c')
-rw-r--r--src/nvim/api/private/helpers.c185
1 files changed, 185 insertions, 0 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 9b407eab8b..962fce6952 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -961,6 +961,10 @@ Object copy_object(Object obj)
case kObjectTypeDictionary:
return DICTIONARY_OBJ(copy_dictionary(obj.data.dictionary));
+
+ case kObjectTypeLuaRef:
+ return LUAREF_OBJ(api_new_luaref(obj.data.luaref));
+
default:
abort();
}
@@ -1342,3 +1346,184 @@ const char *get_default_stl_hl(win_T *wp)
return "StatusLineNC";
}
}
+
+void add_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;
+
+ 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((char_u *)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;
+ }
+
+ bool force = api_object_to_bool(opts->force, "force", false, 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((char_u *)opts->complete.data.string.data,
+ (int)opts->complete.data.string.size, &compl, &argt,
+ (char_u **)&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;
+ }
+
+ 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((char_u *)name.data, name.size, (char_u *)rep, argt, def, flags,
+ compl, (char_u *)compl_arg, compl_luaref, addr_type_arg, luaref,
+ force) != OK) {
+ api_set_error(err, kErrorTypeException, "Failed to create user command");
+ goto err;
+ }
+
+ return;
+
+err:
+ NLUA_CLEAR_REF(luaref);
+ NLUA_CLEAR_REF(compl_luaref);
+}