diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/nvim/buffer.c | 1 | ||||
| -rw-r--r-- | src/nvim/eval.c | 6 | ||||
| -rw-r--r-- | src/nvim/eval/typval.h | 1 | ||||
| -rw-r--r-- | src/nvim/ex_cmds2.c | 3 | ||||
| -rw-r--r-- | src/nvim/globals.h | 2 | ||||
| -rw-r--r-- | src/nvim/main.c | 2 | ||||
| -rw-r--r-- | src/nvim/option.c | 6 | ||||
| -rw-r--r-- | src/nvim/testdir/test_functions.vim | 27 | 
8 files changed, 44 insertions, 4 deletions
| diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index f15205349b..f8e07a471f 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -5155,6 +5155,7 @@ chk_modeline(        const int secure_save = secure;        const sctx_T save_current_sctx = current_sctx;        current_sctx.sc_sid = SID_MODELINE; +      current_sctx.sc_seq = 0;        current_sctx.sc_lnum = 0;        // Make sure no risky things are executed as a side effect.        secure = 1; diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 8fa4e23df6..6f7d5ed6e4 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -21504,7 +21504,11 @@ void ex_function(exarg_T *eap)      fp = find_func(name);      if (fp != NULL) { -      if (!eap->forceit) { +      // Function can be replaced with "function!" and when sourcing the +      // same script again, but only once. +      if (!eap->forceit +          && (fp->uf_script_ctx.sc_sid != current_sctx.sc_sid +              || fp->uf_script_ctx.sc_seq == current_sctx.sc_seq)) {          emsg_funcname(e_funcexts, name);          goto erret;        } diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index c40585443e..823367560a 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -256,6 +256,7 @@ typedef int scid_T;  // the line number in the script "sc_sid".  typedef struct {    scid_T sc_sid;     // script ID +  int sc_seq;        // sourcing sequence number    linenr_T sc_lnum;  // line number  } sctx_T; diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 96f758805b..964b884460 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -3034,6 +3034,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc)    char_u                  *firstline = NULL;    int retval = FAIL;    static scid_T last_current_SID = 0; +  static int last_current_SID_seq = 0;    void                    *save_funccalp;    int save_debug_break_level = debug_break_level;    scriptitem_T            *si = NULL; @@ -3160,7 +3161,9 @@ int do_source(char_u *fname, int check_other, int is_vimrc)    // Check if this script was sourced before to finds its SID.    // If it's new, generate a new SID. +  // Always use a new sequence number.    const sctx_T save_current_sctx = current_sctx; +  current_sctx.sc_seq = ++last_current_SID_seq;    current_sctx.sc_lnum = 0;    FileID file_id;    bool file_id_ok = os_fileid((char *)fname_exp, &file_id); diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 3eae415719..5237c621f9 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -333,7 +333,7 @@ EXTERN int garbage_collect_at_exit INIT(= false);  #define SID_API_CLIENT  -8      // for API clients  // Script CTX being sourced or was sourced to define the current function. -EXTERN sctx_T current_sctx INIT(= { 0 COMMA 0 }); +EXTERN sctx_T current_sctx INIT(= { 0 COMMA 0 COMMA 0 });  // ID of the current channel making a client API call  EXTERN uint64_t current_channel_id INIT(= 0); diff --git a/src/nvim/main.c b/src/nvim/main.c index 9ea856a0c4..50e495c1e6 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1665,6 +1665,7 @@ static void exe_commands(mparm_T *parmp)      curwin->w_cursor.lnum = 0;    sourcing_name = (char_u *)"command line";    current_sctx.sc_sid = SID_CARG; +  current_sctx.sc_seq = 0;    for (i = 0; i < parmp->n_commands; i++) {      do_cmdline_cmd(parmp->commands[i]);      if (parmp->cmds_tofree[i]) @@ -1862,6 +1863,7 @@ static int execute_env(char *env)      sourcing_lnum = 0;      const sctx_T save_current_sctx = current_sctx;      current_sctx.sc_sid = SID_ENV; +    current_sctx.sc_seq = 0;      current_sctx.sc_lnum = 0;      do_cmdline_cmd((char *)initstr);      sourcing_name = save_sourcing_name; diff --git a/src/nvim/option.c b/src/nvim/option.c index c7d2dcb602..ae75644794 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -200,7 +200,7 @@ typedef struct vimoption {                                  // local option: indirect option index    char_u      *def_val[2];      // default values for variable (vi and vim)    LastSet last_set;             // script in which the option was last set -# define SCTX_INIT , { 0, 0 } +# define SCTX_INIT , { 0, 0, 0 }  } vimoption_T;  #define VI_DEFAULT  0       // def_val[VI_DEFAULT] is Vi default value @@ -2423,6 +2423,7 @@ set_string_option_direct(          script_ctx = current_sctx;        } else {          script_ctx.sc_sid = set_sid; +        script_ctx.sc_seq = 0;          script_ctx.sc_lnum = 0;        }        set_option_sctx_idx(idx, opt_flags, script_ctx); @@ -3798,7 +3799,8 @@ static void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx)    int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;    int indir = (int)options[opt_idx].indir;    const LastSet last_set = { .script_ctx = -    { script_ctx.sc_sid, script_ctx.sc_lnum + sourcing_lnum }, +    { script_ctx.sc_sid, script_ctx.sc_seq, +      script_ctx.sc_lnum + sourcing_lnum },      current_channel_id };    // Remember where the option was set.  For local options need to do that diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index 6c3d944ad5..a36c51f56f 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -1067,6 +1067,33 @@ func Test_func_range_with_edit()    bwipe!  endfunc +func Test_func_exists_on_reload() +  call writefile(['func ExistingFunction()', 'echo "yes"', 'endfunc'], 'Xfuncexists') +  call assert_equal(0, exists('*ExistingFunction')) +  source Xfuncexists +  call assert_equal(1, exists('*ExistingFunction')) +  " Redefining a function when reloading a script is OK. +  source Xfuncexists +  call assert_equal(1, exists('*ExistingFunction')) + +  " But redefining in another script is not OK. +  call writefile(['func ExistingFunction()', 'echo "yes"', 'endfunc'], 'Xfuncexists2') +  call assert_fails('source Xfuncexists2', 'E122:') + +  delfunc ExistingFunction +  call assert_equal(0, exists('*ExistingFunction')) +  call writefile([ +	\ 'func ExistingFunction()', 'echo "yes"', 'endfunc', +	\ 'func ExistingFunction()', 'echo "no"', 'endfunc', +	\ ], 'Xfuncexists') +  call assert_fails('source Xfuncexists', 'E122:') +  call assert_equal(1, exists('*ExistingFunction')) + +  call delete('Xfuncexists2') +  call delete('Xfuncexists') +  delfunc ExistingFunction +endfunc +  sandbox function Fsandbox()    normal ix  endfunc | 
