1
0
forked from aniani/vim

patch 8.2.4607: sourcing buffer lines may lead to errors for conflicts

Problem:    Sourcing buffer lines may lead to errors for conflicts.
Solution:   Add the ++clear argument. (Yegappan Lakshmanan, closes #9991)
This commit is contained in:
Yegappan Lakshmanan
2022-03-22 12:13:54 +00:00
committed by Bram Moolenaar
parent e18acb02bb
commit 35dc17634d
6 changed files with 121 additions and 38 deletions

View File

@@ -198,16 +198,35 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
start with a ":". start with a ":".
Triggers the |SourcePre| autocommand. Triggers the |SourcePre| autocommand.
:[range]so[urce] Read Ex commands from the [range] of lines in the :[range]so[urce] [++clear]
current buffer. When sourcing commands from the Read Ex commands from the [range] of lines in the
current buffer, the same script-ID |<SID>| is used current buffer.
even if the buffer is sourced multiple times. If a
buffer is sourced more than once, then the functions When sourcing commands from the current buffer, the
in the buffer are redefined again. same script-ID |<SID>| is used even if the buffer is
Sourcing a buffer with a Vim9 script more than once sourced multiple times. If a buffer is sourced more
works like |vim9-reload|. than once, then the functions in the buffer are
To source a script in the Vim9 context, the |:vim9cmd| defined again.
modifier can be used.
To source a range of lines that doesn't start with the
|:vim9script| command in Vim9 script context, the
|:vim9cmd| modifier can be used.
When a range of lines in a buffer is sourced in the
Vim9 script context, the previously defined
script-local variables and functions are not cleared.
This works like the range started with the
":vim9script noclear" command. The "++clear" argument
can be used to clear the script-local variables and
functions before sourcing the script. This works like
the range started with the |:vimscript| command
without the "noclear" argument. See |vim9-reload| for
more information.
Examples: >
:4,5source
:vim9cmd :'<,'>source
:10,18source ++clear
*:source!* *:source!*
:so[urce]! {file} Read Vim commands from {file}. These are commands :so[urce]! {file} Read Vim commands from {file}. These are commands

View File

@@ -2,6 +2,7 @@
int in_vim9script(void); int in_vim9script(void);
int in_old_script(int max_version); int in_old_script(int max_version);
int current_script_is_vim9(void); int current_script_is_vim9(void);
void clear_vim9_scriptlocal_vars(int sid);
void ex_vim9script(exarg_T *eap); void ex_vim9script(exarg_T *eap);
int not_in_vim9(exarg_T *eap); int not_in_vim9(exarg_T *eap);
int vim9_bad_comment(char_u *p); int vim9_bad_comment(char_u *p);

View File

@@ -23,7 +23,7 @@ static garray_T ga_loaded = {0, 0, sizeof(char_u *), 4, NULL};
static int last_current_SID_seq = 0; static int last_current_SID_seq = 0;
#endif #endif
static int do_source_ext(char_u *fname, int check_other, int is_vimrc, int *ret_sid, exarg_T *eap); static int do_source_ext(char_u *fname, int check_other, int is_vimrc, int *ret_sid, exarg_T *eap, int clearvars);
/* /*
* Initialize the execution stack. * Initialize the execution stack.
@@ -1084,6 +1084,20 @@ ExpandPackAddDir(
static void static void
cmd_source(char_u *fname, exarg_T *eap) cmd_source(char_u *fname, exarg_T *eap)
{ {
int clearvars = FALSE;
if (*fname != NUL && STRNCMP(fname, "++clear", 7) == 0)
{
// ++clear argument is supplied
clearvars = TRUE;
fname = fname + 7;
if (*fname != NUL)
{
semsg(_(e_invalid_argument_str), eap->arg);
return;
}
}
if (*fname != NUL && eap != NULL && eap->addr_count > 0) if (*fname != NUL && eap != NULL && eap->addr_count > 0)
{ {
// if a filename is specified to :source, then a range is not allowed // if a filename is specified to :source, then a range is not allowed
@@ -1098,7 +1112,7 @@ cmd_source(char_u *fname, exarg_T *eap)
emsg(_(e_argument_required)); emsg(_(e_argument_required));
else else
// source ex commands from the current buffer // source ex commands from the current buffer
do_source_ext(NULL, FALSE, FALSE, NULL, eap); do_source_ext(NULL, FALSE, FALSE, NULL, eap, clearvars);
} }
else if (eap != NULL && eap->forceit) else if (eap != NULL && eap->forceit)
// ":source!": read Normal mode commands // ":source!": read Normal mode commands
@@ -1292,6 +1306,10 @@ errret:
* The 'eap' argument is used when sourcing lines from a buffer instead of a * The 'eap' argument is used when sourcing lines from a buffer instead of a
* file. * file.
* *
* If 'clearvars' is TRUE, then for scripts which are loaded more than
* once, clear all the functions and variables previously defined in that
* script.
*
* This function may be called recursively! * This function may be called recursively!
* *
* Return FAIL if file could not be opened, OK otherwise. * Return FAIL if file could not be opened, OK otherwise.
@@ -1303,7 +1321,8 @@ do_source_ext(
int check_other, // check for .vimrc and _vimrc int check_other, // check for .vimrc and _vimrc
int is_vimrc, // DOSO_ value int is_vimrc, // DOSO_ value
int *ret_sid UNUSED, int *ret_sid UNUSED,
exarg_T *eap) exarg_T *eap,
int clearvars UNUSED)
{ {
source_cookie_T cookie; source_cookie_T cookie;
char_u *p; char_u *p;
@@ -1527,9 +1546,11 @@ do_source_ext(
{ {
si->sn_state = SN_STATE_RELOAD; si->sn_state = SN_STATE_RELOAD;
if (!clearvars)
{
// Script-local variables remain but "const" can be set again. // Script-local variables remain but "const" can be set again.
// In Vim9 script variables will be cleared when "vim9script" is // In Vim9 script variables will be cleared when "vim9script"
// encountered without the "noclear" argument. // is encountered without the "noclear" argument.
ht = &SCRIPT_VARS(sid); ht = &SCRIPT_VARS(sid);
todo = (int)ht->ht_used; todo = (int)ht->ht_used;
for (hi = ht->ht_array; todo > 0; ++hi) for (hi = ht->ht_array; todo > 0; ++hi)
@@ -1541,6 +1562,9 @@ do_source_ext(
} }
// imports can be redefined once // imports can be redefined once
mark_imports_for_reload(sid); mark_imports_for_reload(sid);
}
else
clear_vim9_scriptlocal_vars(sid);
// reset version, "vim9script" may have been added or removed. // reset version, "vim9script" may have been added or removed.
si->sn_version = 1; si->sn_version = 1;
@@ -1731,7 +1755,7 @@ do_source(
int is_vimrc, // DOSO_ value int is_vimrc, // DOSO_ value
int *ret_sid UNUSED) int *ret_sid UNUSED)
{ {
return do_source_ext(fname, check_other, is_vimrc, ret_sid, NULL); return do_source_ext(fname, check_other, is_vimrc, ret_sid, NULL, FALSE);
} }

View File

@@ -608,6 +608,34 @@ func Test_source_buffer_vim9()
source source
call assert_equal('red', g:Color) call assert_equal('red', g:Color)
" test for ++clear argument to clear all the functions/variables
%d _
let lines =<< trim END
g:ScriptVarFound = exists("color")
g:MyFuncFound = exists('*Myfunc')
if g:MyFuncFound
finish
endif
var color = 'blue'
def Myfunc()
enddef
END
call setline(1, lines)
vim9cmd source
call assert_false(g:MyFuncFound)
call assert_false(g:ScriptVarFound)
vim9cmd source
call assert_true(g:MyFuncFound)
call assert_true(g:ScriptVarFound)
vim9cmd source ++clear
call assert_false(g:MyFuncFound)
call assert_false(g:ScriptVarFound)
vim9cmd source ++clear
call assert_false(g:MyFuncFound)
call assert_false(g:ScriptVarFound)
call assert_fails('vim9cmd source ++clearx', 'E475:')
call assert_fails('vim9cmd source ++abcde', 'E484:')
%bw! %bw!
endfunc endfunc

View File

@@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
4607,
/**/ /**/
4606, 4606,
/**/ /**/

View File

@@ -59,6 +59,24 @@ current_script_is_vim9(void)
} }
#endif #endif
#ifdef FEAT_EVAL
/*
* Clear Vim9 script-local variables and functions.
*/
void
clear_vim9_scriptlocal_vars(int sid)
{
hashtab_T *ht = &SCRIPT_VARS(sid);
hashtab_free_contents(ht);
hash_init(ht);
delete_script_functions(sid);
// old imports and script variables are no longer valid
free_imports_and_script_vars(sid);
}
#endif
/* /*
* ":vim9script". * ":vim9script".
*/ */
@@ -103,18 +121,9 @@ ex_vim9script(exarg_T *eap UNUSED)
} }
if (si->sn_state == SN_STATE_RELOAD && !found_noclear) if (si->sn_state == SN_STATE_RELOAD && !found_noclear)
{
hashtab_T *ht = &SCRIPT_VARS(sid);
// Reloading a script without the "noclear" argument: clear // Reloading a script without the "noclear" argument: clear
// script-local variables and functions. // script-local variables and functions.
hashtab_free_contents(ht); clear_vim9_scriptlocal_vars(sid);
hash_init(ht);
delete_script_functions(sid);
// old imports and script variables are no longer valid
free_imports_and_script_vars(sid);
}
si->sn_state = SN_STATE_HAD_COMMAND; si->sn_state = SN_STATE_HAD_COMMAND;
// Store the prefix with the script, it is used to find exported functions. // Store the prefix with the script, it is used to find exported functions.