To: vim_dev@googlegroups.com Subject: Patch 8.2.2138 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2138 Problem: Vim9: "exit_cb" causes Vim to exit. Solution: Require white space after a command in Vim9 script. (closes #7467) Also fix that Vim9 style heredoc was not always recognized. Files: src/ex_cmds.h, src/ex_docmd.c, src/errors.h, src/userfunc.c, src/testdir/test_vim9_assign.vim, src/testdir/test_vim9_script.vim, src/testdir/test_let.vim *** ../vim-8.2.2137/src/ex_cmds.h 2020-11-14 17:25:44.868329693 +0100 --- src/ex_cmds.h 2020-12-13 15:05:18.625003271 +0100 *************** *** 55,60 **** --- 55,61 ---- #define EX_LOCK_OK 0x1000000 // command can be executed when textlock is // set; when missing disallows editing another // buffer when curbuf_lock is set + #define EX_NONWHITE_OK 0x2000000 // command can be followed by non-white #define EX_FILES (EX_XFILE | EX_EXTRA) // multiple extra files allowed #define EX_FILE1 (EX_FILES | EX_NOSPC) // 1 file, defaults to current file *************** *** 632,638 **** EX_EXTRA|EX_BANG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), EXCMD(CMD_global, "global", ex_global, ! EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_EXTRA|EX_DFLALL|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK, ADDR_LINES), EXCMD(CMD_goto, "goto", ex_goto, EX_RANGE|EX_COUNT|EX_TRLBAR|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK, --- 633,639 ---- EX_EXTRA|EX_BANG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), EXCMD(CMD_global, "global", ex_global, ! EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_EXTRA|EX_DFLALL|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK, ADDR_LINES), EXCMD(CMD_goto, "goto", ex_goto, EX_RANGE|EX_COUNT|EX_TRLBAR|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK, *************** *** 1277,1283 **** EX_BANG|EX_FILE1|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), EXCMD(CMD_substitute, "substitute", ex_substitute, ! EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK, ADDR_LINES), EXCMD(CMD_sNext, "sNext", ex_previous, EX_EXTRA|EX_RANGE|EX_COUNT|EX_BANG|EX_CMDARG|EX_ARGOPT|EX_TRLBAR, --- 1278,1284 ---- EX_BANG|EX_FILE1|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), EXCMD(CMD_substitute, "substitute", ex_substitute, ! EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK, ADDR_LINES), EXCMD(CMD_sNext, "sNext", ex_previous, EX_EXTRA|EX_RANGE|EX_COUNT|EX_BANG|EX_CMDARG|EX_ARGOPT|EX_TRLBAR, *************** *** 1652,1658 **** EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_FILE1|EX_ARGOPT|EX_DFLALL|EX_TRLBAR, ADDR_LINES), EXCMD(CMD_vglobal, "vglobal", ex_global, ! EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_DFLALL|EX_CMDWIN|EX_LOCK_OK, ADDR_LINES), EXCMD(CMD_var, "var", ex_var, EX_EXTRA|EX_NOTRLCOM|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK, --- 1653,1659 ---- EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_FILE1|EX_ARGOPT|EX_DFLALL|EX_TRLBAR, ADDR_LINES), EXCMD(CMD_vglobal, "vglobal", ex_global, ! EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_DFLALL|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK, ADDR_LINES), EXCMD(CMD_var, "var", ex_var, EX_EXTRA|EX_NOTRLCOM|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK, *************** *** 1792,1807 **** // commands that don't start with a letter EXCMD(CMD_bang, "!", ex_bang, ! EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_FILES|EX_CMDWIN|EX_LOCK_OK, ADDR_LINES), EXCMD(CMD_pound, "#", ex_print, EX_RANGE|EX_WHOLEFOLD|EX_COUNT|EX_FLAGS|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_LINES), EXCMD(CMD_and, "&", ex_substitute, ! EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY, ADDR_LINES), EXCMD(CMD_star, "*", ex_at, ! EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_LINES), EXCMD(CMD_lshift, "<", ex_operators, EX_RANGE|EX_WHOLEFOLD|EX_COUNT|EX_FLAGS|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY, --- 1793,1808 ---- // commands that don't start with a letter EXCMD(CMD_bang, "!", ex_bang, ! EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_FILES|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK, ADDR_LINES), EXCMD(CMD_pound, "#", ex_print, EX_RANGE|EX_WHOLEFOLD|EX_COUNT|EX_FLAGS|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_LINES), EXCMD(CMD_and, "&", ex_substitute, ! EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY|EX_NONWHITE_OK, ADDR_LINES), EXCMD(CMD_star, "*", ex_at, ! EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK, ADDR_LINES), EXCMD(CMD_lshift, "<", ex_operators, EX_RANGE|EX_WHOLEFOLD|EX_COUNT|EX_FLAGS|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY, *************** *** 1813,1819 **** EX_RANGE|EX_WHOLEFOLD|EX_COUNT|EX_FLAGS|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY, ADDR_LINES), EXCMD(CMD_at, "@", ex_at, ! EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_LINES), EXCMD(CMD_block, "{{{{{{{{", ex_block, // not found normally 0, --- 1814,1820 ---- EX_RANGE|EX_WHOLEFOLD|EX_COUNT|EX_FLAGS|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY, ADDR_LINES), EXCMD(CMD_at, "@", ex_at, ! EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK, ADDR_LINES), EXCMD(CMD_block, "{{{{{{{{", ex_block, // not found normally 0, *************** *** 1822,1828 **** EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), EXCMD(CMD_tilde, "~", ex_substitute, ! EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY, ADDR_LINES), // commands that start with an uppercase letter --- 1823,1829 ---- EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), EXCMD(CMD_tilde, "~", ex_substitute, ! EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY|EX_NONWHITE_OK, ADDR_LINES), // commands that start with an uppercase letter *** ../vim-8.2.2137/src/ex_docmd.c 2020-12-12 21:25:52.837244962 +0100 --- src/ex_docmd.c 2020-12-13 15:00:13.226108961 +0100 *************** *** 3528,3533 **** --- 3528,3541 ---- if (eap->cmdidx == CMD_final && p - eap->cmd == 4) eap->cmdidx = CMD_finally; + if (eap->cmdidx != CMD_SIZE && in_vim9script() + && !IS_WHITE_OR_NUL(*p) && !ends_excmd(*p) && *p != '!' + && (cmdnames[eap->cmdidx].cmd_argt & EX_NONWHITE_OK) == 0) + { + semsg(_(e_command_not_followed_by_white_space_str), eap->cmd); + eap->cmdidx = CMD_SIZE; + } + return p; } *************** *** 5114,5120 **** /* * Check if "c" ends an Ex command. ! * In Vim9 script does not check for white space before # or #{. */ int ends_excmd(int c) --- 5122,5128 ---- /* * Check if "c" ends an Ex command. ! * In Vim9 script does not check for white space before #. */ int ends_excmd(int c) *** ../vim-8.2.2137/src/errors.h 2020-12-13 14:19:22.131979168 +0100 --- src/errors.h 2020-12-13 15:38:24.821893627 +0100 *************** *** 316,319 **** EXTERN char e_non_empty_string_required[] INIT(= N_("E1142: Non-empty string required")); EXTERN char e_empty_expression_str[] ! INIT(= N_("E1143: empty expression: \"%s\"")); --- 316,323 ---- EXTERN char e_non_empty_string_required[] INIT(= N_("E1142: Non-empty string required")); EXTERN char e_empty_expression_str[] ! INIT(= N_("E1143: Empty expression: \"%s\"")); ! EXTERN char e_command_not_followed_by_white_space_str[] ! INIT(= N_("E1144: Command is not followed by white space: %s")); ! EXTERN char e_missing_heredoc_end_marker_str[] ! INIT(= N_("E1145: Missing heredoc end marker: %s")); *** ../vim-8.2.2137/src/userfunc.c 2020-11-22 18:15:40.171258382 +0100 --- src/userfunc.c 2020-12-13 15:38:37.353848980 +0100 *************** *** 3185,3191 **** lines_left = Rows - 1; if (theline == NULL) { ! if (eap->cmdidx == CMD_def) emsg(_(e_missing_enddef)); else emsg(_("E126: Missing :endfunction")); --- 3185,3193 ---- lines_left = Rows - 1; if (theline == NULL) { ! if (skip_until != NULL) ! semsg(_(e_missing_heredoc_end_marker_str), skip_until); ! else if (eap->cmdidx == CMD_def) emsg(_(e_missing_enddef)); else emsg(_("E126: Missing :endfunction")); *************** *** 3352,3369 **** // Check for ":cmd v =<< [trim] EOF" // and ":cmd [a, b] =<< [trim] EOF" // Where "cmd" can be "let", "var", "final" or "const". arg = skipwhite(skiptowhite(p)); if (*arg == '[') arg = vim_strchr(arg, ']'); if (arg != NULL) { ! arg = skipwhite(skiptowhite(arg)); ! if (arg[0] == '=' && arg[1] == '<' && arg[2] =='<' && (checkforcmd(&p, "let", 2) || checkforcmd(&p, "var", 3) || checkforcmd(&p, "final", 5) ! || checkforcmd(&p, "const", 5))) { p = skipwhite(arg + 3); if (STRNCMP(p, "trim", 4) == 0) --- 3354,3377 ---- // Check for ":cmd v =<< [trim] EOF" // and ":cmd [a, b] =<< [trim] EOF" + // and "lines =<< [trim] EOF" for Vim9 // Where "cmd" can be "let", "var", "final" or "const". arg = skipwhite(skiptowhite(p)); if (*arg == '[') arg = vim_strchr(arg, ']'); if (arg != NULL) { ! int found = (eap->cmdidx == CMD_def && arg[0] == '=' ! && arg[1] == '<' && arg[2] =='<'); ! ! if (!found) ! // skip over the argument after "cmd" ! arg = skipwhite(skiptowhite(arg)); ! if (found || (arg[0] == '=' && arg[1] == '<' && arg[2] =='<' && (checkforcmd(&p, "let", 2) || checkforcmd(&p, "var", 3) || checkforcmd(&p, "final", 5) ! || checkforcmd(&p, "const", 5)))) { p = skipwhite(arg + 3); if (STRNCMP(p, "trim", 4) == 0) *** ../vim-8.2.2137/src/testdir/test_vim9_assign.vim 2020-12-08 22:08:47.672125693 +0100 --- src/testdir/test_vim9_assign.vim 2020-12-13 17:32:23.346376617 +0100 *************** *** 982,987 **** --- 982,998 ---- var&lines =<< trim END x x + enddef + defcompile + [END] + CheckScriptFailure(lines, 'E1145: Missing heredoc end marker: END') + delfunc! g:Func + + lines =<< trim [END] + def Func() + var lines =<< trim END + x + x x x x *************** *** 991,997 **** enddef call Func() [END] ! CheckScriptFailure(lines, 'E990:') delfunc! g:Func enddef --- 1002,1008 ---- enddef call Func() [END] ! CheckScriptFailure(lines, 'E1145: Missing heredoc end marker: END') delfunc! g:Func enddef *** ../vim-8.2.2137/src/testdir/test_vim9_script.vim 2020-12-13 14:19:22.131979168 +0100 --- src/testdir/test_vim9_script.vim 2020-12-13 15:01:09.653903594 +0100 *************** *** 3058,3064 **** new var lines =<< trim END vim9script ! pu=split('abc', '\zs') ->join() END CheckScriptSuccess(lines) --- 3058,3064 ---- new var lines =<< trim END vim9script ! pu =split('abc', '\zs') ->join() END CheckScriptSuccess(lines) *************** *** 3079,3084 **** --- 3079,3091 ---- xunmap enddef + def Test_white_space_after_command() + var lines =<< trim END + exit_cb: Func}) + END + CheckDefAndScriptFailure(lines, 'E1144:', 1) + enddef + " Keep this last, it messes up highlighting. def Test_substitute_cmd() new *** ../vim-8.2.2137/src/testdir/test_let.vim 2020-09-04 21:18:40.484161926 +0200 --- src/testdir/test_let.vim 2020-12-13 17:48:23.775328713 +0100 *************** *** 338,344 **** endfunc END call writefile(text, 'XheredocFail') ! call assert_fails('source XheredocFail', 'E126:') call delete('XheredocFail') let text =<< trim CodeEnd --- 338,344 ---- endfunc END call writefile(text, 'XheredocFail') ! call assert_fails('source XheredocFail', 'E1145:') call delete('XheredocFail') let text =<< trim CodeEnd *************** *** 347,353 **** endfunc CodeEnd call writefile(text, 'XheredocWrong') ! call assert_fails('source XheredocWrong', 'E126:') call delete('XheredocWrong') let text =<< trim TEXTend --- 347,353 ---- endfunc CodeEnd call writefile(text, 'XheredocWrong') ! call assert_fails('source XheredocWrong', 'E1145:') call delete('XheredocWrong') let text =<< trim TEXTend *** ../vim-8.2.2137/src/version.c 2020-12-13 14:19:22.131979168 +0100 --- src/version.c 2020-12-13 14:50:00.388395996 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2138, /**/ -- FATAL ERROR! SYSTEM HALTED! - Press any key to continue doing nothing. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///