patch 9.2.1132: skip condition not considered for certain commands

Problem:  "if 0" condition not correctly skipped for :command, :autocmd,
          :class, :interface, :enum and :loadkeymap
Solution: Skip those commands and discard the blocks they read
          (Hirohito Higashi).

closes: #21349

Assisted-by: Claude
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Hirohito Higashi authored and Christian Brabandt committed 2026-09-25 21:49:38 +00:00
1 parent 33402ca930
commit f3dc0fee77
9 files changed
+157

No files matched your search

+8
View File
@@ -2299,6 +2299,14 @@ ex_loadkeymap(exarg_T *eap)
return;
}
if (eap->skip)
{
// The rest of the script is the keymap, read it and throw it away.
while ((line = eap->ea_getline(0, eap->cookie, 0, TRUE)) != NULL)
vim_free(line);
return;
}
/*
* Stop any active keymap and clear the table.
*/
+16
View File
@@ -2526,6 +2526,16 @@ do_one_cmd(
case CMD_def:
break;
// commands that read a block of lines
case CMD_abstract:
case CMD_autocmd:
case CMD_class:
case CMD_command:
case CMD_enum:
case CMD_interface:
case CMD_loadkeymap:
break;
// Commands that handle '|' themselves. Check: A command should
// either have the EX_TRLBAR flag, appear in this list or appear in
// the list at ":help :bar".
@@ -5834,6 +5844,12 @@ expand_argopt(
static void
ex_autocmd(exarg_T *eap)
{
if (eap->skip)
{
skip_cmd_block(eap);
return;
}
/*
* Disallow autocommands from .exrc and .vimrc in current
* directory for security reasons.
+1
View File
@@ -15,6 +15,7 @@ int cmdcomplete_str_to_type(char_u *complete_str);
char *uc_fun_cmd(void);
int parse_compl_arg(char_u *value, int vallen, int *complp, long *argt, char_u **compl_arg);
char_u *may_get_cmd_block(exarg_T *eap, char_u *p, char_u **tofree, int *flags);
void skip_cmd_block(exarg_T *eap);
void ex_command(exarg_T *eap);
void ex_comclear(exarg_T *eap);
void uc_clear(garray_T *gap);
+9
View File
@@ -505,6 +505,15 @@ func Test_loadkeymap_error()
call assert_fails('source Xkeymap', 'E791:')
endfunc
" Test for ":loadkeymap" in a block that is not executed: it reads the rest of
" the script, so that rest, the "endif" with it, is thrown away instead of
" being read as commands.
func Test_loadkeymap_skipped()
CheckFeature keymap
call writefile(['if 0', ' loadkeymap', ' a b', 'endif'], 'Xkeymap', 'D')
call assert_fails('source Xkeymap', 'E171:')
endfunc
" Test for the characters displayed on the screen when entering a digraph
func Test_entering_digraph()
CheckRunVimInTerminal
+37
View File
@@ -1276,4 +1276,41 @@ func Test_command_list_0()
delcommand VeryMuchLongerCommand
endfunc
" Test for a block of ":command" or ":autocmd" in a block that is not
" executed: the lines up to the "}" are skipped, not parsed as commands.
func Test_command_block_skipped()
let lines =<< trim END
vim9script
def Something(s: string)
echo s
enddef
if 0
command! -bar -nargs=? Xfoo {
Something(<q-args>)
}
endif
if 0
autocmd BufRead *.xyz {
Something(<q-args>)
}
endif
while 0
command! Xbar {
Something('x')
}
endwhile
g:skipped = 'all three'
END
call writefile(lines, 'Xcmdblock.vim', 'D')
let g:skipped = ''
source Xcmdblock.vim
call assert_equal('all three', g:skipped)
call assert_equal(0, exists(':Xfoo'))
call assert_equal(0, exists(':Xbar'))
call assert_notmatch('xyz', execute('autocmd BufRead'))
unlet g:skipped
endfunc
" vim: shiftwidth=2 sts=2 expandtab
+29
View File
@@ -11965,4 +11965,33 @@ def Test_nested_object_member_op_assign()
v9.CheckSourceSuccess(lines)
enddef
" Test for a class, interface or enum in a block that is not executed: the
" body is skipped, not read as commands.
def Test_class_body_skipped()
var lines =<< trim END
vim9script
if 0
interface Bar
def M(): number
endinterface
endif
if 0
class Foo
var x: number = 1
endclass
endif
while 0
enum Baz
One,
Two
endenum
endwhile
g:skipped = 'all three'
END
g:skipped = ''
v9.CheckSourceSuccess(lines)
assert_equal('all three', g:skipped)
unlet g:skipped
enddef
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
+20
View File
@@ -1372,6 +1372,20 @@ may_get_cmd_block(exarg_T *eap, char_u *p, char_u **tofree, int *flags)
return retp;
}
/*
* Read the block of commands that may follow and throw it away.
* Used for ":command" and ":autocmd" while skipping.
*/
void
skip_cmd_block(exarg_T *eap)
{
char_u *tofree = NULL;
int flags = 0;
(void)may_get_cmd_block(eap, eap->cmd, &tofree, &flags);
vim_free(tofree);
}
/*
* ":command ..." implementation
*/
@@ -1391,6 +1405,12 @@ ex_command(exarg_T *eap)
int has_attr = (eap->arg[0] == '-');
int name_len;
if (eap->skip)
{
skip_cmd_block(eap);
return;
}
p = eap->arg;
// Check for attributes
+2
View File
@@ -763,6 +763,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1132,
/**/
1131,
/**/
+35
View File
@@ -1934,6 +1934,35 @@ enum_set_internal_obj_vars(class_T *en, object_T *enval)
ord_tv->vval.v_number = i;
}
/*
* Read the body up to ":endclass", ":endenum" or ":endinterface" and throw it
* away. Used while skipping.
*/
static void
skip_class_body(exarg_T *eap)
{
for (;;)
{
char_u *theline = eap->ea_getline(':', eap->cookie, 0,
GETLINE_CONCAT_ALL);
if (theline == NULL)
break;
char_u *p = theline;
int found;
// skip ':' and blanks
for (; VIM_ISWHITE(*p) || *p == ':'; ++p)
;
found = checkforcmd(&p, "endclass", 4)
|| checkforcmd(&p, "endenum", 4)
|| checkforcmd(&p, "endinterface", 5);
vim_free(theline);
if (found)
break;
}
}
/*
* Handle ":class" and ":abstract class" up to ":endclass".
* Handle ":enum" up to ":endenum".
@@ -1950,6 +1979,12 @@ ex_class(exarg_T *eap)
long start_lnum = SOURCING_LNUM;
char_u *arg = eap->arg;
if (eap->skip)
{
skip_class_body(eap);
return;
}
if (is_abstract)
{
if (STRNCMP(arg, "class", 5) != 0 || !VIM_ISWHITE(arg[5]))