aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Dewar <seandewar@users.noreply.github.com>2021-10-14 00:40:46 +0100
committerSean Dewar <seandewar@users.noreply.github.com>2021-10-14 12:50:04 +0100
commitda9b0abc67a936021a4ecf7634395db860edcab1 (patch)
treef193d08a729743d2f165a81486df78dfd2b6acce
parentd4ed51eb4492d4358eb4ab0c939802f2a5fdc636 (diff)
downloadrneovim-da9b0abc67a936021a4ecf7634395db860edcab1.tar.gz
rneovim-da9b0abc67a936021a4ecf7634395db860edcab1.tar.bz2
rneovim-da9b0abc67a936021a4ecf7634395db860edcab1.zip
feat(:source, nvim_exec): defer script item creation until s:var access
For anonymous scripts, defer the creation of script items until an attempt to access a script-local variable is made. This dramatically reduces the number of script items created when using lots of vim.cmd and nvim_exec especially. This will mean <SID> usage fails until a script-local variable access is first made.
-rw-r--r--src/nvim/eval.c6
-rw-r--r--src/nvim/ex_cmds2.c30
-rw-r--r--src/nvim/ex_cmds2.h25
-rw-r--r--test/functional/api/vim_spec.lua22
-rw-r--r--test/functional/ex_cmds/source_spec.lua10
5 files changed, 61 insertions, 32 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index ac659fbda4..2709f24998 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -9191,8 +9191,12 @@ static hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, cons
} else if (*name == 'l' && funccal != NULL) { // local variable
*d = &funccal->l_vars;
} else if (*name == 's' // script variable
- && current_sctx.sc_sid > 0
+ && (current_sctx.sc_sid > 0 || current_sctx.sc_sid == SID_STR)
&& current_sctx.sc_sid <= ga_scripts.ga_len) {
+ // For anonymous scripts without a script item, create one now so script vars can be used
+ if (current_sctx.sc_sid == SID_STR) {
+ new_script_item(NULL, &current_sctx.sc_sid);
+ }
*d = &SCRIPT_SV(current_sctx.sc_sid)->sv_dict;
}
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index c421d3991c..4d26e16104 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -52,33 +52,7 @@
#include "nvim/version.h"
#include "nvim/window.h"
-
/// Growarray to store info about already sourced scripts.
-/// Also store the dev/ino, so that we don't have to stat() each
-/// script when going through the list.
-typedef struct scriptitem_S {
- char_u *sn_name;
- bool file_id_valid;
- FileID file_id;
- bool sn_prof_on; ///< true when script is/was profiled
- bool sn_pr_force; ///< forceit: profile functions in this script
- proftime_T sn_pr_child; ///< time set when going into first child
- int sn_pr_nest; ///< nesting for sn_pr_child
- // profiling the script as a whole
- int sn_pr_count; ///< nr of times sourced
- proftime_T sn_pr_total; ///< time spent in script + children
- proftime_T sn_pr_self; ///< time spent in script itself
- proftime_T sn_pr_start; ///< time at script start
- proftime_T sn_pr_children; ///< time in children after script start
- // profiling the script per line
- garray_T sn_prl_ga; ///< things stored for every line
- proftime_T sn_prl_start; ///< start time for current line
- proftime_T sn_prl_children; ///< time spent in children for this line
- proftime_T sn_prl_wait; ///< wait start time for current line
- linenr_T sn_prl_idx; ///< index of line being timed; -1 if none
- int sn_prl_execed; ///< line being timed was executed
-} scriptitem_T;
-
static garray_T script_items = { 0, 0, sizeof(scriptitem_T), 4, NULL };
#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
@@ -1944,7 +1918,7 @@ static char_u *get_str_line(int c, void *cookie, int indent, bool do_concat)
/// @param name File name of the script. NULL for anonymous :source.
/// @param[out] sid_out SID of the new item.
/// @return pointer to the created script item.
-static scriptitem_T *new_script_item(char_u *const name, scid_T *const sid_out)
+scriptitem_T *new_script_item(char_u *const name, scid_T *const sid_out)
{
static scid_T last_current_SID = 0;
const scid_T sid = ++last_current_SID;
@@ -1978,7 +1952,7 @@ static int source_using_linegetter(void *cookie, LineGetter fgetline, const char
sourcing_lnum = 0;
const sctx_T save_current_sctx = current_sctx;
- new_script_item(NULL, &current_sctx.sc_sid);
+ current_sctx.sc_sid = SID_STR;
current_sctx.sc_seq = 0;
current_sctx.sc_lnum = save_sourcing_lnum;
funccal_entry_T entry;
diff --git a/src/nvim/ex_cmds2.h b/src/nvim/ex_cmds2.h
index de4e1429b7..d426ff28f8 100644
--- a/src/nvim/ex_cmds2.h
+++ b/src/nvim/ex_cmds2.h
@@ -16,6 +16,31 @@
#define CCGD_ALLBUF 8 // may write all buffers
#define CCGD_EXCMD 16 // may suggest using !
+/// Also store the dev/ino, so that we don't have to stat() each
+/// script when going through the list.
+typedef struct scriptitem_S {
+ char_u *sn_name;
+ bool file_id_valid;
+ FileID file_id;
+ bool sn_prof_on; ///< true when script is/was profiled
+ bool sn_pr_force; ///< forceit: profile functions in this script
+ proftime_T sn_pr_child; ///< time set when going into first child
+ int sn_pr_nest; ///< nesting for sn_pr_child
+ // profiling the script as a whole
+ int sn_pr_count; ///< nr of times sourced
+ proftime_T sn_pr_total; ///< time spent in script + children
+ proftime_T sn_pr_self; ///< time spent in script itself
+ proftime_T sn_pr_start; ///< time at script start
+ proftime_T sn_pr_children; ///< time in children after script start
+ // profiling the script per line
+ garray_T sn_prl_ga; ///< things stored for every line
+ proftime_T sn_prl_start; ///< start time for current line
+ proftime_T sn_prl_children; ///< time spent in children for this line
+ proftime_T sn_prl_wait; ///< wait start time for current line
+ linenr_T sn_prl_idx; ///< index of line being timed; -1 if none
+ int sn_prl_execed; ///< line being timed was executed
+} scriptitem_T;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_cmds2.h.generated.h"
#endif
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index f878a50a26..d8914a3ab7 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -89,6 +89,14 @@ describe('API', function()
it(':verbose set {option}?', function()
nvim('exec', 'set nowrap', false)
+ eq('nowrap\n\tLast set from anonymous :source',
+ nvim('exec', 'verbose set wrap?', true))
+
+ -- Using script var to force creation of a script item
+ nvim('exec', [[
+ let s:a = 1
+ set nowrap
+ ]], false)
eq('nowrap\n\tLast set from anonymous :source (script id 1)',
nvim('exec', 'verbose set wrap?', true))
end)
@@ -155,6 +163,20 @@ describe('API', function()
let s:pirate = 'script-scoped varrrrr'
call nvim_exec('echo s:pirate', 1)
]], false))
+
+ -- Script items are created only on script var access
+ eq('1\n0', nvim('exec', [[
+ echo expand("<SID>")->empty()
+ let s:a = 123
+ echo expand("<SID>")->empty()
+ ]], true))
+
+ eq('1\n0', nvim('exec', [[
+ echo expand("<SID>")->empty()
+ function s:a() abort
+ endfunction
+ echo expand("<SID>")->empty()
+ ]], true))
end)
it('non-ASCII input', function()
diff --git a/test/functional/ex_cmds/source_spec.lua b/test/functional/ex_cmds/source_spec.lua
index 8077b22e56..fa650d611b 100644
--- a/test/functional/ex_cmds/source_spec.lua
+++ b/test/functional/ex_cmds/source_spec.lua
@@ -26,13 +26,17 @@ describe(':source', function()
\ k: "v"
"\ (o_o)
\ }
+ let c = expand("<SID>")->empty()
let s:s = 0zbeef.cafe
- let c = s:s]])
+ let d = s:s]])
command('source')
eq('2', meths.exec('echo a', true))
eq("{'k': 'v'}", meths.exec('echo b', true))
- eq("0zBEEFCAFE", meths.exec('echo c', true))
+
+ -- Script items are created only on script var access
+ eq("1", meths.exec('echo c', true))
+ eq("0zBEEFCAFE", meths.exec('echo d', true))
exec('set cpoptions+=C')
eq('Vim(let):E15: Invalid expression: #{', exc_exec('source'))
@@ -62,7 +66,7 @@ describe(':source', function()
feed_command(':source')
eq('4', meths.exec('echo a', true))
eq("{'K': 'V'}", meths.exec('echo b', true))
- eq("<SNR>3_C()", meths.exec('echo D()', true))
+ eq("<SNR>1_C()", meths.exec('echo D()', true))
-- Source last line only
feed_command(':$source')