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 -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220322121621.024901C22C9%40moolenaar.net.

Raspunde prin e-mail lui