vim-patch:9.1.1807: :set doesn't clear local insecure flag like :setlocal does

Problem:  :set doesn't clear local insecure flag like :setlocal does.
Solution: Also clear the local insecure flag when using :set (zeertzjq).

This applies to local options like 'wrap', 'foldtext' and 'foldexpr',
whose global flags are actually never used.  For global-local options
like 'statusline' the behavior is already correct, so add some tests.

related: vim/vim#18434

fec5586a45
(cherry picked from commit ff564237d2)
This commit is contained in:
zeertzjq
2025-09-30 06:28:22 +08:00
committed by github-actions[bot]
parent 9c09983068
commit 67688ab616
4 changed files with 181 additions and 28 deletions

View File

@@ -485,6 +485,7 @@ static void change_option_default(const OptIndex opt_idx, OptVal value)
/// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination).
static void set_option_default(const OptIndex opt_idx, int opt_flags) static void set_option_default(const OptIndex opt_idx, int opt_flags)
{ {
bool both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
OptVal def_val = get_option_default(opt_idx, opt_flags); OptVal def_val = get_option_default(opt_idx, opt_flags);
set_option_direct(opt_idx, def_val, opt_flags, current_sctx.sc_sid); set_option_direct(opt_idx, def_val, opt_flags, current_sctx.sc_sid);
@@ -495,6 +496,10 @@ static void set_option_default(const OptIndex opt_idx, int opt_flags)
// The default value is not insecure. // The default value is not insecure.
uint32_t *flagsp = insecure_flag(curwin, opt_idx, opt_flags); uint32_t *flagsp = insecure_flag(curwin, opt_idx, opt_flags);
*flagsp = *flagsp & ~(unsigned)kOptFlagInsecure; *flagsp = *flagsp & ~(unsigned)kOptFlagInsecure;
if (both) {
flagsp = insecure_flag(curwin, opt_idx, OPT_LOCAL);
*flagsp = *flagsp & ~(unsigned)kOptFlagInsecure;
}
} }
/// Set all options (except terminal options) to their default value. /// Set all options (except terminal options) to their default value.
@@ -3550,15 +3555,22 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value
check_redraw(opt->flags); check_redraw(opt->flags);
if (errmsg == NULL) { if (errmsg == NULL) {
uint32_t *p = insecure_flag(curwin, opt_idx, opt_flags);
opt->flags |= kOptFlagWasSet; opt->flags |= kOptFlagWasSet;
// When an option is set in the sandbox, from a modeline or in secure mode set the kOptFlagInsecure uint32_t *flagsp = insecure_flag(curwin, opt_idx, opt_flags);
// flag. Otherwise, if a new value is stored reset the flag. uint32_t *flagsp_local = scope_both ? insecure_flag(curwin, opt_idx, OPT_LOCAL) : NULL;
// When an option is set in the sandbox, from a modeline or in secure mode set the
// kOptFlagInsecure flag. Otherwise, if a new value is stored reset the flag.
if (!value_checked && (secure || sandbox != 0 || (opt_flags & OPT_MODELINE))) { if (!value_checked && (secure || sandbox != 0 || (opt_flags & OPT_MODELINE))) {
*p |= kOptFlagInsecure; *flagsp |= kOptFlagInsecure;
if (flagsp_local != NULL) {
*flagsp_local |= kOptFlagInsecure;
}
} else if (value_replaced) { } else if (value_replaced) {
*p &= ~(unsigned)kOptFlagInsecure; *flagsp &= ~(unsigned)kOptFlagInsecure;
if (flagsp_local != NULL) {
*flagsp_local &= ~(unsigned)kOptFlagInsecure;
}
} }
} }

View File

@@ -1499,7 +1499,7 @@ endfunc
" in a sandbox " in a sandbox
func Test_foldtext_in_modeline() func Test_foldtext_in_modeline()
func ModelineFoldText() func ModelineFoldText()
call feedkeys('aFoo', 'xt') call writefile(['after'], 'Xmodelinefoldtext_write')
return "folded text" return "folded text"
endfunc endfunc
let lines =<< trim END let lines =<< trim END
@@ -1510,24 +1510,51 @@ func Test_foldtext_in_modeline()
END END
call writefile(lines, 'Xmodelinefoldtext', 'D') call writefile(lines, 'Xmodelinefoldtext', 'D')
func Check_foldtext_in_modeline(set_cmd)
call writefile(['before'], 'Xmodelinefoldtext_write', 'D')
split Xmodelinefoldtext
call cursor(1, 1)
normal! zf3j
call assert_equal('folded text', foldtextresult(1))
call assert_equal(['before'], readfile('Xmodelinefoldtext_write'))
setglobal foldtext=ModelineFoldText()
call assert_equal('folded text', foldtextresult(1))
call assert_equal(['before'], readfile('Xmodelinefoldtext_write'))
setglobal foldtext&
call assert_equal('folded text', foldtextresult(1))
call assert_equal(['before'], readfile('Xmodelinefoldtext_write'))
exe a:set_cmd 'foldtext=ModelineFoldText()'
call assert_equal('folded text', foldtextresult(1))
call assert_equal(['after'], readfile('Xmodelinefoldtext_write'))
call writefile(['before'], 'Xmodelinefoldtext_write')
exe 'sandbox' a:set_cmd 'foldtext=ModelineFoldText()'
call assert_equal('folded text', foldtextresult(1))
call assert_equal(['before'], readfile('Xmodelinefoldtext_write'))
exe a:set_cmd 'foldtext=ModelineFoldText()'
call assert_equal('folded text', foldtextresult(1))
call assert_equal(['after'], readfile('Xmodelinefoldtext_write'))
bw!
endfunc
set modeline modelineexpr set modeline modelineexpr
split Xmodelinefoldtext call Check_foldtext_in_modeline('setlocal')
call Check_foldtext_in_modeline('set')
call cursor(1, 1)
normal! zf3j
call assert_equal('folded text', foldtextresult(1))
call assert_equal(lines, getbufline('', 1, '$'))
bw!
set modeline& modelineexpr& set modeline& modelineexpr&
delfunc ModelineFoldText delfunc ModelineFoldText
delfunc Check_foldtext_in_modeline
endfunc endfunc
" Test for setting 'foldexpr' from the modeline and executing the expression " Test for setting 'foldexpr' from the modeline and executing the expression
" in a sandbox " in a sandbox
func Test_foldexpr_in_modeline() func Test_foldexpr_in_modeline()
func ModelineFoldExpr() func ModelineFoldExpr()
call feedkeys('aFoo', 'xt') call writefile(['after'], 'Xmodelinefoldexpr_write')
return strlen(matchstr(getline(v:lnum),'^\s*')) return strlen(matchstr(getline(v:lnum),'^\s*'))
endfunc endfunc
let lines =<< trim END let lines =<< trim END
@@ -1541,15 +1568,42 @@ func Test_foldexpr_in_modeline()
END END
call writefile(lines, 'Xmodelinefoldexpr', 'D') call writefile(lines, 'Xmodelinefoldexpr', 'D')
func Check_foldexpr_in_modeline(set_cmd)
call writefile(['before'], 'Xmodelinefoldexpr_write', 'D')
split Xmodelinefoldexpr
call assert_equal(2, foldlevel(3))
call assert_equal(['before'], readfile('Xmodelinefoldexpr_write'))
setglobal foldexpr=ModelineFoldExpr()
call assert_equal(2, foldlevel(3))
call assert_equal(['before'], readfile('Xmodelinefoldexpr_write'))
setglobal foldexpr&
call assert_equal(2, foldlevel(3))
call assert_equal(['before'], readfile('Xmodelinefoldexpr_write'))
exe a:set_cmd 'foldexpr=ModelineFoldExpr()'
call assert_equal(2, foldlevel(3))
call assert_equal(['after'], readfile('Xmodelinefoldexpr_write'))
call writefile(['before'], 'Xmodelinefoldexpr_write')
exe 'sandbox' a:set_cmd 'foldexpr=ModelineFoldExpr()'
call assert_equal(2, foldlevel(3))
call assert_equal(['before'], readfile('Xmodelinefoldexpr_write'))
exe a:set_cmd 'foldexpr=ModelineFoldExpr()'
call assert_equal(2, foldlevel(3))
call assert_equal(['after'], readfile('Xmodelinefoldexpr_write'))
bw!
endfunc
set modeline modelineexpr set modeline modelineexpr
split Xmodelinefoldexpr call Check_foldexpr_in_modeline('setlocal')
call Check_foldexpr_in_modeline('set')
call assert_equal(2, foldlevel(3))
call assert_equal(lines, getbufline('', 1, '$'))
bw!
set modeline& modelineexpr& set modeline& modelineexpr&
delfunc ModelineFoldExpr delfunc ModelineFoldExpr
delfunc Check_foldexpr_in_modeline
endfunc endfunc
" Make sure a fold containing a nested fold is split correctly when using " Make sure a fold containing a nested fold is split correctly when using

View File

@@ -384,8 +384,22 @@ func Test_modeline_nowrap_lcs_extends()
\ ], 'Xmodeline_nowrap', 'D') \ ], 'Xmodeline_nowrap', 'D')
call NewWindow(10, 20) call NewWindow(10, 20)
func Check_modeline_nowrap(expect_insecure, expect_secure, set_cmd)
edit Xmodeline_nowrap
call assert_equal(a:expect_insecure, ScreenLines([1, 5], 20))
setglobal nowrap
call assert_equal(a:expect_insecure, ScreenLines([1, 5], 20))
setglobal wrap
call assert_equal(a:expect_insecure, ScreenLines([1, 5], 20))
exe a:set_cmd 'nowrap'
call assert_equal(a:expect_secure, ScreenLines([1, 5], 20))
exe 'sandbox' a:set_cmd 'nowrap'
call assert_equal(a:expect_insecure, ScreenLines([1, 5], 20))
exe a:set_cmd 'nowrap'
call assert_equal(a:expect_secure, ScreenLines([1, 5], 20))
endfunc
setlocal nolist listchars= setlocal nolist listchars=
edit Xmodeline_nowrap
let expect_insecure = [ let expect_insecure = [
\ 'aaa ', \ 'aaa ',
\ 'bbb ', \ 'bbb ',
@@ -393,9 +407,6 @@ func Test_modeline_nowrap_lcs_extends()
\ 'ddd >', \ 'ddd >',
\ '~ ', \ '~ ',
\ ] \ ]
call assert_equal(expect_insecure, ScreenLines([1, 5], 20))
setlocal nowrap
let expect_secure = [ let expect_secure = [
\ 'aaa ', \ 'aaa ',
\ 'bbb ', \ 'bbb ',
@@ -403,7 +414,8 @@ func Test_modeline_nowrap_lcs_extends()
\ 'ddd ', \ 'ddd ',
\ '~ ', \ '~ ',
\ ] \ ]
call assert_equal(expect_secure, ScreenLines([1, 5], 20)) call Check_modeline_nowrap(expect_insecure, expect_secure, 'setlocal')
call Check_modeline_nowrap(expect_insecure, expect_secure, 'set')
setlocal list listchars=extends:+ setlocal list listchars=extends:+
let expect_secure = [ let expect_secure = [
@@ -414,13 +426,45 @@ func Test_modeline_nowrap_lcs_extends()
\ '~ ', \ '~ ',
\ ] \ ]
call assert_equal(expect_secure, ScreenLines([1, 5], 20)) call assert_equal(expect_secure, ScreenLines([1, 5], 20))
call Check_modeline_nowrap(expect_insecure, expect_secure, 'setlocal')
call Check_modeline_nowrap(expect_insecure, expect_secure, 'set')
edit Xmodeline_nowrap " Other 'listchars' flags are not affected.
call assert_equal(expect_insecure, ScreenLines([1, 5], 20)) call writefile([
setlocal nowrap \ "aa\ta",
call assert_equal(expect_secure, ScreenLines([1, 5], 20)) \ "bb\tb",
\ "cc\tc evil",
\ "dd\td vim: nowrap lcs=tab\\:<->",
\ ], 'Xmodeline_nowrap')
let expect_insecure = [
\ 'aa<---->a ',
\ 'bb<---->b ',
\ 'cc<---->c >',
\ 'dd<---->d >',
\ '~ ',
\ ]
let expect_secure = [
\ 'aa<---->a ',
\ 'bb<---->b ',
\ 'cc<---->c ',
\ 'dd<---->d ',
\ '~ ',
\ ]
call Check_modeline_nowrap(expect_insecure, expect_secure, 'setlocal')
call Check_modeline_nowrap(expect_insecure, expect_secure, 'set')
" Same behavior even if modeline sets "extends" to a space.
call writefile([
\ "aa\ta",
\ "bb\tb",
\ "cc\tc evil",
\ "dd\td vim: nowrap lcs=tab\\:<->",
\ ], 'Xmodeline_nowrap')
call Check_modeline_nowrap(expect_insecure, expect_secure, 'setlocal')
call Check_modeline_nowrap(expect_insecure, expect_secure, 'set')
call CloseWindow() call CloseWindow()
delfunc Check_modeline_nowrap
endfunc endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab

View File

@@ -639,4 +639,47 @@ func Test_statusline_highlight_group_cleared()
call StopVimInTerminal(buf) call StopVimInTerminal(buf)
endfunc endfunc
" Test for setting both global and local 'statusline' values in a sandbox
func Test_statusline_in_sandbox()
func SandboxStatusLine()
call writefile(['after'], 'Xsandboxstatusline_write')
return "status line"
endfunc
func Check_statusline_in_sandbox(set_cmd0, set_cmd1)
new | only
call writefile(['before'], 'Xsandboxstatusline_write', 'D')
setlocal statusline=
exe 'sandbox' a:set_cmd0 'statusline=%!SandboxStatusLine()'
call assert_equal('', &l:statusline)
sandbox setlocal statusline=%!SandboxStatusLine()
call assert_fails('redrawstatus', 'E48:')
call assert_equal(['before'], readfile('Xsandboxstatusline_write'))
setlocal statusline=%!SandboxStatusLine() | redrawstatus
call assert_equal('status line', Screenline(&lines - 1))
call assert_equal(['after'], readfile('Xsandboxstatusline_write'))
call writefile(['before'], 'Xsandboxstatusline_write')
setlocal statusline=
call assert_fails('redrawstatus', 'E48:')
call assert_equal(['before'], readfile('Xsandboxstatusline_write'))
exe a:set_cmd1 'statusline=%!SandboxStatusLine()' | redrawstatus
call assert_equal('', &l:statusline)
call assert_equal('status line', Screenline(&lines - 1))
call assert_equal(['after'], readfile('Xsandboxstatusline_write'))
bw!
endfunc
call Check_statusline_in_sandbox('setglobal', 'setglobal')
call Check_statusline_in_sandbox('setglobal', 'set')
call Check_statusline_in_sandbox('set', 'setglobal')
call Check_statusline_in_sandbox('set', 'set')
set statusline&
delfunc SandboxStatusLine
delfunc Check_statusline_in_sandbox
endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab