diff options
author | erw7 <erw7.github@gmail.com> | 2019-08-29 13:07:03 +0900 |
---|---|---|
committer | erw7 <erw7.github@gmail.com> | 2019-09-04 13:40:05 +0900 |
commit | 9db60b06a1d9b50b3ba6beb858eb0fd2c58571c4 (patch) | |
tree | bd7d55a5af91afae726345b7fc40324625241879 | |
parent | e4a47862415ee6e0c4904f9c5cc8c3453be6bf17 (diff) | |
download | rneovim-9db60b06a1d9b50b3ba6beb858eb0fd2c58571c4.tar.gz rneovim-9db60b06a1d9b50b3ba6beb858eb0fd2c58571c4.tar.bz2 rneovim-9db60b06a1d9b50b3ba6beb858eb0fd2c58571c4.zip |
vim-patch:8.1.0515: reloading a script gives errors for existing functions
Problem: Reloading a script gives errors for existing functions.
Solution: Allow redefining a function once when reloading a script.
https://github.com/vim/vim/commit/ded5f1bed7ff2d138b3ee0f9610d17290b62692d
-rw-r--r-- | runtime/doc/eval.txt | 10 | ||||
-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 |
9 files changed, 51 insertions, 7 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 97ca804c9a..d8c1132906 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -9238,9 +9238,13 @@ See |:verbose-cmd| for more information. deleted if there are no more references to it. *E127* *E122* When a function by this name already exists and [!] is - not used an error message is given. When [!] is used, - an existing function is silently replaced. Unless it - is currently being executed, that is an error. + not used an error message is given. There is one + exception: When sourcing a script again, a function + that was previously defined in that script will be + silently replaced. + When [!] is used, an existing function is silently + replaced. Unless it is currently being executed, that + is an error. NOTE: Use ! wisely. If used without care it can cause an existing function to be replaced unexpectedly, which is hard to debug. 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 |