diff options
Diffstat (limited to 'src/nvim/eval')
-rw-r--r-- | src/nvim/eval/funcs.c | 94 | ||||
-rw-r--r-- | src/nvim/eval/userfunc.c | 96 |
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; |