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.
|
deleted if there are no more references to it.
|
||||||
*E127* *E122*
|
*E127* *E122*
|
||||||
When a function by this name already exists and [!] is
|
When a function by this name already exists and [!] is
|
||||||
not used an error message is given. When [!] is used,
|
not used an error message is given. There is one
|
||||||
an existing function is silently replaced. Unless it
|
exception: When sourcing a script again, a function
|
||||||
is currently being executed, that is an error.
|
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
|
NOTE: Use ! wisely. If used without care it can cause
|
||||||
an existing function to be replaced unexpectedly,
|
an existing function to be replaced unexpectedly,
|
||||||
which is hard to debug.
|
which is hard to debug.
|
||||||
|
@@ -5155,6 +5155,7 @@ chk_modeline(
|
|||||||
const int secure_save = secure;
|
const int secure_save = secure;
|
||||||
const sctx_T save_current_sctx = current_sctx;
|
const sctx_T save_current_sctx = current_sctx;
|
||||||
current_sctx.sc_sid = SID_MODELINE;
|
current_sctx.sc_sid = SID_MODELINE;
|
||||||
|
current_sctx.sc_seq = 0;
|
||||||
current_sctx.sc_lnum = 0;
|
current_sctx.sc_lnum = 0;
|
||||||
// Make sure no risky things are executed as a side effect.
|
// Make sure no risky things are executed as a side effect.
|
||||||
secure = 1;
|
secure = 1;
|
||||||
|
@@ -21504,7 +21504,11 @@ void ex_function(exarg_T *eap)
|
|||||||
|
|
||||||
fp = find_func(name);
|
fp = find_func(name);
|
||||||
if (fp != NULL) {
|
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);
|
emsg_funcname(e_funcexts, name);
|
||||||
goto erret;
|
goto erret;
|
||||||
}
|
}
|
||||||
|
@@ -256,6 +256,7 @@ typedef int scid_T;
|
|||||||
// the line number in the script "sc_sid".
|
// the line number in the script "sc_sid".
|
||||||
typedef struct {
|
typedef struct {
|
||||||
scid_T sc_sid; // script ID
|
scid_T sc_sid; // script ID
|
||||||
|
int sc_seq; // sourcing sequence number
|
||||||
linenr_T sc_lnum; // line number
|
linenr_T sc_lnum; // line number
|
||||||
} sctx_T;
|
} sctx_T;
|
||||||
|
|
||||||
|
@@ -3034,6 +3034,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
|
|||||||
char_u *firstline = NULL;
|
char_u *firstline = NULL;
|
||||||
int retval = FAIL;
|
int retval = FAIL;
|
||||||
static scid_T last_current_SID = 0;
|
static scid_T last_current_SID = 0;
|
||||||
|
static int last_current_SID_seq = 0;
|
||||||
void *save_funccalp;
|
void *save_funccalp;
|
||||||
int save_debug_break_level = debug_break_level;
|
int save_debug_break_level = debug_break_level;
|
||||||
scriptitem_T *si = NULL;
|
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.
|
// Check if this script was sourced before to finds its SID.
|
||||||
// If it's new, generate a new SID.
|
// If it's new, generate a new SID.
|
||||||
|
// Always use a new sequence number.
|
||||||
const sctx_T save_current_sctx = current_sctx;
|
const sctx_T save_current_sctx = current_sctx;
|
||||||
|
current_sctx.sc_seq = ++last_current_SID_seq;
|
||||||
current_sctx.sc_lnum = 0;
|
current_sctx.sc_lnum = 0;
|
||||||
FileID file_id;
|
FileID file_id;
|
||||||
bool file_id_ok = os_fileid((char *)fname_exp, &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
|
#define SID_API_CLIENT -8 // for API clients
|
||||||
|
|
||||||
// Script CTX being sourced or was sourced to define the current function.
|
// 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
|
// ID of the current channel making a client API call
|
||||||
EXTERN uint64_t current_channel_id INIT(= 0);
|
EXTERN uint64_t current_channel_id INIT(= 0);
|
||||||
|
|
||||||
|
@@ -1665,6 +1665,7 @@ static void exe_commands(mparm_T *parmp)
|
|||||||
curwin->w_cursor.lnum = 0;
|
curwin->w_cursor.lnum = 0;
|
||||||
sourcing_name = (char_u *)"command line";
|
sourcing_name = (char_u *)"command line";
|
||||||
current_sctx.sc_sid = SID_CARG;
|
current_sctx.sc_sid = SID_CARG;
|
||||||
|
current_sctx.sc_seq = 0;
|
||||||
for (i = 0; i < parmp->n_commands; i++) {
|
for (i = 0; i < parmp->n_commands; i++) {
|
||||||
do_cmdline_cmd(parmp->commands[i]);
|
do_cmdline_cmd(parmp->commands[i]);
|
||||||
if (parmp->cmds_tofree[i])
|
if (parmp->cmds_tofree[i])
|
||||||
@@ -1862,6 +1863,7 @@ static int execute_env(char *env)
|
|||||||
sourcing_lnum = 0;
|
sourcing_lnum = 0;
|
||||||
const sctx_T save_current_sctx = current_sctx;
|
const sctx_T save_current_sctx = current_sctx;
|
||||||
current_sctx.sc_sid = SID_ENV;
|
current_sctx.sc_sid = SID_ENV;
|
||||||
|
current_sctx.sc_seq = 0;
|
||||||
current_sctx.sc_lnum = 0;
|
current_sctx.sc_lnum = 0;
|
||||||
do_cmdline_cmd((char *)initstr);
|
do_cmdline_cmd((char *)initstr);
|
||||||
sourcing_name = save_sourcing_name;
|
sourcing_name = save_sourcing_name;
|
||||||
|
@@ -200,7 +200,7 @@ typedef struct vimoption {
|
|||||||
// local option: indirect option index
|
// local option: indirect option index
|
||||||
char_u *def_val[2]; // default values for variable (vi and vim)
|
char_u *def_val[2]; // default values for variable (vi and vim)
|
||||||
LastSet last_set; // script in which the option was last set
|
LastSet last_set; // script in which the option was last set
|
||||||
# define SCTX_INIT , { 0, 0 }
|
# define SCTX_INIT , { 0, 0, 0 }
|
||||||
} vimoption_T;
|
} vimoption_T;
|
||||||
|
|
||||||
#define VI_DEFAULT 0 // def_val[VI_DEFAULT] is Vi default value
|
#define VI_DEFAULT 0 // def_val[VI_DEFAULT] is Vi default value
|
||||||
@@ -2423,6 +2423,7 @@ set_string_option_direct(
|
|||||||
script_ctx = current_sctx;
|
script_ctx = current_sctx;
|
||||||
} else {
|
} else {
|
||||||
script_ctx.sc_sid = set_sid;
|
script_ctx.sc_sid = set_sid;
|
||||||
|
script_ctx.sc_seq = 0;
|
||||||
script_ctx.sc_lnum = 0;
|
script_ctx.sc_lnum = 0;
|
||||||
}
|
}
|
||||||
set_option_sctx_idx(idx, opt_flags, script_ctx);
|
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 both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
|
||||||
int indir = (int)options[opt_idx].indir;
|
int indir = (int)options[opt_idx].indir;
|
||||||
const LastSet last_set = { .script_ctx =
|
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 };
|
current_channel_id };
|
||||||
|
|
||||||
// Remember where the option was set. For local options need to do that
|
// Remember where the option was set. For local options need to do that
|
||||||
|
@@ -1067,6 +1067,33 @@ func Test_func_range_with_edit()
|
|||||||
bwipe!
|
bwipe!
|
||||||
endfunc
|
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()
|
sandbox function Fsandbox()
|
||||||
normal ix
|
normal ix
|
||||||
endfunc
|
endfunc
|
||||||
|
Reference in New Issue
Block a user