diff src/scriptfile.c @ 19181:94eda51ba9ba v8.2.0149

patch 8.2.0149: maintaining a Vim9 branch separately is more work Commit: https://github.com/vim/vim/commit/8a7d6542b33e5d2b352262305c3bfdb2d14e1cf8 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jan 26 15:56:19 2020 +0100 patch 8.2.0149: maintaining a Vim9 branch separately is more work Problem: Maintaining a Vim9 branch separately is more work. Solution: Merge the Vim9 script changes.
author Bram Moolenaar <Bram@vim.org>
date Sun, 26 Jan 2020 16:00:05 +0100
parents ea3ac1de7704
children 17d878a2ddaa
line wrap: on
line diff
--- a/src/scriptfile.c
+++ b/src/scriptfile.c
@@ -182,9 +182,9 @@ ex_runtime(exarg_T *eap)
 }
 
     static void
-source_callback(char_u *fname, void *cookie UNUSED)
+source_callback(char_u *fname, void *cookie)
 {
-    (void)do_source(fname, FALSE, DOSO_NONE);
+    (void)do_source(fname, FALSE, DOSO_NONE, cookie);
 }
 
 /*
@@ -399,16 +399,16 @@ do_in_runtimepath(
     int
 source_runtime(char_u *name, int flags)
 {
-    return source_in_path(p_rtp, name, flags);
+    return source_in_path(p_rtp, name, flags, NULL);
 }
 
 /*
  * Just like source_runtime(), but use "path" instead of 'runtimepath'.
  */
     int
-source_in_path(char_u *path, char_u *name, int flags)
+source_in_path(char_u *path, char_u *name, int flags, int *ret_sid)
 {
-    return do_in_path_and_pp(path, name, flags, source_callback, NULL);
+    return do_in_path_and_pp(path, name, flags, source_callback, ret_sid);
 }
 
 
@@ -427,7 +427,7 @@ source_all_matches(char_u *pat)
     if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
     {
 	for (i = 0; i < num_files; ++i)
-	    (void)do_source(files[i], FALSE, DOSO_NONE);
+	    (void)do_source(files[i], FALSE, DOSO_NONE, NULL);
 	FreeWild(num_files, files);
     }
 }
@@ -930,7 +930,7 @@ cmd_source(char_u *fname, exarg_T *eap)
 						 );
 
     // ":source" read ex commands
-    else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
+    else if (do_source(fname, FALSE, DOSO_NONE, NULL) == FAIL)
 	semsg(_(e_notopen), fname);
 }
 
@@ -1063,16 +1063,20 @@ fopen_noinh_readbin(char *filename)
 
 /*
  * do_source: Read the file "fname" and execute its lines as EX commands.
+ * When "ret_sid" is not NULL and we loaded the script before, don't load it
+ * again.
  *
  * This function may be called recursively!
  *
- * return FAIL if file could not be opened, OK otherwise
+ * Return FAIL if file could not be opened, OK otherwise.
+ * If a scriptitem_T was found or created "*ret_sid" is set to the SID.
  */
     int
 do_source(
     char_u	*fname,
     int		check_other,	    // check for .vimrc and _vimrc
-    int		is_vimrc)	    // DOSO_ value
+    int		is_vimrc,	    // DOSO_ value
+    int		*ret_sid UNUSED)
 {
     struct source_cookie    cookie;
     char_u		    *p;
@@ -1085,6 +1089,7 @@ do_source(
     static int		    last_current_SID_seq = 0;
     funccal_entry_T	    funccalp_entry;
     int			    save_debug_break_level = debug_break_level;
+    int			    sid;
     scriptitem_T	    *si = NULL;
 # ifdef UNIX
     stat_T		    st;
@@ -1114,6 +1119,37 @@ do_source(
 	goto theend;
     }
 
+#ifdef FEAT_EVAL
+    // See if we loaded this script before.
+# ifdef UNIX
+    stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
+# endif
+    for (sid = script_items.ga_len; sid > 0; --sid)
+    {
+	si = &SCRIPT_ITEM(sid);
+	if (si->sn_name != NULL)
+	{
+# ifdef UNIX
+	    // Compare dev/ino when possible, it catches symbolic links.  Also
+	    // compare file names, the inode may change when the file was
+	    // edited or it may be re-used for another script (esp. in tests).
+	    if ((stat_ok && si->sn_dev_valid)
+		       && (si->sn_dev != st.st_dev || si->sn_ino != st.st_ino))
+		continue;
+# endif
+	    if (fnamecmp(si->sn_name, fname_exp) == 0)
+		// Found it!
+		break;
+	}
+    }
+    if (sid > 0 && ret_sid != NULL)
+    {
+	// Already loaded and no need to load again, return here.
+	*ret_sid = sid;
+	return OK;
+    }
+#endif
+
     // Apply SourceCmd autocommands, they should get the file and source it.
     if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
 	    && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
@@ -1239,33 +1275,32 @@ do_source(
     current_sctx.sc_version = 1;  // default script version
 
     // Check if this script was sourced before to finds its SID.
-    // If it's new, generate a new SID.
     // Always use a new sequence number.
     current_sctx.sc_seq = ++last_current_SID_seq;
-# ifdef UNIX
-    stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
-# endif
-    for (current_sctx.sc_sid = script_items.ga_len; current_sctx.sc_sid > 0;
-							 --current_sctx.sc_sid)
+    if (sid > 0)
     {
-	si = &SCRIPT_ITEM(current_sctx.sc_sid);
-	if (si->sn_name != NULL)
-	{
-# ifdef UNIX
-	    // Compare dev/ino when possible, it catches symbolic links.  Also
-	    // compare file names, the inode may change when the file was
-	    // edited or it may be re-used for another script (esp. in tests).
-	    if ((stat_ok && si->sn_dev_valid)
-		       && (si->sn_dev != st.st_dev || si->sn_ino != st.st_ino))
-		continue;
-# endif
-	    if (fnamecmp(si->sn_name, fname_exp) == 0)
-		// Found it!
-		break;
-	}
+	hashtab_T	*ht;
+	hashitem_T	*hi;
+	dictitem_T	*di;
+	int		todo;
+
+	// loading the same script again
+	si->sn_had_command = FALSE;
+	current_sctx.sc_sid = sid;
+
+	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;
+	    }
     }
-    if (current_sctx.sc_sid == 0)
+    else
     {
+	// It's new, generate a new SID.
 	current_sctx.sc_sid = ++last_current_SID;
 	if (ga_grow(&script_items,
 		     (int)(current_sctx.sc_sid - script_items.ga_len)) == FAIL)
@@ -1273,13 +1308,17 @@ do_source(
 	while (script_items.ga_len < current_sctx.sc_sid)
 	{
 	    ++script_items.ga_len;
-	    SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
-	    SCRIPT_ITEM(script_items.ga_len).sn_version = 1;
+	    si = &SCRIPT_ITEM(script_items.ga_len);
+	    si->sn_name = NULL;
+	    si->sn_version = 1;
 
 	    // Allocate the local script variables to use for this script.
 	    new_script_vars(script_items.ga_len);
+	    ga_init2(&si->sn_var_vals, sizeof(typval_T), 10);
+	    ga_init2(&si->sn_imports, sizeof(imported_T), 10);
+	    ga_init2(&si->sn_type_list, sizeof(type_T), 10);
 # ifdef FEAT_PROFILE
-	    SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
+	    si->sn_prof_on = FALSE;
 # endif
 	}
 	si = &SCRIPT_ITEM(current_sctx.sc_sid);
@@ -1295,6 +1334,8 @@ do_source(
 	else
 	    si->sn_dev_valid = FALSE;
 # endif
+	if (ret_sid != NULL)
+	    *ret_sid = current_sctx.sc_sid;
     }
 
 # ifdef FEAT_PROFILE
@@ -1392,6 +1433,15 @@ do_source(
 
 #ifdef FEAT_EVAL
 almosttheend:
+    // Get "si" again, "script_items" may have been reallocated.
+    si = &SCRIPT_ITEM(current_sctx.sc_sid);
+    if (si->sn_save_cpo != NULL)
+    {
+	free_string_option(p_cpo);
+	p_cpo = si->sn_save_cpo;
+	si->sn_save_cpo = NULL;
+    }
+
     current_sctx = save_current_sctx;
     restore_funccal();
 # ifdef FEAT_PROFILE
@@ -1488,7 +1538,9 @@ free_scriptnames(void)
     {
 	// the variables themselves are cleared in evalvars_clear()
 	vim_free(SCRIPT_ITEM(i).sn_vars);
+
 	vim_free(SCRIPT_ITEM(i).sn_name);
+	free_string_option(SCRIPT_ITEM(i).sn_save_cpo);
 #  ifdef FEAT_PROFILE
 	ga_clear(&SCRIPT_ITEM(i).sn_prl_ga);
 #  endif
@@ -1789,6 +1841,11 @@ ex_scriptversion(exarg_T *eap UNUSED)
 	emsg(_("E984: :scriptversion used outside of a sourced file"));
 	return;
     }
+    if (current_sctx.sc_version == SCRIPT_VERSION_VIM9)
+    {
+	emsg(_("E1040: Cannot use :scriptversion after :vim9script"));
+	return;
+    }
 
     nr = getdigits(&eap->arg);
     if (nr == 0 || *eap->arg != NUL)