From 7603f9a6a257aaab16967f9fe1705ca4749792de Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 17 Dec 2025 07:57:28 +0800 Subject: [PATCH] :setlocal changes effective global 'omnifunc' Problem: :setlocal changes effective global 'omnifunc'. Solution: Don't change global callback when using :setlocal. fixes: #18948 --- src/insexpand.c | 35 +++++++++++++------ src/tag.c | 25 +++++++------ src/testdir/test_ins_complete.vim | 58 +++++++++++++++++++++++++++++++ src/testdir/test_tagfunc.vim | 30 ++++++++++++++-- 4 files changed, 122 insertions(+), 26 deletions(-) diff --git a/src/insexpand.c b/src/insexpand.c index b44f77d5316c0..30a89df96c820 100644 --- a/src/insexpand.c +++ b/src/insexpand.c @@ -3319,14 +3319,21 @@ copy_global_to_buflocal_cb(callback_T *globcb, callback_T *bufcb) * lambda expression. */ char * -did_set_completefunc(optset_T *args UNUSED) +did_set_completefunc(optset_T *args) { - if (option_set_callback_func(curbuf->b_p_cfu, &cfu_cb) == FAIL) - return e_invalid_argument; + int retval; - set_buflocal_cfu_callback(curbuf); + if (args->os_flags & OPT_LOCAL) + retval = option_set_callback_func(args->os_newval.string, + &curbuf->b_cfu_cb); + else + { + retval = option_set_callback_func(args->os_newval.string, &cfu_cb); + if (retval == OK && !(args->os_flags & OPT_GLOBAL)) + set_buflocal_cfu_callback(curbuf); + } - return NULL; + return retval == FAIL ? e_invalid_argument : NULL; } /* @@ -3348,13 +3355,21 @@ set_buflocal_cfu_callback(buf_T *buf UNUSED) * lambda expression. */ char * -did_set_omnifunc(optset_T *args UNUSED) +did_set_omnifunc(optset_T *args) { - if (option_set_callback_func(curbuf->b_p_ofu, &ofu_cb) == FAIL) - return e_invalid_argument; + int retval; - set_buflocal_ofu_callback(curbuf); - return NULL; + if (args->os_flags & OPT_LOCAL) + retval = option_set_callback_func(args->os_newval.string, + &curbuf->b_ofu_cb); + else + { + retval = option_set_callback_func(args->os_newval.string, &ofu_cb); + if (retval == OK && !(args->os_flags & OPT_GLOBAL)) + set_buflocal_ofu_callback(curbuf); + } + + return retval == FAIL ? e_invalid_argument : NULL; } /* diff --git a/src/tag.c b/src/tag.c index 78d2902770aa5..796fd12a9b250 100644 --- a/src/tag.c +++ b/src/tag.c @@ -170,22 +170,21 @@ static callback_T tfu_cb; // 'tagfunc' callback function * a function (string), or function() or funcref() or a lambda. */ char * -did_set_tagfunc(optset_T *args UNUSED) +did_set_tagfunc(optset_T *args) { -#ifdef FEAT_EVAL - free_callback(&tfu_cb); - free_callback(&curbuf->b_tfu_cb); - - if (*curbuf->b_p_tfu == NUL) - return NULL; - - if (option_set_callback_func(curbuf->b_p_tfu, &tfu_cb) == FAIL) - return e_invalid_argument; + int retval; - copy_callback(&curbuf->b_tfu_cb, &tfu_cb); -#endif + if (args->os_flags & OPT_LOCAL) + retval = option_set_callback_func(args->os_newval.string, + &curbuf->b_tfu_cb); + else + { + retval = option_set_callback_func(args->os_newval.string, &tfu_cb); + if (retval == OK && !(args->os_flags & OPT_GLOBAL)) + set_buflocal_tfu_callback(curbuf); + } - return NULL; + return retval == FAIL ? e_invalid_argument : NULL; } #endif diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim index c2b8c67bc37ef..315b81e49e25e 100644 --- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -2426,6 +2426,35 @@ func Test_completefunc_callback() call feedkeys("A\\\", 'x') call assert_equal([[1, ''], [0, 'five']], g:CompleteFunc2Args) bw! + + #" :setlocal and :setglobal + set completefunc& + setlocal completefunc=function('g:CompleteFunc1',\ [22]) + call setline(1, 'sun') + LET g:CompleteFunc1Args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[22, 1, ''], [22, 0, 'sun']], g:CompleteFunc1Args) + new + call setline(1, 'sun') + LET g:CompleteFunc1Args = [] + call assert_fails('call feedkeys("A\\\", "x")', 'E764:') + call assert_equal([], g:CompleteFunc1Args) + bw! + setglobal completefunc=function('g:CompleteFunc1',\ [23]) + call setline(1, 'sun') + call feedkeys("A\\\", 'x') + call assert_equal([[22, 1, ''], [22, 0, 'sun']], g:CompleteFunc1Args) + new + call setline(1, 'sun') + LET g:CompleteFunc1Args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[23, 1, ''], [23, 0, 'sun']], g:CompleteFunc1Args) + setlocal completefunc& + call setline(1, 'sun') + LET g:CompleteFunc1Args = [] + call assert_fails('call feedkeys("A\\\", "x")', 'E764:') + call assert_equal([], g:CompleteFunc1Args) + :%bw! END call v9.CheckLegacyAndVim9Success(lines) @@ -2700,6 +2729,35 @@ func Test_omnifunc_callback() call feedkeys("A\\\", 'x') call assert_equal([[1, ''], [0, 'nine']], g:OmniFunc2Args) bw! + + #" :setlocal and :setglobal + set omnifunc& + setlocal omnifunc=function('g:OmniFunc1',\ [22]) + call setline(1, 'sun') + LET g:OmniFunc1Args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[22, 1, ''], [22, 0, 'sun']], g:OmniFunc1Args) + new + call setline(1, 'sun') + LET g:OmniFunc1Args = [] + call assert_fails('call feedkeys("A\\\", "x")', 'E764:') + call assert_equal([], g:OmniFunc1Args) + bw! + setglobal omnifunc=function('g:OmniFunc1',\ [23]) + call setline(1, 'sun') + call feedkeys("A\\\", 'x') + call assert_equal([[22, 1, ''], [22, 0, 'sun']], g:OmniFunc1Args) + new + call setline(1, 'sun') + LET g:OmniFunc1Args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[23, 1, ''], [23, 0, 'sun']], g:OmniFunc1Args) + setlocal omnifunc& + call setline(1, 'sun') + LET g:OmniFunc1Args = [] + call assert_fails('call feedkeys("A\\\", "x")', 'E764:') + call assert_equal([], g:OmniFunc1Args) + :%bw! END call v9.CheckLegacyAndVim9Success(lines) diff --git a/src/testdir/test_tagfunc.vim b/src/testdir/test_tagfunc.vim index 11a105b63fd01..286a54a3c5266 100644 --- a/src/testdir/test_tagfunc.vim +++ b/src/testdir/test_tagfunc.vim @@ -255,13 +255,37 @@ func Test_tagfunc_callback() call assert_fails("set tagfunc=funcref('abc')", "E700:") #" set 'tagfunc' to a non-existing function - LET &tagfunc = function('g:TagFunc2', [21]) + LET &tagfunc = function('g:TagFunc2') LET g:TagFunc2Args = [] call assert_fails("set tagfunc=function('NonExistingFunc')", 'E700:') call assert_fails("LET &tagfunc = function('NonExistingFunc')", 'E700:') - call assert_fails("tag axb123", 'E426:') - call assert_equal([], g:TagFunc2Args) + call assert_fails("tag axb123", 'E433:') + call assert_equal(['axb123', '', {}], g:TagFunc2Args) bw! + + #" :setlocal and :setglobal + set tagfunc& + setlocal tagfunc=function('g:TagFunc1',\ [22]) + LET g:TagFunc1Args = [] + call assert_fails("tag a22", 'E433:') + call assert_equal([22, 'a22', '', {}], g:TagFunc1Args) + new + LET g:TagFunc1Args = [] + call assert_fails("tag a22", 'E433:') + call assert_equal([], g:TagFunc1Args) + bw! + setglobal tagfunc=function('g:TagFunc1',\ [23]) + call assert_fails("tag a22", 'E433:') + call assert_equal([22, 'a22', '', {}], g:TagFunc1Args) + new + LET g:TagFunc1Args = [] + call assert_fails("tag a23", 'E433:') + call assert_equal([23, 'a23', '', {}], g:TagFunc1Args) + setlocal tagfunc& + LET g:TagFunc1Args = [] + call assert_fails("tag a23", 'E433:') + call assert_equal([], g:TagFunc1Args) + :%bw! END call v9.CheckLegacyAndVim9Success(lines)