diff options
| author | Sebastian Witte <woozletoff@gmail.com> | 2018-05-02 23:38:18 +0200 | 
|---|---|---|
| committer | Justin M. Keyes <justinkz@gmail.com> | 2018-05-06 14:38:26 +0200 | 
| commit | 124275dd58ae998decbc8891f9feb7e239a8a7e1 (patch) | |
| tree | c7af4489a1984eed614c35a9ce6ee1022e39b0eb /src/nvim/api/vim.c | |
| parent | f46f138fb6882ad98ed66fc6d4fa24fd6a97aeae (diff) | |
| download | rneovim-124275dd58ae998decbc8891f9feb7e239a8a7e1.tar.gz rneovim-124275dd58ae998decbc8891f9feb7e239a8a7e1.tar.bz2 rneovim-124275dd58ae998decbc8891f9feb7e239a8a7e1.zip  | |
API: nvim_call_dict_function #3032
Diffstat (limited to 'src/nvim/api/vim.c')
| -rw-r--r-- | src/nvim/api/vim.c | 106 | 
1 files changed, 105 insertions, 1 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index af3d379870..dabbfe1621 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -298,6 +298,18 @@ Object nvim_eval(String expr, Error *err)  Object nvim_call_function(String fname, Array args, Error *err)    FUNC_API_SINCE(1)  { +  return call_function(fname, args, NULL, err); +} + +/// Call an internal or user defined function. +/// +/// @param fname Function name +/// @param args Function arguments +/// @param self `self` dict (only required for dict functions) +/// @param[out] err Details of an error that may have occurred +/// @return Result of the function call +static Object call_function(String fname, Array args, dict_T *self, Error *err) +{    Object rv = OBJECT_INIT;    if (args.size > MAX_FUNC_ARGS) {      api_set_error(err, kErrorTypeValidation, @@ -321,7 +333,7 @@ Object nvim_call_function(String fname, Array args, Error *err)    int r = call_func((char_u *)fname.data, (int)fname.size,                      &rettv, (int)args.size, vim_args, NULL,                      curwin->w_cursor.lnum, curwin->w_cursor.lnum, &dummy, -                    true, NULL, NULL); +                    true, NULL, self);    if (r == FAIL) {      api_set_error(err, kErrorTypeException, "Error calling function.");    } @@ -356,6 +368,98 @@ Object nvim_execute_lua(String code, Array args, Error *err)    return executor_exec_lua_api(code, args, err);  } +/// Call the given dict function with the given arguments stored in an array. +/// +/// @param self |self| dict or string expression evaluating to a dict +/// @param internal true if the function is stored in the self-dict +/// @param fnname Function to call +/// @param args Functions arguments packed in an Array +/// @param[out] err Details of an error that may have occurred +/// @return Result of the function call +Object nvim_call_dict_function(Object self, Boolean internal, String fnname, +                               Array args, Error *err) +  FUNC_API_SINCE(4) +{ +  Object rv = OBJECT_INIT; + +  typval_T rettv; +  bool mustfree = false; +  switch (self.type) { +    case kObjectTypeString: { +      try_start(); +      if (eval0((char_u *)self.data.string.data, &rettv, NULL, true) == FAIL) { +        api_set_error(err, kErrorTypeException, +                      "Failed to evaluate self expression"); +      } +      if (try_end(err)) { +        return rv; +      } +      // Evaluation of the string arg created a new dict or increased the +      // refcount of a dict. Not necessary for a dict inside a RPC Object. +      mustfree = true; +      break; +    } +    case kObjectTypeDictionary: { +      if (internal) { +        api_set_error(err, kErrorTypeValidation, +                      "Funcrefs are not supported for RPC dicts"); +        return rv; +      } else if (!object_to_vim(self, &rettv, err)) { +        tv_clear(&rettv); +        return rv; +      } +      break; +    } +    default: { +      api_set_error(err, kErrorTypeValidation, +                    "self argument must be String or Dictionary"); +      return rv; +    } +  } +  dict_T *self_dict = rettv.vval.v_dict; +  if (rettv.v_type != VAR_DICT || !self_dict) { +    api_set_error(err, kErrorTypeValidation, +                  "Referenced self-dict does not exist"); +    goto end; +  } + +  // Set the function to call +  String func = STRING_INIT; +  if (internal /* && self.type == kObjectTypeString */) { +    dictitem_T *const di = tv_dict_find(self_dict, fnname.data, +                                        (ptrdiff_t)fnname.size); +    if (di == NULL) { +      api_set_error(err, kErrorTypeValidation, +                    "Function not found in self-dict"); +      goto end; +    } +    if (di->di_tv.v_type != VAR_STRING) { +      api_set_error(err, kErrorTypeValidation, +                    "Value inside self-dict is not a valid function name"); +      goto end; +    } +    func.data = (char *)di->di_tv.vval.v_string; +    func.size = strlen(func.data); +  } else { +    func.data = fnname.data; +    func.size = fnname.size; +  } +  if (!func.data || func.size < 1) { +    api_set_error(err, kErrorTypeValidation, +                  "Invalid (empty) function name"); +    goto end; +  } + +  // Finally try to call the function +  rv = call_function(func, args, self_dict, err); +end: +  if (mustfree) { +    tv_clear(&rettv); +  } + +  return rv; +} +  /// Calculates the number of display cells occupied by `text`.  /// <Tab> counts as one cell.  ///  | 
