0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

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 ":".
Triggers the |SourcePre| autocommand.
:[range]so[urce] Read Ex commands from the [range] of lines in the
current buffer. When sourcing commands from the
current buffer, the same script-ID |<SID>| is used
even if the buffer is sourced multiple times. If a
buffer is sourced more than once, then the functions
in the buffer are redefined again.
Sourcing a buffer with a Vim9 script more than once
works like |vim9-reload|.
To source a script in the Vim9 context, the |:vim9cmd|
modifier can be used.
:[range]so[urce] [++clear]
Read Ex commands from the [range] of lines in the
current buffer.
When sourcing commands from the current buffer, the
same script-ID |<SID>| is used even if the buffer is
sourced multiple times. If a buffer is sourced more
than once, then the functions in the buffer are
defined again.
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!*
:so[urce]! {file} Read Vim commands from {file}. These are commands

View File

@@ -2,6 +2,7 @@
int in_vim9script(void);
int in_old_script(int max_version);
int current_script_is_vim9(void);
void clear_vim9_scriptlocal_vars(int sid);
void ex_vim9script(exarg_T *eap);
int not_in_vim9(exarg_T *eap);
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;
#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.
@@ -1084,6 +1084,20 @@ ExpandPackAddDir(
static void
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 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));
else
// 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)
// ":source!": read Normal mode commands
@@ -1292,6 +1306,10 @@ errret:
* The 'eap' argument is used when sourcing lines from a buffer instead of a
* 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!
*
* 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 is_vimrc, // DOSO_ value
int *ret_sid UNUSED,
exarg_T *eap)
exarg_T *eap,
int clearvars UNUSED)
{
source_cookie_T cookie;
char_u *p;
@@ -1527,9 +1546,11 @@ do_source_ext(
{
si->sn_state = SN_STATE_RELOAD;
if (!clearvars)
{
// Script-local variables remain but "const" can be set again.
// In Vim9 script variables will be cleared when "vim9script" is
// encountered without the "noclear" argument.
// In Vim9 script variables will be cleared when "vim9script"
// is encountered without the "noclear" argument.
ht = &SCRIPT_VARS(sid);
todo = (int)ht->ht_used;
for (hi = ht->ht_array; todo > 0; ++hi)
@@ -1541,6 +1562,9 @@ do_source_ext(
}
// imports can be redefined once
mark_imports_for_reload(sid);
}
else
clear_vim9_scriptlocal_vars(sid);
// reset version, "vim9script" may have been added or removed.
si->sn_version = 1;
@@ -1731,7 +1755,7 @@ do_source(
int is_vimrc, // DOSO_ value
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
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!
endfunc

View File

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

View File

@@ -59,6 +59,24 @@ current_script_is_vim9(void)
}
#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".
*/
@@ -103,18 +121,9 @@ ex_vim9script(exarg_T *eap UNUSED)
}
if (si->sn_state == SN_STATE_RELOAD && !found_noclear)
{
hashtab_T *ht = &SCRIPT_VARS(sid);
// Reloading a script without the "noclear" argument: clear
// script-local variables and functions.
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);
}
clear_vim9_scriptlocal_vars(sid);
si->sn_state = SN_STATE_HAD_COMMAND;
// Store the prefix with the script, it is used to find exported functions.