# HG changeset patch # User Bram Moolenaar # Date 1578847503 -3600 # Node ID 44c6498535c9e419c493f5de8453dd7a73db2def # Parent d661615091639dd8e469ec2ba0e49e04674ecb92 patch 8.2.0114: info about sourced scripts is scattered Commit: https://github.com/vim/vim/commit/7ebcba61b20d25d23109fff73d0346ad44ba1b3b Author: Bram Moolenaar Date: Sun Jan 12 17:42:55 2020 +0100 patch 8.2.0114: info about sourced scripts is scattered Problem: Info about sourced scripts is scattered. Solution: Use scriptitem_T for info about a script, including s: variables. Drop ga_scripts. diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -149,8 +149,7 @@ eval_init(void) eval_clear(void) { evalvars_clear(); - - free_scriptnames(); + free_scriptnames(); // must come after evalvars_clear(). free_locales(); // autoloaded script names diff --git a/src/evalvars.c b/src/evalvars.c --- a/src/evalvars.c +++ b/src/evalvars.c @@ -163,18 +163,7 @@ static dict_T vimvardict; // Dictionar // for VIM_VERSION_ defines #include "version.h" -/* - * Array to hold the hashtab with variables local to each sourced script. - * Each item holds a variable (nameless) that points to the dict_T. - */ -typedef struct -{ - dictitem_T sv_var; - dict_T sv_dict; -} scriptvar_T; - -static garray_T ga_scripts = {0, 0, sizeof(scriptvar_T *), 4, NULL}; -#define SCRIPT_SV(id) (((scriptvar_T **)ga_scripts.ga_data)[(id) - 1]) +#define SCRIPT_SV(id) (SCRIPT_ITEM(id).sn_vars) #define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab) static void ex_let_const(exarg_T *eap, int is_const); @@ -289,14 +278,12 @@ evalvars_clear(void) // global variables vars_clear(&globvarht); - // Script-local variables. First clear all the variables and in a second - // loop free the scriptvar_T, because a variable in one script might hold - // a reference to the whole scope of another script. - for (i = 1; i <= ga_scripts.ga_len; ++i) + // Script-local variables. Clear all the variables here. + // The scriptvar_T is cleared later in free_scriptnames(), because a + // variable in one script might hold a reference to the whole scope of + // another script. + for (i = 1; i <= script_items.ga_len; ++i) vars_clear(&SCRIPT_VARS(i)); - for (i = 1; i <= ga_scripts.ga_len; ++i) - vim_free(SCRIPT_SV(i)); - ga_clear(&ga_scripts); } #endif @@ -318,7 +305,7 @@ garbage_collect_scriptvars(int copyID) int i; int abort = FALSE; - for (i = 1; i <= ga_scripts.ga_len; ++i) + for (i = 1; i <= script_items.ga_len; ++i) abort = abort || set_ref_in_ht(&SCRIPT_VARS(i), copyID, NULL); return abort; @@ -538,7 +525,7 @@ list_vim_vars(int *first) static void list_script_vars(int *first) { - if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= ga_scripts.ga_len) + if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len) list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid), "s:", FALSE, first); } @@ -2433,7 +2420,7 @@ find_var_ht(char_u *name, char_u **varna return get_funccal_local_ht(); if (*name == 's' // script variable && current_sctx.sc_sid > 0 - && current_sctx.sc_sid <= ga_scripts.ga_len) + && current_sctx.sc_sid <= script_items.ga_len) return &SCRIPT_VARS(current_sctx.sc_sid); return NULL; } @@ -2461,32 +2448,13 @@ get_var_value(char_u *name) void new_script_vars(scid_T id) { - int i; - hashtab_T *ht; scriptvar_T *sv; - if (ga_grow(&ga_scripts, (int)(id - ga_scripts.ga_len)) == OK) - { - // Re-allocating ga_data means that an ht_array pointing to - // ht_smallarray becomes invalid. We can recognize this: ht_mask is - // at its init value. Also reset "v_dict", it's always the same. - for (i = 1; i <= ga_scripts.ga_len; ++i) - { - ht = &SCRIPT_VARS(i); - if (ht->ht_mask == HT_INIT_SIZE - 1) - ht->ht_array = ht->ht_smallarray; - sv = SCRIPT_SV(i); - sv->sv_var.di_tv.vval.v_dict = &sv->sv_dict; - } - - while (ga_scripts.ga_len < id) - { - sv = SCRIPT_SV(ga_scripts.ga_len + 1) = - ALLOC_CLEAR_ONE(scriptvar_T); - init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE); - ++ga_scripts.ga_len; - } - } + sv = ALLOC_CLEAR_ONE(scriptvar_T); + if (sv == NULL) + return; + init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE); + SCRIPT_ITEM(id).sn_vars = sv; } /* diff --git a/src/scriptfile.c b/src/scriptfile.c --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -1236,7 +1236,7 @@ do_source( save_current_sctx = current_sctx; current_sctx.sc_lnum = 0; - current_sctx.sc_version = 1; + 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. @@ -1272,6 +1272,10 @@ do_source( { ++script_items.ga_len; SCRIPT_ITEM(script_items.ga_len).sn_name = NULL; + SCRIPT_ITEM(script_items.ga_len).sn_version = 1; + + // Allocate the local script variables to use for this script. + new_script_vars(script_items.ga_len); # ifdef FEAT_PROFILE SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE; # endif @@ -1289,9 +1293,6 @@ do_source( else si->sn_dev_valid = FALSE; # endif - - // Allocate the local script variables to use for this script. - new_script_vars(current_sctx.sc_sid); } # ifdef FEAT_PROFILE @@ -1483,6 +1484,8 @@ free_scriptnames(void) for (i = script_items.ga_len; i > 0; --i) { + // the variables themselves are cleared in evalvars_clear() + vim_free(SCRIPT_ITEM(i).sn_vars); vim_free(SCRIPT_ITEM(i).sn_name); # ifdef FEAT_PROFILE ga_clear(&SCRIPT_ITEM(i).sn_prl_ga); @@ -1791,7 +1794,10 @@ ex_scriptversion(exarg_T *eap UNUSED) else if (nr > 4) semsg(_("E999: scriptversion not supported: %d"), nr); else + { current_sctx.sc_version = nr; + SCRIPT_ITEM(current_sctx.sc_sid).sn_version = nr; + } #endif } diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -74,6 +74,8 @@ typedef struct VimMenu vimmenu_T; * function was defined, "sourcing_lnum" is the line number inside the * function. When stored with a function, mapping, option, etc. "sc_lnum" is * the line number in the script "sc_sid". + * + * sc_version is also here, for convenience. */ typedef struct { scid_T sc_sid; // script ID @@ -1566,13 +1568,28 @@ struct funccal_entry { #define HI2UF(hi) HIKEY2UF((hi)->hi_key) /* + * Holds the hashtab with variables local to each sourced script. + * Each item holds a variable (nameless) that points to the dict_T. + */ +typedef struct +{ + dictitem_T sv_var; + dict_T sv_dict; +} scriptvar_T; + +/* * Growarray to store info about already sourced scripts. * For Unix also store the dev/ino, so that we don't have to stat() each * script when going through the list. */ -typedef struct scriptitem_S +typedef struct { + scriptvar_T *sn_vars; // stores s: variables for this script + char_u *sn_name; + + int sn_version; // :scriptversion + # ifdef UNIX int sn_dev_valid; dev_t sn_dev; diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -743,6 +743,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 114, +/**/ 113, /**/ 112,