To: vim_dev@googlegroups.com Subject: Patch 8.2.3297 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3297 Problem: Cannot use all commands inside a {} block after :command and :autocmd. Solution: Do consider \n to separate commands. (closes #8620) Files: runtime/doc/map.txt, src/ex_docmd.c, src/proto/ex_docmd.pro, src/ex_eval.c, src/proto/ex_eval.pro, src/eval.c, src/evalvars.c, src/ex_cmds.c, src/syntax.c, src/userfunc.c, src/vim9compile.c, src/vim9script.c, src/errors.h, src/testdir/test_autocmd.vim, src/testdir/test_usercommands.vim *** ../vim-8.2.3296/runtime/doc/map.txt 2021-08-01 14:52:05.554645412 +0200 --- runtime/doc/map.txt 2021-08-05 20:38:05.454379134 +0200 *************** *** 1561,1568 **** echo 'hello' g:calledMyCommand = true } ! No nesting is supported, inline functions cannot be used. Using `:normal` ! directly does not work, you can use it indirectly with `:execute`. The replacement text {repl} for a user defined command is scanned for special escape sequences, using <...> notation. Escape sequences are replaced with --- 1580,1590 ---- echo 'hello' g:calledMyCommand = true } ! < *E1231* ! There must be white space before the "{". No nesting is supported, inline ! functions cannot be used. Commands where a "|" may appear in the argument, ! such as commands with an expression argument, cannot be followed by a "|" and ! another command. The replacement text {repl} for a user defined command is scanned for special escape sequences, using <...> notation. Escape sequences are replaced with *** ../vim-8.2.3296/src/ex_docmd.c 2021-08-01 21:19:40.130538381 +0200 --- src/ex_docmd.c 2021-08-05 20:34:52.042934992 +0200 *************** *** 2314,2335 **** ea.do_ecmd_cmd = getargcmd(&ea.arg); /* ! * Check for '|' to separate commands and '"' or '#' to start comments. ! * Don't do this for ":read !cmd" and ":write !cmd". ! */ ! if ((ea.argt & EX_TRLBAR) && !ea.usefilter) ! separate_nextcmd(&ea); ! ! /* ! * Check for to end a shell command. * Also do this for ":read !cmd", ":write !cmd" and ":global". * Any others? */ else if (ea.cmdidx == CMD_bang || ea.cmdidx == CMD_terminal || ea.cmdidx == CMD_global || ea.cmdidx == CMD_vglobal ! || ea.usefilter) { for (p = ea.arg; *p; ++p) { --- 2314,2337 ---- ea.do_ecmd_cmd = getargcmd(&ea.arg); /* ! * For commands that do not use '|' inside their argument: Check for '|' to ! * separate commands and '"' or '#' to start comments. ! * ! * Otherwise: Check for to end a shell command. * Also do this for ":read !cmd", ":write !cmd" and ":global". + * Also do this inside a { - } block after :command and :autocmd. * Any others? */ + if ((ea.argt & EX_TRLBAR) && !ea.usefilter) + { + separate_nextcmd(&ea); + } else if (ea.cmdidx == CMD_bang || ea.cmdidx == CMD_terminal || ea.cmdidx == CMD_global || ea.cmdidx == CMD_vglobal ! || ea.usefilter ! || inside_block(&ea)) { for (p = ea.arg; *p; ++p) { *************** *** 5410,5415 **** --- 5412,5432 ---- } /* + * If "eap->nextcmd" is not set, check for a next command at "p". + */ + void + set_nextcmd(exarg_T *eap, char_u *arg) + { + char_u *p = check_nextcmd(arg); + + if (eap->nextcmd == NULL) + eap->nextcmd = p; + else if (p != NULL) + // cannot use "| command" inside a {} block + semsg(_(e_cannot_use_bar_to_separate_commands_here_str), arg); + } + + /* * - if there are more files to edit * - and this is the last window * - and forceit not used *************** *** 7546,7552 **** else p = eap->arg + 1; ! eap->nextcmd = check_nextcmd(p); p = skipwhite(p); if (*p != NUL && *p != ( #ifdef FEAT_EVAL --- 7563,7569 ---- else p = eap->arg + 1; ! set_nextcmd(eap, p); p = skipwhite(p); if (*p != NUL && *p != ( #ifdef FEAT_EVAL *************** *** 8580,8586 **** if (!ends_excmd2(eap->arg, p)) eap->errmsg = ex_errmsg(e_trailing_arg, p); else ! eap->nextcmd = check_nextcmd(p); } } if (!eap->skip) --- 8597,8603 ---- if (!ends_excmd2(eap->arg, p)) eap->errmsg = ex_errmsg(e_trailing_arg, p); else ! set_nextcmd(eap, p); } } if (!eap->skip) *** ../vim-8.2.3296/src/proto/ex_docmd.pro 2021-08-01 21:19:40.130538381 +0200 --- src/proto/ex_docmd.pro 2021-08-05 20:13:28.455007890 +0200 *************** *** 33,38 **** --- 33,39 ---- int ends_excmd2(char_u *cmd_start, char_u *cmd); char_u *find_nextcmd(char_u *p); char_u *check_nextcmd(char_u *p); + void set_nextcmd(exarg_T *eap, char_u *p); char_u *get_command_name(expand_T *xp, int idx); void not_exiting(void); int before_quit_autocmds(win_T *wp, int quit_all, int forceit); *** ../vim-8.2.3296/src/ex_eval.c 2021-07-25 14:13:50.040566339 +0200 --- src/ex_eval.c 2021-08-05 19:27:31.462636805 +0200 *************** *** 1461,1466 **** --- 1461,1478 ---- leave_block(cstack); } + int + inside_block(exarg_T *eap) + { + cstack_T *cstack = eap->cstack; + int i; + + for (i = 0; i <= cstack->cs_idx; ++i) + if (cstack->cs_flags[cstack->cs_idx] & CSF_BLOCK) + return TRUE; + return FALSE; + } + /* * ":throw expr" */ *** ../vim-8.2.3296/src/proto/ex_eval.pro 2020-10-10 21:33:42.403033529 +0200 --- src/proto/ex_eval.pro 2021-08-05 19:28:25.242498746 +0200 *************** *** 22,27 **** --- 22,28 ---- void ex_endwhile(exarg_T *eap); void ex_block(exarg_T *eap); void ex_endblock(exarg_T *eap); + int inside_block(exarg_T *eap); void ex_throw(exarg_T *eap); void do_throw(cstack_T *cstack); void ex_try(exarg_T *eap); *** ../vim-8.2.3296/src/eval.c 2021-08-04 19:25:50.614808524 +0200 --- src/eval.c 2021-08-05 20:12:22.731262479 +0200 *************** *** 2314,2320 **** } if (eap != NULL) ! eap->nextcmd = check_nextcmd(p); return ret; } --- 2314,2320 ---- } if (eap != NULL) ! set_nextcmd(eap, p); return ret; } *************** *** 6173,6179 **** clear_tv(&rettv); arg = skipwhite(arg); } ! eap->nextcmd = check_nextcmd(arg); clear_evalarg(&evalarg, eap); if (eap->skip) --- 6173,6179 ---- clear_tv(&rettv); arg = skipwhite(arg); } ! set_nextcmd(eap, arg); clear_evalarg(&evalarg, eap); if (eap->skip) *************** *** 6317,6323 **** if (eap->skip) --emsg_skip; ! eap->nextcmd = check_nextcmd(arg); } /* --- 6317,6323 ---- if (eap->skip) --emsg_skip; ! set_nextcmd(eap, arg); } /* *** ../vim-8.2.3296/src/evalvars.c 2021-07-28 21:25:45.360602797 +0200 --- src/evalvars.c 2021-08-05 20:14:04.414872230 +0200 *************** *** 812,818 **** list_func_vars(&first); list_vim_vars(&first); } ! eap->nextcmd = check_nextcmd(arg); } else if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<') { --- 812,818 ---- list_func_vars(&first); list_vim_vars(&first); } ! set_nextcmd(eap, arg); } else if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<') { *************** *** 1629,1635 **** arg = skipwhite(name_end); } while (!ends_excmd2(name_end, arg)); ! eap->nextcmd = check_nextcmd(arg); } static int --- 1629,1635 ---- arg = skipwhite(name_end); } while (!ends_excmd2(name_end, arg)); ! set_nextcmd(eap, arg); } static int *** ../vim-8.2.3296/src/ex_cmds.c 2021-07-21 22:20:30.062401737 +0200 --- src/ex_cmds.c 2021-08-05 20:14:58.090674037 +0200 *************** *** 450,456 **** unique = TRUE; else if (*p == '"') // comment start break; ! else if (check_nextcmd(p) != NULL) { eap->nextcmd = check_nextcmd(p); break; --- 450,456 ---- unique = TRUE; else if (*p == '"') // comment start break; ! else if (eap->nextcmd == NULL && check_nextcmd(p) != NULL) { eap->nextcmd = check_nextcmd(p); break; *************** *** 3930,3936 **** cmd = skipwhite(cmd); if (*cmd && *cmd != '"') // if not end-of-line or comment { ! eap->nextcmd = check_nextcmd(cmd); if (eap->nextcmd == NULL) { semsg(_(e_trailing_arg), cmd); --- 3930,3936 ---- cmd = skipwhite(cmd); if (*cmd && *cmd != '"') // if not end-of-line or comment { ! set_nextcmd(eap, cmd); if (eap->nextcmd == NULL) { semsg(_(e_trailing_arg), cmd); *** ../vim-8.2.3296/src/syntax.c 2021-07-20 21:07:32.968058851 +0200 --- src/syntax.c 2021-08-05 20:18:00.198034391 +0200 *************** *** 3789,3795 **** static void syn_cmd_reset(exarg_T *eap, int syncing UNUSED) { ! eap->nextcmd = check_nextcmd(eap->arg); if (!eap->skip) { set_internal_string_var((char_u *)"syntax_cmd", (char_u *)"reset"); --- 3789,3795 ---- static void syn_cmd_reset(exarg_T *eap, int syncing UNUSED) { ! set_nextcmd(eap, eap->arg); if (!eap->skip) { set_internal_string_var((char_u *)"syntax_cmd", (char_u *)"reset"); *************** *** 3821,3827 **** { char_u buf[100]; ! eap->nextcmd = check_nextcmd(eap->arg); if (!eap->skip) { STRCPY(buf, "so "); --- 3821,3827 ---- { char_u buf[100]; ! set_nextcmd(eap, eap->arg); if (!eap->skip) { STRCPY(buf, "so "); *************** *** 3928,3934 **** arg = skipwhite(arg_end); } } ! eap->nextcmd = check_nextcmd(arg); } static void --- 3928,3934 ---- arg = skipwhite(arg_end); } } ! set_nextcmd(eap, arg); } static void *************** *** 4921,4927 **** } if (rest != NULL) ! eap->nextcmd = check_nextcmd(rest); else semsg(_(e_invarg2), arg); --- 4921,4927 ---- } if (rest != NULL) ! set_nextcmd(eap, rest); else semsg(_(e_invarg2), arg); *************** *** 4978,4984 **** /* * Check for trailing command and illegal trailing arguments. */ ! eap->nextcmd = check_nextcmd(rest); if (!ends_excmd2(eap->cmd, rest) || eap->skip) rest = NULL; else if (ga_grow(&curwin->w_s->b_syn_patterns, 1) != FAIL --- 4978,4984 ---- /* * Check for trailing command and illegal trailing arguments. */ ! set_nextcmd(eap, rest); if (!ends_excmd2(eap->cmd, rest) || eap->skip) rest = NULL; else if (ga_grow(&curwin->w_s->b_syn_patterns, 1) != FAIL *************** *** 5218,5224 **** * Check for trailing garbage or command. * If OK, add the item. */ ! eap->nextcmd = check_nextcmd(rest); if (!ends_excmd(*rest) || eap->skip) rest = NULL; else if (ga_grow(&(curwin->w_s->b_syn_patterns), pat_count) != FAIL --- 5218,5224 ---- * Check for trailing garbage or command. * If OK, add the item. */ ! set_nextcmd(eap, rest); if (!ends_excmd(*rest) || eap->skip) rest = NULL; else if (ga_grow(&(curwin->w_s->b_syn_patterns), pat_count) != FAIL *************** *** 5896,5902 **** semsg(_("E404: Illegal arguments: %s"), arg_start); else if (!finished) { ! eap->nextcmd = check_nextcmd(arg_start); redraw_curbuf_later(SOME_VALID); syn_stack_free_all(curwin->w_s); // Need to recompute all syntax. } --- 5896,5902 ---- semsg(_("E404: Illegal arguments: %s"), arg_start); else if (!finished) { ! set_nextcmd(eap, arg_start); redraw_curbuf_later(SOME_VALID); syn_stack_free_all(curwin->w_s); // Need to recompute all syntax. } *** ../vim-8.2.3296/src/userfunc.c 2021-08-01 22:01:25.985012239 +0200 --- src/userfunc.c 2021-08-05 20:20:05.501617362 +0200 *************** *** 3842,3848 **** { if (!eap->skip) list_functions(NULL); ! eap->nextcmd = check_nextcmd(eap->arg); return NULL; } --- 3842,3848 ---- { if (!eap->skip) list_functions(NULL); ! set_nextcmd(eap, eap->arg); return NULL; } *************** *** 3869,3875 **** } if (*p == '/') ++p; ! eap->nextcmd = check_nextcmd(p); return NULL; } --- 3869,3875 ---- } if (*p == '/') ++p; ! set_nextcmd(eap, p); return NULL; } *************** *** 3947,3953 **** semsg(_(e_trailing_arg), p); goto ret_free; } ! eap->nextcmd = check_nextcmd(p); if (eap->nextcmd != NULL) *p = NUL; if (!eap->skip && !got_int) --- 3947,3953 ---- semsg(_(e_trailing_arg), p); goto ret_free; } ! set_nextcmd(eap, p); if (eap->nextcmd != NULL) *p = NUL; if (!eap->skip && !got_int) *************** *** 4655,4661 **** semsg(_(e_trailing_arg), p); return; } ! eap->nextcmd = check_nextcmd(p); if (eap->nextcmd != NULL) *p = NUL; --- 4655,4661 ---- semsg(_(e_trailing_arg), p); return; } ! set_nextcmd(eap, p); if (eap->nextcmd != NULL) *p = NUL; *************** *** 4844,4850 **** if (returning) eap->nextcmd = NULL; else if (eap->nextcmd == NULL) // no argument ! eap->nextcmd = check_nextcmd(arg); if (eap->skip) --emsg_skip; --- 4844,4850 ---- if (returning) eap->nextcmd = NULL; else if (eap->nextcmd == NULL) // no argument ! set_nextcmd(eap, arg); if (eap->skip) --emsg_skip; *************** *** 5004,5010 **** } } else ! eap->nextcmd = check_nextcmd(arg); } end: --- 5004,5010 ---- } } else ! set_nextcmd(eap, arg); } end: *** ../vim-8.2.3296/src/vim9compile.c 2021-08-05 19:01:12.294746361 +0200 --- src/vim9compile.c 2021-08-05 20:20:17.717577500 +0200 *************** *** 5691,5697 **** name_end = skip_regexp(name_start + 1, '/', TRUE); if (*name_end == '/') ++name_end; ! eap->nextcmd = check_nextcmd(name_end); } if (name_end == name_start || *skipwhite(name_end) != '(') { --- 5691,5697 ---- name_end = skip_regexp(name_start + 1, '/', TRUE); if (*name_end == '/') ++name_end; ! set_nextcmd(eap, name_end); } if (name_end == name_start || *skipwhite(name_end) != '(') { *** ../vim-8.2.3296/src/vim9script.c 2021-07-29 22:48:50.103129907 +0200 --- src/vim9script.c 2021-08-05 20:20:28.917541061 +0200 *************** *** 311,317 **** cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid, &evalarg, NULL); if (cmd_end != NULL) ! eap->nextcmd = check_nextcmd(cmd_end); clear_evalarg(&evalarg, eap); } --- 311,317 ---- cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid, &evalarg, NULL); if (cmd_end != NULL) ! set_nextcmd(eap, cmd_end); clear_evalarg(&evalarg, eap); } *** ../vim-8.2.3296/src/errors.h 2021-08-04 19:25:50.614808524 +0200 --- src/errors.h 2021-08-05 20:34:28.183003921 +0200 *************** *** 643,646 **** EXTERN char e_expected_dictionary_for_using_key_str_but_got_str[] INIT(= N_("E1229: Expected dictionary for using key \"%s\", but got %s")); EXTERN char e_encryption_sodium_mlock_failed[] ! INIT(= N_("E1230: encryption: sodium_mlock() failed")); --- 643,648 ---- EXTERN char e_expected_dictionary_for_using_key_str_but_got_str[] INIT(= N_("E1229: Expected dictionary for using key \"%s\", but got %s")); EXTERN char e_encryption_sodium_mlock_failed[] ! INIT(= N_("E1230: Encryption: sodium_mlock() failed")); ! EXTERN char e_cannot_use_bar_to_separate_commands_here_str[] ! INIT(= N_("E1231: Cannot use a bar to separate commands here: %s")); *** ../vim-8.2.3296/src/testdir/test_autocmd.vim 2021-08-01 14:52:05.558645405 +0200 --- src/testdir/test_autocmd.vim 2021-08-05 19:35:56.697417515 +0200 *************** *** 2816,2826 **** --- 2816,2834 ---- setlocal matchpairs+=<:> /