aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval')
-rw-r--r--src/nvim/eval/funcs.c94
-rw-r--r--src/nvim/eval/userfunc.c96
2 files changed, 117 insertions, 73 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index da129c1170..5c22bf0f8f 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -28,6 +28,7 @@
#include "nvim/file_search.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
+#include "nvim/globals.h"
#include "nvim/if_cscope.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
@@ -1062,6 +1063,45 @@ static void f_charidx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = len > 0 ? len - 1 : 0;
}
+// "chdir(dir)" function
+static void f_chdir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ char_u *cwd;
+ CdScope scope = kCdScopeGlobal;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ if (argvars[0].v_type != VAR_STRING) {
+ // Returning an empty string means it failed.
+ // No error message, for historic reasons.
+ return;
+ }
+
+ // Return the current directory
+ cwd = xmalloc(MAXPATHL);
+ if (cwd != NULL) {
+ if (os_dirname(cwd, MAXPATHL) != FAIL) {
+#ifdef BACKSLASH_IN_FILENAME
+ slash_adjust(cwd);
+#endif
+ rettv->vval.v_string = vim_strsave(cwd);
+ }
+ xfree(cwd);
+ }
+
+ if (curwin->w_localdir != NULL) {
+ scope = kCdScopeWindow;
+ } else if (curtab->tp_localdir != NULL) {
+ scope = kCdScopeTabpage;
+ }
+
+ if (!changedir_func(argvars[0].vval.v_string, scope)) {
+ // Directory change failed
+ XFREE_CLEAR(rettv->vval.v_string);
+ }
+}
+
/*
* "cindent(lnum)" function
*/
@@ -3405,8 +3445,8 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// Numbers of the scope objects (window, tab) we want the working directory
// of. A `-1` means to skip this scope, a `0` means the current object.
int scope_number[] = {
- [kCdScopeWindow] = 0, // Number of window to look at.
- [kCdScopeTab ] = 0, // Number of tab to look at.
+ [kCdScopeWindow ] = 0, // Number of window to look at.
+ [kCdScopeTabpage] = 0, // Number of tab to look at.
};
char_u *cwd = NULL; // Current working directory to print
@@ -3449,8 +3489,8 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
// Find the tabpage by number
- if (scope_number[kCdScopeTab] > 0) {
- tp = find_tabpage(scope_number[kCdScopeTab]);
+ if (scope_number[kCdScopeTabpage] > 0) {
+ tp = find_tabpage(scope_number[kCdScopeTabpage]);
if (!tp) {
EMSG(_("E5000: Cannot find tab number."));
return;
@@ -3459,7 +3499,7 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// Find the window in `tp` by number, `NULL` if none.
if (scope_number[kCdScopeWindow] >= 0) {
- if (scope_number[kCdScopeTab] < 0) {
+ if (scope_number[kCdScopeTabpage] < 0) {
EMSG(_("E5001: Higher scope cannot be -1 if lower scope is >= 0."));
return;
}
@@ -3483,7 +3523,7 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
break;
}
FALLTHROUGH;
- case kCdScopeTab:
+ case kCdScopeTabpage:
assert(tp);
from = tp->tp_localdir;
if (from) {
@@ -4612,8 +4652,8 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// Numbers of the scope objects (window, tab) we want the working directory
// of. A `-1` means to skip this scope, a `0` means the current object.
int scope_number[] = {
- [kCdScopeWindow] = 0, // Number of window to look at.
- [kCdScopeTab ] = 0, // Number of tab to look at.
+ [kCdScopeWindow ] = 0, // Number of window to look at.
+ [kCdScopeTabpage] = 0, // Number of tab to look at.
};
tabpage_T *tp = curtab; // The tabpage to look at.
@@ -4651,8 +4691,8 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
// Find the tabpage by number
- if (scope_number[kCdScopeTab] > 0) {
- tp = find_tabpage(scope_number[kCdScopeTab]);
+ if (scope_number[kCdScopeTabpage] > 0) {
+ tp = find_tabpage(scope_number[kCdScopeTabpage]);
if (!tp) {
EMSG(_("E5000: Cannot find tab number."));
return;
@@ -4661,7 +4701,7 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// Find the window in `tp` by number, `NULL` if none.
if (scope_number[kCdScopeWindow] >= 0) {
- if (scope_number[kCdScopeTab] < 0) {
+ if (scope_number[kCdScopeTabpage] < 0) {
EMSG(_("E5001: Higher scope cannot be -1 if lower scope is >= 0."));
return;
}
@@ -4680,7 +4720,7 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
assert(win);
rettv->vval.v_number = win->w_localdir ? 1 : 0;
break;
- case kCdScopeTab:
+ case kCdScopeTabpage:
assert(tp);
rettv->vval.v_number = tp->tp_localdir ? 1 : 0;
break;
@@ -8480,20 +8520,22 @@ static void f_searchpairpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_list_append_number(rettv->vval.v_list, (varnumber_T)col);
}
-/*
- * Search for a start/middle/end thing.
- * Used by searchpair(), see its documentation for the details.
- * Returns 0 or -1 for no match,
- */
-long do_searchpair(const char *spat, // start pattern
- const char *mpat, // middle pattern
- const char *epat, // end pattern
- int dir, // BACKWARD or FORWARD
- const typval_T *skip, // skip expression
- int flags, // SP_SETPCMARK and other SP_ values
- pos_T *match_pos, linenr_T lnum_stop, // stop at this line if not zero
- long time_limit // stop after this many msec
- )
+/// Search for a start/middle/end thing.
+/// Used by searchpair(), see its documentation for the details.
+///
+/// @param spat start pattern
+/// @param mpat middle pattern
+/// @param epat end pattern
+/// @param dir BACKWARD or FORWARD
+/// @param skip skip expression
+/// @param flags SP_SETPCMARK and other SP_ values
+/// @param lnum_stop stop at this line if not zero
+/// @param time_limit stop after this many msec
+///
+/// @returns 0 or -1 for no match,
+long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir,
+ const typval_T *skip, int flags, pos_T *match_pos, linenr_T lnum_stop,
+ long time_limit)
FUNC_ATTR_NONNULL_ARG(1, 2, 3)
{
char_u *save_cpo;
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 657777d7db..f4393a79dc 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -402,15 +402,15 @@ void emsg_funcname(char *ermsg, const char_u *name)
}
}
-/*
- * Allocate a variable for the result of a function.
- * Return OK or FAIL.
- */
-int get_func_tv(const char_u *name, // name of the function
- int len, // length of "name" or -1 to use strlen()
- typval_T *rettv, char_u **arg, // argument, pointing to the '('
- funcexe_T *funcexe // various values
- )
+/// Allocate a variable for the result of a function.
+///
+/// @param name name of the function
+/// @param len length of "name" or -1 to use strlen()
+/// @param arg argument, pointing to the '('
+/// @param funcexe various values
+///
+/// @return OK or FAIL.
+int get_func_tv(const char_u *name, int len, typval_T *rettv, char_u **arg, funcexe_T *funcexe)
{
char_u *argp;
int ret = OK;
@@ -1436,17 +1436,18 @@ static void argv_add_base(typval_T *const basetv, typval_T **const argvars, int
/// Call a function with its resolved parameters
///
+/// @param funcname name of the function
+/// @param len length of "name" or -1 to use strlen()
+/// @param rettv [out] value goes here
+/// @param argcount_in number of "argvars"
+/// @param argvars_in vars for arguments, must have "argcount" PLUS ONE elements!
+/// @param funcexe more arguments
+///
/// @return FAIL if function cannot be called, else OK (even if an error
/// occurred while executing the function! Set `msg_list` to capture
/// the error, see do_cmdline()).
-int call_func(const char_u *funcname, // name of the function
- int len, // length of "name" or -1 to use strlen()
- typval_T *rettv, // [out] value goes here
- int argcount_in, // number of "argvars"
- typval_T *argvars_in, // vars for arguments, must have "argcount"
- // PLUS ONE elements!
- funcexe_T *funcexe // more arguments
- )
+int call_func(const char_u *funcname, int len, typval_T *rettv, int argcount_in,
+ typval_T *argvars_in, funcexe_T *funcexe)
FUNC_ATTR_NONNULL_ARG(1, 3, 5, 6)
{
int ret = FAIL;
@@ -1690,11 +1691,12 @@ static void list_func_head(ufunc_T *fp, int indent, bool force)
/// TFN_NO_DEREF: do not dereference a Funcref
/// Advances "pp" to just after the function name (if no error).
///
+/// @param skip only find the end, don't evaluate
+/// @param fdp return: info about dictionary used
+/// @param partial return: partial of a FuncRef
+///
/// @return the function name in allocated memory, or NULL for failure.
-char_u *trans_function_name(char_u **pp, bool skip, // only find the end, don't evaluate
- int flags, funcdict_T *fdp, // return: info about dictionary used
- partial_T **partial // return: partial of a FuncRef
- )
+char_u *trans_function_name(char_u **pp, bool skip, int flags, funcdict_T *fdp, partial_T **partial)
FUNC_ATTR_NONNULL_ARG(1)
{
char_u *name = NULL;
@@ -1709,8 +1711,8 @@ char_u *trans_function_name(char_u **pp, bool skip, // only
}
start = *pp;
- /* Check for hard coded <SNR>: already translated function ID (from a user
- * command). */
+ // Check for hard coded <SNR>: already translated function ID (from a user
+ // command).
if ((*pp)[0] == K_SPECIAL && (*pp)[1] == KS_EXTRA
&& (*pp)[2] == (int)KE_SNR) {
*pp += 3;
@@ -2032,8 +2034,8 @@ void ex_function(exarg_T *eap)
}
}
- /* An error in a function call during evaluation of an expression in magic
- * braces should not cause the function not to be defined. */
+ // An error in a function call during evaluation of an expression in magic
+ // braces should not cause the function not to be defined.
saved_did_emsg = did_emsg;
did_emsg = FALSE;
@@ -2105,8 +2107,8 @@ void ex_function(exarg_T *eap)
ga_init(&newlines, (int)sizeof(char_u *), 3);
if (!eap->skip) {
- /* Check the name of the function. Unless it's a dictionary function
- * (that we are overwriting). */
+ // Check the name of the function. Unless it's a dictionary function
+ // (that we are overwriting).
if (name != NULL) {
arg = name;
} else {
@@ -2164,8 +2166,8 @@ void ex_function(exarg_T *eap)
}
}
- /* When there is a line break use what follows for the function body.
- * Makes 'exe "func Test()\n...\nendfunc"' work. */
+ // When there is a line break use what follows for the function body.
+ // Makes 'exe "func Test()\n...\nendfunc"' work.
if (*p == '\n') {
line_arg = p + 1;
} else if (*p != NUL && *p != '"' && !eap->skip && !did_emsg) {
@@ -2176,9 +2178,9 @@ void ex_function(exarg_T *eap)
* Read the body of the function, until ":endfunction" is found.
*/
if (KeyTyped) {
- /* Check if the function already exists, don't let the user type the
- * whole function before telling him it doesn't work! For a script we
- * need to skip the body to be able to find what follows. */
+ // Check if the function already exists, don't let the user type the
+ // whole function before telling him it doesn't work! For a script we
+ // need to skip the body to be able to find what follows.
if (!eap->skip && !eap->forceit) {
if (fudi.fd_dict != NULL && fudi.fd_newkey == NULL) {
EMSG(_(e_funcdict));
@@ -2305,8 +2307,8 @@ void ex_function(exarg_T *eap)
break;
}
- /* Increase indent inside "if", "while", "for" and "try", decrease
- * at "end". */
+ // Increase indent inside "if", "while", "for" and "try", decrease
+ // at "end".
if (indent > 2 && STRNCMP(p, "end", 3) == 0) {
indent -= 2;
} else if (STRNCMP(p, "if", 2) == 0
@@ -2421,8 +2423,8 @@ void ex_function(exarg_T *eap)
}
}
- /* Don't define the function when skipping commands or when an error was
- * detected. */
+ // Don't define the function when skipping commands or when an error was
+ // detected.
if (eap->skip || did_emsg) {
goto erret;
}
@@ -2640,8 +2642,8 @@ bool function_exists(const char *const name, bool no_deref)
NULL);
nm = skipwhite(nm);
- /* Only accept "funcname", "funcname ", "funcname (..." and
- * "funcname(...", not "funcname!...". */
+ // Only accept "funcname", "funcname ", "funcname (..." and
+ // "funcname(...", not "funcname!...".
if (p != NULL && (*nm == NUL || *nm == '(')) {
n = translated_function_exists(p);
}
@@ -2903,9 +2905,9 @@ void ex_return(exarg_T *eap)
}
}
- /* When skipping or the return gets pending, advance to the next command
- * in this line (!returning). Otherwise, ignore the rest of the line.
- * Following lines will be ignored by get_func_line(). */
+ // When skipping or the return gets pending, advance to the next command
+ // in this line (!returning). Otherwise, ignore the rest of the line.
+ // Following lines will be ignored by get_func_line().
if (returning) {
eap->nextcmd = NULL;
} else if (eap->nextcmd == NULL) { // no argument
@@ -3098,9 +3100,9 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv)
}
if (reanimate) {
- /* The pending return value could be overwritten by a ":return"
- * without argument in a finally clause; reset the default
- * return value. */
+ // The pending return value could be overwritten by a ":return"
+ // without argument in a finally clause; reset the default
+ // return value.
current_funccal->rettv->v_type = VAR_NUMBER;
current_funccal->rettv->vval.v_number = 0;
}
@@ -3109,9 +3111,9 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv)
} else {
current_funccal->returned = TRUE;
- /* If the return is carried out now, store the return value. For
- * a return immediately after reanimation, the value is already
- * there. */
+ // If the return is carried out now, store the return value. For
+ // a return immediately after reanimation, the value is already
+ // there.
if (!reanimate && rettv != NULL) {
tv_clear(current_funccal->rettv);
*current_funccal->rettv = *(typval_T *)rettv;