diff options
-rw-r--r-- | runtime/doc/eval.txt | 42 | ||||
-rw-r--r-- | src/Makefile | 2 | ||||
-rw-r--r-- | src/eval.c | 161 | ||||
-rw-r--r-- | src/ex_docmd.c | 4 | ||||
-rw-r--r-- | src/globals.h | 3 | ||||
-rw-r--r-- | src/message.c | 43 | ||||
-rw-r--r-- | src/proto/eval.pro | 2 | ||||
-rw-r--r-- | src/testdir/test_alot.vim | 2 | ||||
-rw-r--r-- | src/testdir/test_evalcmd.vim | 33 | ||||
-rw-r--r-- | src/testdir/test_execute_func.vim | 51 |
10 files changed, 224 insertions, 119 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 4b55f911d..7f948eee1 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -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 diff --git a/src/Makefile b/src/Makefile index 13bf77691..007c7925d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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 \ diff --git a/src/eval.c b/src/eval.c index 4764f49ab..ab808b9e2 100644 --- a/src/eval.c +++ b/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,13 +11345,35 @@ f_eval(typval_T *argvars, typval_T *rettv) EMSG(_(e_trailing)); } -static garray_T redir_evalcmd_ga; +/* + * "eventhandler()" function + */ + static void +f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv) +{ + rettv->vval.v_number = vgetc_busy; +} + +/* + * "executable()" function + */ + static void +f_executable(typval_T *argvars, typval_T *rettv) +{ + char_u *name = get_tv_string(&argvars[0]); + + /* Check in $PATH and also check directly if there is a directory name. */ + rettv->vval.v_number = mch_can_exe(name, NULL, TRUE) + || (gettail(name) != name && mch_can_exe(name, NULL, FALSE)); +} + +static garray_T redir_execute_ga; /* - * Append "value[value_len]" to the evalcmd() output. + * Append "value[value_len]" to the execute() output. */ void -evalcmd_redir_str(char_u *value, int value_len) +execute_redir_str(char_u *value, int value_len) { int len; @@ -11359,71 +11381,116 @@ evalcmd_redir_str(char_u *value, int value_len) 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) + if (ga_grow(&redir_execute_ga, len) == OK) { - mch_memmove((char *)redir_evalcmd_ga.ga_data - + redir_evalcmd_ga.ga_len, value, len); - redir_evalcmd_ga.ga_len += len; + mch_memmove((char *)redir_execute_ga.ga_data + + redir_execute_ga.ga_len, value, len); + redir_execute_ga.ga_len += len; } } /* - * "evalcmd()" function + * 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 void -f_evalcmd(typval_T *argvars, typval_T *rettv) + + 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_redir_evalcmd = redir_evalcmd; + 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; - s = get_tv_string_chk(&argvars[0]); - if (s != NULL) + if (argvars[0].v_type == VAR_LIST) { - if (redir_evalcmd) - save_ga = redir_evalcmd_ga; - ga_init2(&redir_evalcmd_ga, (int)sizeof(char), 500); - redir_evalcmd = TRUE; + 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; - 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; + if (cmd != NULL) + do_cmdline_cmd(cmd); + else + { + listitem_T *item = list->lv_first; - /* "silent reg" or "silent echo x" leaves msg_col somewhere in the - * line. Put it back in the first column. */ - msg_col = 0; + do_cmdline(NULL, get_list_line, (void *)&item, + DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED); + --list->lv_refcount; } -} -/* - * "eventhandler()" function - */ - static void -f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->vval.v_number = vgetc_busy; -} + rettv->vval.v_string = redir_execute_ga.ga_data; + msg_silent = save_msg_silent; + emsg_silent = save_emsg_silent; + emsg_noredir = save_emsg_noredir; -/* - * "executable()" function - */ - static void -f_executable(typval_T *argvars, typval_T *rettv) -{ - char_u *name = get_tv_string(&argvars[0]); + redir_execute = save_redir_execute; + if (redir_execute) + redir_execute_ga = save_ga; - /* Check in $PATH and also check directly if there is a directory name. */ - rettv->vval.v_number = mch_can_exe(name, NULL, TRUE) - || (gettail(name) != name && mch_can_exe(name, NULL, FALSE)); + /* "silent reg" or "silent echo x" leaves msg_col somewhere in the + * line. Put it back in the first column. */ + msg_col = 0; } /* diff --git a/src/ex_docmd.c b/src/ex_docmd.c index b892b6307..f8b50ed1d 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -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 diff --git a/src/globals.h b/src/globals.h index 97711164a..68bf36f58 100644 --- a/src/globals.h +++ b/src/globals.h @@ -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 diff --git a/src/message.c b/src/message.c index f793ed414..7bb154d2e 100644 --- a/src/message.c +++ b/src/message.c @@ -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); - } - p = get_emsg_lnum(); - if (p != NULL) - { - 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); } - 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 ; } diff --git a/src/proto/eval.pro b/src/proto/eval.pro index 28edd782c..e81669b05 100644 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -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); diff --git a/src/testdir/test_alot.vim b/src/testdir/test_alot.vim index 074c2dec9..3074a5c0b 100644 --- a/src/testdir/test_alot.vim +++ b/src/testdir/test_alot.vim @@ -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 diff --git a/src/testdir/test_evalcmd.vim b/src/testdir/test_evalcmd.vim deleted file mode 100644 index a9bda875f..000000000 --- a/src/testdir/test_evalcmd.vim +++ /dev/null @@ -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 - diff --git a/src/testdir/test_execute_func.vim b/src/testdir/test_execute_func.vim new file mode 100644 index 000000000..dd07e4a62 --- /dev/null +++ b/src/testdir/test_execute_func.vim @@ -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 |