mirror of
https://github.com/vim/vim.git
synced 2025-09-26 04:04:07 -04:00
patch 7.4.2008
Problem: evalcmd() has a confusing name. Solution: Rename to execute(). Make silent optional. Support a list of commands.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
*eval.txt* For Vim version 7.4. Last change: 2016 Jul 06
|
||||
*eval.txt* For Vim version 7.4. Last change: 2016 Jul 09
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -1961,9 +1961,9 @@ diff_hlID({lnum}, {col}) Number diff highlighting at {lnum}/{col}
|
||||
empty({expr}) Number |TRUE| if {expr} is empty
|
||||
escape({string}, {chars}) String escape {chars} in {string} with '\'
|
||||
eval({string}) any evaluate {string} into its value
|
||||
evalcmd({command}) String execute {command} and get the output
|
||||
eventhandler() Number |TRUE| if inside an event handler
|
||||
executable({expr}) Number 1 if executable {expr} exists
|
||||
execute({command}) String execute {command} and get the output
|
||||
exepath({expr}) String full path of the command {expr}
|
||||
exists({expr}) Number |TRUE| if {expr} exists
|
||||
extend({expr1}, {expr2} [, {expr3}])
|
||||
@@ -3232,15 +3232,6 @@ eval({string}) Evaluate {string} and return the result. Especially useful to
|
||||
them. Also works for |Funcref|s that refer to existing
|
||||
functions.
|
||||
|
||||
evalcmd({command}) *evalcmd()*
|
||||
Execute Ex {command} and return the output as a string. This
|
||||
is equivalent to: >
|
||||
redir => var
|
||||
{command}
|
||||
redir END
|
||||
< To get a list of lines use: >
|
||||
split(evalcmd(cmd), "\n")
|
||||
|
||||
eventhandler() *eventhandler()*
|
||||
Returns 1 when inside an event handler. That is that Vim got
|
||||
interrupted while waiting for the user to type a character,
|
||||
@@ -3271,6 +3262,31 @@ executable({expr}) *executable()*
|
||||
0 does not exist
|
||||
-1 not implemented on this system
|
||||
|
||||
execute({command} [, {silent}]) *execute()*
|
||||
Execute an Ex command or commands and return the output as a
|
||||
string.
|
||||
{command} can be a string or a List. In case of a List the
|
||||
lines are executed one by one.
|
||||
This is equivalent to: >
|
||||
redir => var
|
||||
{command}
|
||||
redir END
|
||||
<
|
||||
The optional {silent} argument can have these values:
|
||||
"" no `:silent` used
|
||||
"silent" `:silent` used
|
||||
"silent!" `:silent!` used
|
||||
The default is 'silent'. Note that with "silent!", unlike
|
||||
`:redir`, error messages are dropped.
|
||||
*E930*
|
||||
It is not possible to use `:redir` anywhere in {command}.
|
||||
|
||||
To get a list of lines use |split()| on the result: >
|
||||
split(evalcmd('args'), "\n")
|
||||
|
||||
< When used recursively the output of the recursive call is not
|
||||
included in the output of the higher level call.
|
||||
|
||||
exepath({expr}) *exepath()*
|
||||
If {expr} is an executable and is either an absolute path, a
|
||||
relative path or found in $PATH, return the full path.
|
||||
@@ -7046,9 +7062,9 @@ synID({lnum}, {col}, {trans}) *synID()*
|
||||
that's where the cursor can be in Insert mode, synID() returns
|
||||
zero.
|
||||
|
||||
When {trans} is non-zero, transparent items are reduced to the
|
||||
When {trans} is |TRUE|, transparent items are reduced to the
|
||||
item that they reveal. This is useful when wanting to know
|
||||
the effective color. When {trans} is zero, the transparent
|
||||
the effective color. When {trans} is |FALSE|, the transparent
|
||||
item is returned. This is useful when wanting to know which
|
||||
syntax item is effective (e.g. inside parens).
|
||||
Warning: This function can be very slow. Best speed is
|
||||
|
@@ -2023,8 +2023,8 @@ test_arglist \
|
||||
test_cmdline \
|
||||
test_cursor_func \
|
||||
test_delete \
|
||||
test_evalcmd \
|
||||
test_ex_undo \
|
||||
test_execute_func \
|
||||
test_expand \
|
||||
test_expand_dllpath \
|
||||
test_expr \
|
||||
|
189
src/eval.c
189
src/eval.c
@@ -555,9 +555,9 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
|
||||
static void f_empty(typval_T *argvars, typval_T *rettv);
|
||||
static void f_escape(typval_T *argvars, typval_T *rettv);
|
||||
static void f_eval(typval_T *argvars, typval_T *rettv);
|
||||
static void f_evalcmd(typval_T *argvars, typval_T *rettv);
|
||||
static void f_eventhandler(typval_T *argvars, typval_T *rettv);
|
||||
static void f_executable(typval_T *argvars, typval_T *rettv);
|
||||
static void f_execute(typval_T *argvars, typval_T *rettv);
|
||||
static void f_exepath(typval_T *argvars, typval_T *rettv);
|
||||
static void f_exists(typval_T *argvars, typval_T *rettv);
|
||||
#ifdef FEAT_FLOAT
|
||||
@@ -8564,9 +8564,9 @@ static struct fst
|
||||
{"empty", 1, 1, f_empty},
|
||||
{"escape", 2, 2, f_escape},
|
||||
{"eval", 1, 1, f_eval},
|
||||
{"evalcmd", 1, 1, f_evalcmd},
|
||||
{"eventhandler", 0, 0, f_eventhandler},
|
||||
{"executable", 1, 1, f_executable},
|
||||
{"execute", 1, 2, f_execute},
|
||||
{"exepath", 1, 1, f_exepath},
|
||||
{"exists", 1, 1, f_exists},
|
||||
#ifdef FEAT_FLOAT
|
||||
@@ -11345,65 +11345,6 @@ f_eval(typval_T *argvars, typval_T *rettv)
|
||||
EMSG(_(e_trailing));
|
||||
}
|
||||
|
||||
static garray_T redir_evalcmd_ga;
|
||||
|
||||
/*
|
||||
* Append "value[value_len]" to the evalcmd() output.
|
||||
*/
|
||||
void
|
||||
evalcmd_redir_str(char_u *value, int value_len)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (value_len == -1)
|
||||
len = (int)STRLEN(value); /* Append the entire string */
|
||||
else
|
||||
len = value_len; /* Append only "value_len" characters */
|
||||
if (ga_grow(&redir_evalcmd_ga, len) == OK)
|
||||
{
|
||||
mch_memmove((char *)redir_evalcmd_ga.ga_data
|
||||
+ redir_evalcmd_ga.ga_len, value, len);
|
||||
redir_evalcmd_ga.ga_len += len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* "evalcmd()" function
|
||||
*/
|
||||
static void
|
||||
f_evalcmd(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
char_u *s;
|
||||
int save_msg_silent = msg_silent;
|
||||
int save_redir_evalcmd = redir_evalcmd;
|
||||
garray_T save_ga;
|
||||
|
||||
rettv->vval.v_string = NULL;
|
||||
rettv->v_type = VAR_STRING;
|
||||
|
||||
s = get_tv_string_chk(&argvars[0]);
|
||||
if (s != NULL)
|
||||
{
|
||||
if (redir_evalcmd)
|
||||
save_ga = redir_evalcmd_ga;
|
||||
ga_init2(&redir_evalcmd_ga, (int)sizeof(char), 500);
|
||||
redir_evalcmd = TRUE;
|
||||
|
||||
++msg_silent;
|
||||
do_cmdline_cmd(s);
|
||||
rettv->vval.v_string = redir_evalcmd_ga.ga_data;
|
||||
msg_silent = save_msg_silent;
|
||||
|
||||
redir_evalcmd = save_redir_evalcmd;
|
||||
if (redir_evalcmd)
|
||||
redir_evalcmd_ga = save_ga;
|
||||
|
||||
/* "silent reg" or "silent echo x" leaves msg_col somewhere in the
|
||||
* line. Put it back in the first column. */
|
||||
msg_col = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* "eventhandler()" function
|
||||
*/
|
||||
@@ -11426,6 +11367,132 @@ f_executable(typval_T *argvars, typval_T *rettv)
|
||||
|| (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
|
||||
}
|
||||
|
||||
static garray_T redir_execute_ga;
|
||||
|
||||
/*
|
||||
* Append "value[value_len]" to the execute() output.
|
||||
*/
|
||||
void
|
||||
execute_redir_str(char_u *value, int value_len)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (value_len == -1)
|
||||
len = (int)STRLEN(value); /* Append the entire string */
|
||||
else
|
||||
len = value_len; /* Append only "value_len" characters */
|
||||
if (ga_grow(&redir_execute_ga, len) == OK)
|
||||
{
|
||||
mch_memmove((char *)redir_execute_ga.ga_data
|
||||
+ redir_execute_ga.ga_len, value, len);
|
||||
redir_execute_ga.ga_len += len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get next line from a list.
|
||||
* Called by do_cmdline() to get the next line.
|
||||
* Returns allocated string, or NULL for end of function.
|
||||
*/
|
||||
|
||||
static char_u *
|
||||
get_list_line(
|
||||
int c UNUSED,
|
||||
void *cookie,
|
||||
int indent UNUSED)
|
||||
{
|
||||
listitem_T **p = (listitem_T **)cookie;
|
||||
listitem_T *item = *p;
|
||||
char_u buf[NUMBUFLEN];
|
||||
char_u *s;
|
||||
|
||||
if (item == NULL)
|
||||
return NULL;
|
||||
s = get_tv_string_buf_chk(&item->li_tv, buf);
|
||||
*p = item->li_next;
|
||||
return s == NULL ? NULL : vim_strsave(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* "execute()" function
|
||||
*/
|
||||
static void
|
||||
f_execute(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
char_u *cmd = NULL;
|
||||
list_T *list = NULL;
|
||||
int save_msg_silent = msg_silent;
|
||||
int save_emsg_silent = emsg_silent;
|
||||
int save_emsg_noredir = emsg_noredir;
|
||||
int save_redir_execute = redir_execute;
|
||||
garray_T save_ga;
|
||||
|
||||
rettv->vval.v_string = NULL;
|
||||
rettv->v_type = VAR_STRING;
|
||||
|
||||
if (argvars[0].v_type == VAR_LIST)
|
||||
{
|
||||
list = argvars[0].vval.v_list;
|
||||
if (list == NULL || list->lv_first == NULL)
|
||||
/* empty list, no commands, empty output */
|
||||
return;
|
||||
++list->lv_refcount;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd = get_tv_string_chk(&argvars[0]);
|
||||
if (cmd == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
if (redir_execute)
|
||||
save_ga = redir_execute_ga;
|
||||
ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
|
||||
redir_execute = TRUE;
|
||||
|
||||
if (argvars[1].v_type != VAR_UNKNOWN)
|
||||
{
|
||||
char_u buf[NUMBUFLEN];
|
||||
char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
|
||||
|
||||
if (s == NULL)
|
||||
return;
|
||||
if (STRNCMP(s, "silent", 6) == 0)
|
||||
++msg_silent;
|
||||
if (STRCMP(s, "silent!") == 0)
|
||||
{
|
||||
emsg_silent = TRUE;
|
||||
emsg_noredir = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
++msg_silent;
|
||||
|
||||
if (cmd != NULL)
|
||||
do_cmdline_cmd(cmd);
|
||||
else
|
||||
{
|
||||
listitem_T *item = list->lv_first;
|
||||
|
||||
do_cmdline(NULL, get_list_line, (void *)&item,
|
||||
DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
|
||||
--list->lv_refcount;
|
||||
}
|
||||
|
||||
rettv->vval.v_string = redir_execute_ga.ga_data;
|
||||
msg_silent = save_msg_silent;
|
||||
emsg_silent = save_emsg_silent;
|
||||
emsg_noredir = save_emsg_noredir;
|
||||
|
||||
redir_execute = save_redir_execute;
|
||||
if (redir_execute)
|
||||
redir_execute_ga = save_ga;
|
||||
|
||||
/* "silent reg" or "silent echo x" leaves msg_col somewhere in the
|
||||
* line. Put it back in the first column. */
|
||||
msg_col = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* "exepath()" function
|
||||
*/
|
||||
|
@@ -9456,9 +9456,9 @@ ex_redir(exarg_T *eap)
|
||||
char_u *arg = eap->arg;
|
||||
|
||||
#ifdef FEAT_EVAL
|
||||
if (redir_evalcmd)
|
||||
if (redir_execute)
|
||||
{
|
||||
EMSG(_("E930: Cannot use :redir inside evalcmd()"));
|
||||
EMSG(_("E930: Cannot use :redir inside execute()"));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
@@ -971,6 +971,7 @@ EXTERN cmdmod_T cmdmod; /* Ex command modifiers */
|
||||
|
||||
EXTERN int msg_silent INIT(= 0); /* don't print messages */
|
||||
EXTERN int emsg_silent INIT(= 0); /* don't print error messages */
|
||||
EXTERN int emsg_noredir INIT(= 0); /* don't redirect error messages */
|
||||
EXTERN int cmd_silent INIT(= FALSE); /* don't echo the command line */
|
||||
|
||||
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) \
|
||||
@@ -1106,7 +1107,7 @@ EXTERN FILE *redir_fd INIT(= NULL); /* message redirection file */
|
||||
#ifdef FEAT_EVAL
|
||||
EXTERN int redir_reg INIT(= 0); /* message redirection register */
|
||||
EXTERN int redir_vname INIT(= 0); /* message redirection variable */
|
||||
EXTERN int redir_evalcmd INIT(= 0); /* evalcmd() redirection */
|
||||
EXTERN int redir_execute INIT(= 0); /* execute() redirection */
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_LANGMAP
|
||||
|
@@ -566,22 +566,25 @@ emsg(char_u *s)
|
||||
*/
|
||||
if (emsg_silent != 0)
|
||||
{
|
||||
msg_start();
|
||||
p = get_emsg_source();
|
||||
if (p != NULL)
|
||||
if (emsg_noredir == 0)
|
||||
{
|
||||
STRCAT(p, "\n");
|
||||
redir_write(p, -1);
|
||||
vim_free(p);
|
||||
msg_start();
|
||||
p = get_emsg_source();
|
||||
if (p != NULL)
|
||||
{
|
||||
STRCAT(p, "\n");
|
||||
redir_write(p, -1);
|
||||
vim_free(p);
|
||||
}
|
||||
p = get_emsg_lnum();
|
||||
if (p != NULL)
|
||||
{
|
||||
STRCAT(p, "\n");
|
||||
redir_write(p, -1);
|
||||
vim_free(p);
|
||||
}
|
||||
redir_write(s, -1);
|
||||
}
|
||||
p = get_emsg_lnum();
|
||||
if (p != NULL)
|
||||
{
|
||||
STRCAT(p, "\n");
|
||||
redir_write(p, -1);
|
||||
vim_free(p);
|
||||
}
|
||||
redir_write(s, -1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -3063,8 +3066,8 @@ redir_write(char_u *str, int maxlen)
|
||||
while (cur_col < msg_col)
|
||||
{
|
||||
#ifdef FEAT_EVAL
|
||||
if (redir_evalcmd)
|
||||
evalcmd_redir_str((char_u *)" ", -1);
|
||||
if (redir_execute)
|
||||
execute_redir_str((char_u *)" ", -1);
|
||||
else if (redir_reg)
|
||||
write_reg_contents(redir_reg, (char_u *)" ", -1, TRUE);
|
||||
else if (redir_vname)
|
||||
@@ -3080,8 +3083,8 @@ redir_write(char_u *str, int maxlen)
|
||||
}
|
||||
|
||||
#ifdef FEAT_EVAL
|
||||
if (redir_evalcmd)
|
||||
evalcmd_redir_str(s, maxlen);
|
||||
if (redir_execute)
|
||||
execute_redir_str(s, maxlen);
|
||||
else if (redir_reg)
|
||||
write_reg_contents(redir_reg, s, maxlen, TRUE);
|
||||
else if (redir_vname)
|
||||
@@ -3092,7 +3095,7 @@ redir_write(char_u *str, int maxlen)
|
||||
while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
|
||||
{
|
||||
#ifdef FEAT_EVAL
|
||||
if (!redir_reg && !redir_vname && !redir_evalcmd)
|
||||
if (!redir_reg && !redir_vname && !redir_execute)
|
||||
#endif
|
||||
if (redir_fd != NULL)
|
||||
putc(*s, redir_fd);
|
||||
@@ -3117,7 +3120,7 @@ redirecting(void)
|
||||
{
|
||||
return redir_fd != NULL || *p_vfile != NUL
|
||||
#ifdef FEAT_EVAL
|
||||
|| redir_reg || redir_vname || redir_evalcmd
|
||||
|| redir_reg || redir_vname || redir_execute
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
@@ -88,7 +88,7 @@ char_u *get_expr_name(expand_T *xp, int idx);
|
||||
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict_in);
|
||||
buf_T *buflist_find_by_name(char_u *name, int curtab_only);
|
||||
int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv);
|
||||
void evalcmd_redir_str(char_u *value, int value_len);
|
||||
void execute_redir_str(char_u *value, int value_len);
|
||||
void dict_extend(dict_T *d1, dict_T *d2, char_u *action);
|
||||
void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
|
||||
float_T vim_round(float_T f);
|
||||
|
@@ -5,7 +5,7 @@ source test_assign.vim
|
||||
source test_autocmd.vim
|
||||
source test_cursor_func.vim
|
||||
source test_delete.vim
|
||||
source test_evalcmd.vim
|
||||
source test_execute_func.vim
|
||||
source test_ex_undo.vim
|
||||
source test_expand.vim
|
||||
source test_expr.vim
|
||||
|
@@ -1,33 +0,0 @@
|
||||
" test evalcmd()
|
||||
|
||||
func NestedEval()
|
||||
let nested = evalcmd('echo "nested\nlines"')
|
||||
echo 'got: "' . nested . '"'
|
||||
endfunc
|
||||
|
||||
func NestedRedir()
|
||||
redir => var
|
||||
echo 'broken'
|
||||
redir END
|
||||
endfunc
|
||||
|
||||
func Test_evalcmd()
|
||||
call assert_equal("\nnocompatible", evalcmd('set compatible?'))
|
||||
call assert_equal("\nsomething\nnice", evalcmd('echo "something\nnice"'))
|
||||
call assert_equal("noendofline", evalcmd('echon "noendofline"'))
|
||||
call assert_equal("", evalcmd(123))
|
||||
|
||||
call assert_equal("\ngot: \"\nnested\nlines\"", evalcmd('call NestedEval()'))
|
||||
redir => redired
|
||||
echo 'this'
|
||||
let evaled = evalcmd('echo "that"')
|
||||
echo 'theend'
|
||||
redir END
|
||||
call assert_equal("\nthis\ntheend", redired)
|
||||
call assert_equal("\nthat", evaled)
|
||||
|
||||
call assert_fails('call evalcmd("doesnotexist")', 'E492:')
|
||||
call assert_fails('call evalcmd(3.4)', 'E806:')
|
||||
call assert_fails('call evalcmd("call NestedRedir()")', 'E930:')
|
||||
endfunc
|
||||
|
51
src/testdir/test_execute_func.vim
Normal file
51
src/testdir/test_execute_func.vim
Normal file
@@ -0,0 +1,51 @@
|
||||
" test execute()
|
||||
|
||||
func NestedEval()
|
||||
let nested = execute('echo "nested\nlines"')
|
||||
echo 'got: "' . nested . '"'
|
||||
endfunc
|
||||
|
||||
func NestedRedir()
|
||||
redir => var
|
||||
echo 'broken'
|
||||
redir END
|
||||
endfunc
|
||||
|
||||
func Test_execute_string()
|
||||
call assert_equal("\nnocompatible", execute('set compatible?'))
|
||||
call assert_equal("\nsomething\nnice", execute('echo "something\nnice"'))
|
||||
call assert_equal("noendofline", execute('echon "noendofline"'))
|
||||
call assert_equal("", execute(123))
|
||||
|
||||
call assert_equal("\ngot: \"\nnested\nlines\"", execute('call NestedEval()'))
|
||||
redir => redired
|
||||
echo 'this'
|
||||
let evaled = execute('echo "that"')
|
||||
echo 'theend'
|
||||
redir END
|
||||
call assert_equal("\nthis\ntheend", redired)
|
||||
call assert_equal("\nthat", evaled)
|
||||
|
||||
call assert_fails('call execute("doesnotexist")', 'E492:')
|
||||
call assert_fails('call execute(3.4)', 'E806:')
|
||||
call assert_fails('call execute("call NestedRedir()")', 'E930:')
|
||||
|
||||
call assert_equal("\nsomething", execute('echo "something"', ''))
|
||||
call assert_equal("\nsomething", execute('echo "something"', 'silent'))
|
||||
call assert_equal("\nsomething", execute('echo "something"', 'silent!'))
|
||||
call assert_equal("", execute('burp', 'silent!'))
|
||||
call assert_fails('call execute("echo \"x\"", 3.4)', 'E806:')
|
||||
|
||||
call assert_equal("", execute(test_null_string()))
|
||||
endfunc
|
||||
|
||||
func Test_execute_list()
|
||||
call assert_equal("\nsomething\nnice", execute(['echo "something"', 'echo "nice"']))
|
||||
let l = ['for n in range(0, 3)',
|
||||
\ 'echo n',
|
||||
\ 'endfor']
|
||||
call assert_equal("\n0\n1\n2\n3", execute(l))
|
||||
|
||||
call assert_equal("", execute([]))
|
||||
call assert_equal("", execute(test_null_list()))
|
||||
endfunc
|
Reference in New Issue
Block a user