mirror of
https://github.com/neovim/neovim.git
synced 2025-09-13 06:48:17 +00:00
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.
ded5f1bed7
This commit is contained in:
@@ -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.
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user