summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYegappan Lakshmanan <yegappan@yahoo.com>2022-03-22 12:13:54 +0000
committerBram Moolenaar <Bram@vim.org>2022-03-22 12:13:54 +0000
commit35dc17634dd6da5b90bd1b0160c4ed9e394f4b87 (patch)
tree3d63468febb80de476c931d79bf814d105d6d654
parente18acb02bb58b2e07f3a52ce619752ba39c05ea2 (diff)
downloadvim-git-35dc17634dd6da5b90bd1b0160c4ed9e394f4b87.tar.gz
patch 8.2.4607: sourcing buffer lines may lead to errors for conflictsv8.2.4607
Problem: Sourcing buffer lines may lead to errors for conflicts. Solution: Add the ++clear argument. (Yegappan Lakshmanan, closes #9991)
-rw-r--r--runtime/doc/repeat.txt39
-rw-r--r--src/proto/vim9script.pro1
-rw-r--r--src/scriptfile.c60
-rw-r--r--src/testdir/test_source.vim28
-rw-r--r--src/version.c2
-rw-r--r--src/vim9script.c29
6 files changed, 121 insertions, 38 deletions
diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt
index f7756c1c0..1ee547ce0 100644
--- a/runtime/doc/repeat.txt
+++ b/runtime/doc/repeat.txt
@@ -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
diff --git a/src/proto/vim9script.pro b/src/proto/vim9script.pro
index 6295dc2cc..bc1e23275 100644
--- a/src/proto/vim9script.pro
+++ b/src/proto/vim9script.pro
@@ -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);
diff --git a/src/scriptfile.c b/src/scriptfile.c
index 3faed4a70..ae46e7a86 100644
--- a/src/scriptfile.c
+++ b/src/scriptfile.c
@@ -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,20 +1546,25 @@ do_source_ext(
{
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);
+ 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,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);
}
diff --git a/src/testdir/test_source.vim b/src/testdir/test_source.vim
index 251625aab..010401084 100644
--- a/src/testdir/test_source.vim
+++ b/src/testdir/test_source.vim
@@ -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
diff --git a/src/version.c b/src/version.c
index 6d5e1a685..2c2ac28bf 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 4607,
+/**/
4606,
/**/
4605,
diff --git a/src/vim9script.c b/src/vim9script.c
index 870056fcc..3e8fe2f65 100644
--- a/src/vim9script.c
+++ b/src/vim9script.c
@@ -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.