1
0
forked from aniani/vim

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:
Bram Moolenaar
2016-07-09 17:07:29 +02:00
parent fc4ad61607
commit 79815f1ec7
10 changed files with 238 additions and 133 deletions

View File

@@ -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 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 empty({expr}) Number |TRUE| if {expr} is empty
escape({string}, {chars}) String escape {chars} in {string} with '\' escape({string}, {chars}) String escape {chars} in {string} with '\'
eval({string}) any evaluate {string} into its value 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 eventhandler() Number |TRUE| if inside an event handler
executable({expr}) Number 1 if executable {expr} exists 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} exepath({expr}) String full path of the command {expr}
exists({expr}) Number |TRUE| if {expr} exists exists({expr}) Number |TRUE| if {expr} exists
extend({expr1}, {expr2} [, {expr3}]) 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 them. Also works for |Funcref|s that refer to existing
functions. 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()* eventhandler() *eventhandler()*
Returns 1 when inside an event handler. That is that Vim got Returns 1 when inside an event handler. That is that Vim got
interrupted while waiting for the user to type a character, interrupted while waiting for the user to type a character,
@@ -3271,6 +3262,31 @@ executable({expr}) *executable()*
0 does not exist 0 does not exist
-1 not implemented on this system -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()* exepath({expr}) *exepath()*
If {expr} is an executable and is either an absolute path, a If {expr} is an executable and is either an absolute path, a
relative path or found in $PATH, return the full path. 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 that's where the cursor can be in Insert mode, synID() returns
zero. 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 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 item is returned. This is useful when wanting to know which
syntax item is effective (e.g. inside parens). syntax item is effective (e.g. inside parens).
Warning: This function can be very slow. Best speed is Warning: This function can be very slow. Best speed is

View File

@@ -2023,8 +2023,8 @@ test_arglist \
test_cmdline \ test_cmdline \
test_cursor_func \ test_cursor_func \
test_delete \ test_delete \
test_evalcmd \
test_ex_undo \ test_ex_undo \
test_execute_func \
test_expand \ test_expand \
test_expand_dllpath \ test_expand_dllpath \
test_expr \ test_expr \

View File

@@ -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_empty(typval_T *argvars, typval_T *rettv);
static void f_escape(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_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_eventhandler(typval_T *argvars, typval_T *rettv);
static void f_executable(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_exepath(typval_T *argvars, typval_T *rettv);
static void f_exists(typval_T *argvars, typval_T *rettv); static void f_exists(typval_T *argvars, typval_T *rettv);
#ifdef FEAT_FLOAT #ifdef FEAT_FLOAT
@@ -8564,9 +8564,9 @@ static struct fst
{"empty", 1, 1, f_empty}, {"empty", 1, 1, f_empty},
{"escape", 2, 2, f_escape}, {"escape", 2, 2, f_escape},
{"eval", 1, 1, f_eval}, {"eval", 1, 1, f_eval},
{"evalcmd", 1, 1, f_evalcmd},
{"eventhandler", 0, 0, f_eventhandler}, {"eventhandler", 0, 0, f_eventhandler},
{"executable", 1, 1, f_executable}, {"executable", 1, 1, f_executable},
{"execute", 1, 2, f_execute},
{"exepath", 1, 1, f_exepath}, {"exepath", 1, 1, f_exepath},
{"exists", 1, 1, f_exists}, {"exists", 1, 1, f_exists},
#ifdef FEAT_FLOAT #ifdef FEAT_FLOAT
@@ -11345,65 +11345,6 @@ f_eval(typval_T *argvars, typval_T *rettv)
EMSG(_(e_trailing)); 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 * "eventhandler()" function
*/ */
@@ -11426,6 +11367,132 @@ f_executable(typval_T *argvars, typval_T *rettv)
|| (gettail(name) != name && mch_can_exe(name, NULL, FALSE)); || (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 * "exepath()" function
*/ */

View File

@@ -9456,9 +9456,9 @@ ex_redir(exarg_T *eap)
char_u *arg = eap->arg; char_u *arg = eap->arg;
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
if (redir_evalcmd) if (redir_execute)
{ {
EMSG(_("E930: Cannot use :redir inside evalcmd()")); EMSG(_("E930: Cannot use :redir inside execute()"));
return; return;
} }
#endif #endif

View File

@@ -971,6 +971,7 @@ EXTERN cmdmod_T cmdmod; /* Ex command modifiers */
EXTERN int msg_silent INIT(= 0); /* don't print messages */ EXTERN int msg_silent INIT(= 0); /* don't print messages */
EXTERN int emsg_silent INIT(= 0); /* don't print error 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 */ EXTERN int cmd_silent INIT(= FALSE); /* don't echo the command line */
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) \ #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 #ifdef FEAT_EVAL
EXTERN int redir_reg INIT(= 0); /* message redirection register */ EXTERN int redir_reg INIT(= 0); /* message redirection register */
EXTERN int redir_vname INIT(= 0); /* message redirection variable */ 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 #endif
#ifdef FEAT_LANGMAP #ifdef FEAT_LANGMAP

View File

@@ -566,22 +566,25 @@ emsg(char_u *s)
*/ */
if (emsg_silent != 0) if (emsg_silent != 0)
{ {
msg_start(); if (emsg_noredir == 0)
p = get_emsg_source();
if (p != NULL)
{ {
STRCAT(p, "\n"); msg_start();
redir_write(p, -1); p = get_emsg_source();
vim_free(p); 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; return TRUE;
} }
@@ -3063,8 +3066,8 @@ redir_write(char_u *str, int maxlen)
while (cur_col < msg_col) while (cur_col < msg_col)
{ {
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
if (redir_evalcmd) if (redir_execute)
evalcmd_redir_str((char_u *)" ", -1); execute_redir_str((char_u *)" ", -1);
else if (redir_reg) else if (redir_reg)
write_reg_contents(redir_reg, (char_u *)" ", -1, TRUE); write_reg_contents(redir_reg, (char_u *)" ", -1, TRUE);
else if (redir_vname) else if (redir_vname)
@@ -3080,8 +3083,8 @@ redir_write(char_u *str, int maxlen)
} }
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
if (redir_evalcmd) if (redir_execute)
evalcmd_redir_str(s, maxlen); execute_redir_str(s, maxlen);
else if (redir_reg) else if (redir_reg)
write_reg_contents(redir_reg, s, maxlen, TRUE); write_reg_contents(redir_reg, s, maxlen, TRUE);
else if (redir_vname) else if (redir_vname)
@@ -3092,7 +3095,7 @@ redir_write(char_u *str, int maxlen)
while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen)) while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
{ {
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
if (!redir_reg && !redir_vname && !redir_evalcmd) if (!redir_reg && !redir_vname && !redir_execute)
#endif #endif
if (redir_fd != NULL) if (redir_fd != NULL)
putc(*s, redir_fd); putc(*s, redir_fd);
@@ -3117,7 +3120,7 @@ redirecting(void)
{ {
return redir_fd != NULL || *p_vfile != NUL return redir_fd != NULL || *p_vfile != NUL
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
|| redir_reg || redir_vname || redir_evalcmd || redir_reg || redir_vname || redir_execute
#endif #endif
; ;
} }

View File

@@ -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); 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); 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); 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 dict_extend(dict_T *d1, dict_T *d2, char_u *action);
void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv); void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
float_T vim_round(float_T f); float_T vim_round(float_T f);

View File

@@ -5,7 +5,7 @@ source test_assign.vim
source test_autocmd.vim source test_autocmd.vim
source test_cursor_func.vim source test_cursor_func.vim
source test_delete.vim source test_delete.vim
source test_evalcmd.vim source test_execute_func.vim
source test_ex_undo.vim source test_ex_undo.vim
source test_expand.vim source test_expand.vim
source test_expr.vim source test_expr.vim

View File

@@ -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

View 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