To: vim_dev@googlegroups.com Subject: Patch 8.1.0515 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.0515 Problem: Reloading a script gives errors for existing functions. Solution: Allow redefining a function once when reloading a script. Files: src/testdir/test_functions.vim, src/userfunc.c, src/structs.h, src/globals.h, src/buffer.c, src/ex_cmds2.c, src/main.c, src/option.c, runtime/doc/eval.txt *** ../vim-8.1.0514/src/testdir/test_functions.vim 2018-11-04 23:39:33.953644902 +0100 --- src/testdir/test_functions.vim 2018-11-10 16:54:47.043813092 +0100 *************** *** 1138,1140 **** --- 1138,1167 ---- call delete('Xfuncrange2') 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 *** ../vim-8.1.0514/src/userfunc.c 2018-11-04 23:39:33.953644902 +0100 --- src/userfunc.c 2018-11-10 16:48:35.046279419 +0100 *************** *** 2330,2343 **** fp = find_func(name); if (fp != NULL) { ! if (!eap->forceit) { emsg_funcname(e_funcexts, name); goto erret; } if (fp->uf_calls > 0) { ! emsg_funcname(N_("E127: Cannot redefine function %s: It is in use"), name); goto erret; } --- 2330,2348 ---- fp = find_func(name); if (fp != NULL) { ! // 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; } if (fp->uf_calls > 0) { ! emsg_funcname( ! N_("E127: Cannot redefine function %s: It is in use"), name); goto erret; } *** ../vim-8.1.0514/src/structs.h 2018-10-19 22:35:04.889189955 +0200 --- src/structs.h 2018-11-10 16:33:16.847566578 +0100 *************** *** 84,89 **** --- 84,90 ---- */ typedef struct { scid_T sc_sid; // script ID + int sc_seq; // sourcing sequence number linenr_T sc_lnum; // line number } sctx_T; *** ../vim-8.1.0514/src/globals.h 2018-09-13 15:33:39.609712174 +0200 --- src/globals.h 2018-11-10 16:33:30.455464981 +0100 *************** *** 326,332 **** EXTERN int garbage_collect_at_exit INIT(= FALSE); // Script CTX being sourced or was sourced to define the current function. ! EXTERN sctx_T current_sctx INIT(= {0 COMMA 0}); #endif EXTERN int did_source_packages INIT(= FALSE); --- 326,332 ---- EXTERN int garbage_collect_at_exit INIT(= FALSE); // Script CTX being sourced or was sourced to define the current function. ! EXTERN sctx_T current_sctx INIT(= {0 COMMA 0 COMMA 0}); #endif EXTERN int did_source_packages INIT(= FALSE); *** ../vim-8.1.0514/src/buffer.c 2018-10-11 19:27:43.916066156 +0200 --- src/buffer.c 2018-11-10 16:34:17.031116881 +0100 *************** *** 5519,5524 **** --- 5519,5525 ---- #ifdef FEAT_EVAL save_current_sctx = current_sctx; current_sctx.sc_sid = SID_MODELINE; + current_sctx.sc_seq = 0; current_sctx.sc_lnum = 0; #endif retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags); *** ../vim-8.1.0514/src/ex_cmds2.c 2018-11-05 20:25:48.804089622 +0100 --- src/ex_cmds2.c 2018-11-10 16:39:27.217457068 +0100 *************** *** 4344,4349 **** --- 4344,4350 ---- #ifdef FEAT_EVAL sctx_T save_current_sctx; static scid_T last_current_SID = 0; + static int last_current_SID_seq = 0; funccal_entry_T funccalp_entry; int save_debug_break_level = debug_break_level; scriptitem_T *si = NULL; *************** *** 4508,4518 **** * Also starts profiling timer for nested script. */ save_funccal(&funccalp_entry); ! /* ! * Check if this script was sourced before to finds its SID. ! * If it's new, generate a new SID. ! */ save_current_sctx = current_sctx; current_sctx.sc_lnum = 0; # ifdef UNIX stat_ok = (mch_stat((char *)fname_exp, &st) >= 0); --- 4509,4519 ---- * Also starts profiling timer for nested script. */ save_funccal(&funccalp_entry); ! // 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. save_current_sctx = current_sctx; + current_sctx.sc_seq = ++last_current_SID_seq; current_sctx.sc_lnum = 0; # ifdef UNIX stat_ok = (mch_stat((char *)fname_exp, &st) >= 0); *** ../vim-8.1.0514/src/main.c 2018-10-14 21:40:57.356848425 +0200 --- src/main.c 2018-11-10 16:42:21.260538735 +0100 *************** *** 2953,2958 **** --- 2953,2959 ---- sourcing_name = (char_u *)"command line"; #ifdef FEAT_EVAL current_sctx.sc_sid = SID_CARG; + current_sctx.sc_seq = 0; #endif for (i = 0; i < parmp->n_commands; ++i) { *************** *** 3183,3188 **** --- 3184,3190 ---- #ifdef FEAT_EVAL save_current_sctx = current_sctx; current_sctx.sc_sid = SID_ENV; + current_sctx.sc_seq = 0; current_sctx.sc_lnum = 0; #endif do_cmdline_cmd(initstr); *** ../vim-8.1.0514/src/option.c 2018-11-04 14:40:42.347139567 +0100 --- src/option.c 2018-11-10 16:48:26.810332143 +0100 *************** *** 415,421 **** char_u *def_val[2]; // default values for variable (vi and vim) #ifdef FEAT_EVAL sctx_T script_ctx; // script context where the option was last set ! # define SCTX_INIT , {0, 0} #else # define SCTX_INIT #endif --- 415,421 ---- char_u *def_val[2]; // default values for variable (vi and vim) #ifdef FEAT_EVAL sctx_T script_ctx; // script context where the option was last set ! # define SCTX_INIT , {0, 0, 0} #else # define SCTX_INIT #endif *************** *** 5959,5964 **** --- 5959,5965 ---- 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); *** ../vim-8.1.0514/runtime/doc/eval.txt 2018-10-25 12:30:52.270659874 +0200 --- runtime/doc/eval.txt 2018-11-10 16:52:02.836919520 +0100 *************** *** 9658,9666 **** 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. NOTE: Use ! wisely. If used without care it can cause an existing function to be replaced unexpectedly, which is hard to debug. --- 9673,9685 ---- 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. 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. *** ../vim-8.1.0514/src/version.c 2018-11-10 16:01:23.335381858 +0100 --- src/version.c 2018-11-10 16:26:16.190674882 +0100 *************** *** 794,795 **** --- 794,797 ---- { /* Add new patch number below this line */ + /**/ + 515, /**/ -- Witches prefer brooms: vacuum-cleaners need extension cords! /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///