]> granicus.if.org Git - vim/commitdiff
patch 8.2.4607: sourcing buffer lines may lead to errors for conflicts v8.2.4607
authorYegappan Lakshmanan <yegappan@yahoo.com>
Tue, 22 Mar 2022 12:13:54 +0000 (12:13 +0000)
committerBram Moolenaar <Bram@vim.org>
Tue, 22 Mar 2022 12:13:54 +0000 (12:13 +0000)
Problem:    Sourcing buffer lines may lead to errors for conflicts.
Solution:   Add the ++clear argument. (Yegappan Lakshmanan, closes #9991)

runtime/doc/repeat.txt
src/proto/vim9script.pro
src/scriptfile.c
src/testdir/test_source.vim
src/version.c
src/vim9script.c

index f7756c1c06842b89d8aa5a705931b963d391646a..1ee547ce042dac1f30ec03b3d9e59685f1944d33 100644 (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
index 6295dc2cca9979e151efc81d9465ffcffafa3209..bc1e23275ceed3385b960e8824a9016e429f5aee 100644 (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);
index 3faed4a700636e482491186779125a5243dca41c..ae46e7a86d7cbc69cca33ebfb244683cf2c36500 100644 (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,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);
 }
 
 
index 251625aab1549a67244cfdbbc12d606332555248..010401084cdf3752c4ff6c236b9d280d9ef6c37d 100644 (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
 
index 6d5e1a685cb9d23c3e9f0b88db2fd4d0986caf6f..2c2ac28bf3408ea8193f5d90ce5dc46d057fdda8 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4607,
 /**/
     4606,
 /**/
index 870056fcc427a8d8cf6fecfed0f430bb6444ca14..3e8fe2f65354b2ce7de56f9d622705ab8e180a85 100644 (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.