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:
1 parent
33402ca930
commit
f3dc0fee77
9 files changed
+157
No files matched your search
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -763,6 +763,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1132,
|
||||
/**/
|
||||
1131,
|
||||
/**/
|
||||
|
||||
@@ -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]))
|
||||
|
||||
Reference in new issue
Block a user