Patch 8.2.4607
Problem: Sourcing buffer lines may lead to errors for conflicts.
Solution: Add the ++clear argument. (Yegappan Lakshmanan, closes #9991)
Files: runtime/doc/repeat.txt, src/scriptfile.c, src/vim9script.c,
src/proto/
vim9script.pro, src/testdir/test_source.vim
*** ../vim-8.2.4606/runtime/doc/repeat.txt 2022-03-21 19:45:13.200420997 +0000
--- runtime/doc/repeat.txt 2022-03-22 12:09:01.580053334 +0000
***************
*** 189,204 ****
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.
*:source!*
:so[urce]! {file} Read Vim commands from {file}. These are commands
--- 198,232 ----
start with a ":".
Triggers the |SourcePre| autocommand.
! :[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
*** ../vim-8.2.4606/src/scriptfile.c 2022-03-21 19:45:13.200420997 +0000
--- src/scriptfile.c 2022-03-22 12:09:01.584053325 +0000
***************
*** 23,29 ****
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);
/*
* Initialize the execution stack.
--- 23,29 ----
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, int clearvars);
/*
* Initialize the execution stack.
***************
*** 1084,1089 ****
--- 1084,1103 ----
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,1104 ****
emsg(_(e_argument_required));
else
// source ex commands from the current buffer
! do_source_ext(NULL, FALSE, FALSE, NULL, eap);
}
else if (eap != NULL && eap->forceit)
// ":source!": read Normal mode commands
--- 1112,1118 ----
emsg(_(e_argument_required));
else
// source ex commands from the current buffer
! do_source_ext(NULL, FALSE, FALSE, NULL, eap, clearvars);
}
else if (eap != NULL && eap->forceit)
// ":source!": read Normal mode commands
***************
*** 1292,1297 ****
--- 1306,1315 ----
* 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,1309 ****
int check_other, // check for .vimrc and _vimrc
int is_vimrc, // DOSO_ value
int *ret_sid UNUSED,
! exarg_T *eap)
{
source_cookie_T cookie;
char_u *p;
--- 1321,1328 ----
int check_other, // check for .vimrc and _vimrc
int is_vimrc, // DOSO_ value
int *ret_sid UNUSED,
! exarg_T *eap,
! int clearvars UNUSED)
{
source_cookie_T cookie;
char_u *p;
***************
*** 1527,1546 ****
{
si->sn_state = SN_STATE_RELOAD;
! // 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.
! ht = &SCRIPT_VARS(sid);
! todo = (int)ht->ht_used;
! for (hi = ht->ht_array; todo > 0; ++hi)
! if (!HASHITEM_EMPTY(hi))
! {
! --todo;
! di = HI2DI(hi);
! di->di_flags |= DI_FLAGS_RELOAD;
! }
! // imports can be redefined once
! mark_imports_for_reload(sid);
// reset version, "vim9script" may have been added or removed.
si->sn_version = 1;
--- 1546,1570 ----
{
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.
! ht = &SCRIPT_VARS(sid);
! todo = (int)ht->ht_used;
! for (hi = ht->ht_array; todo > 0; ++hi)
! if (!HASHITEM_EMPTY(hi))
! {
! --todo;
! di = HI2DI(hi);
! di->di_flags |= DI_FLAGS_RELOAD;
! }
! // 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,1737 ****
int is_vimrc, // DOSO_ value
int *ret_sid UNUSED)
{
! return do_source_ext(fname, check_other, is_vimrc, ret_sid, NULL);
}
--- 1755,1761 ----
int is_vimrc, // DOSO_ value
int *ret_sid UNUSED)
{
! return do_source_ext(fname, check_other, is_vimrc, ret_sid, NULL, FALSE);
}
*** ../vim-8.2.4606/src/vim9script.c 2022-03-19 12:56:42.533503825 +0000
--- src/vim9script.c 2022-03-22 12:09:01.584053325 +0000
***************
*** 59,64 ****
--- 59,82 ----
}
#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,120 ****
}
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);
! }
si->sn_state = SN_STATE_HAD_COMMAND;
// Store the prefix with the script, it is used to find exported functions.
--- 121,129 ----
}
if (si->sn_state == SN_STATE_RELOAD && !found_noclear)
// Reloading a script without the "noclear" argument: clear
// script-local variables and functions.
! 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.
*** ../vim-8.2.4606/src/proto/
vim9script.pro 2022-02-08 21:17:18.881463910 +0000
--- src/proto/
vim9script.pro 2022-03-22 12:09:01.584053325 +0000
***************
*** 2,7 ****
--- 2,8 ----
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);
*** ../vim-8.2.4606/src/testdir/test_source.vim 2022-03-21 19:45:13.200420997 +0000
--- src/testdir/test_source.vim 2022-03-22 12:09:01.584053325 +0000
***************
*** 608,613 ****
--- 608,641 ----
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
*** ../vim-8.2.4606/src/version.c 2022-03-21 20:40:32.408367357 +0000
--- src/version.c 2022-03-22 12:12:54.155508636 +0000
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 4607,
/**/
--
LAUNCELOT: At last! A call! A cry of distress ...
(he draws his sword, and turns to CONCORDE)
Concorde! Brave, Concorde ... you shall not have died in vain!
CONCORDE: I'm not quite dead, sir ...
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///