diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-12-26 15:39:31 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-12-26 15:39:31 +0100 |
commit | 2b32700dabf392566d8e9fef76e0d587a891ee3e (patch) | |
tree | 3f83eabd005ede0c2dc4fd171b8a9cbb3fb412f6 /src | |
parent | b0ac4ea5e1c5f0ff4e951978c32ccfffe46916f8 (diff) |
patch 8.2.2222: Vim9: cannot keep script variables when reloadingv8.2.2222
Problem: Vim9: cannot keep script variables when reloading.
Solution: Add the "noclear" argument to :vim9script.
Diffstat (limited to 'src')
-rw-r--r-- | src/ex_cmds.h | 2 | ||||
-rw-r--r-- | src/ex_docmd.c | 2 | ||||
-rw-r--r-- | src/scriptfile.c | 50 | ||||
-rw-r--r-- | src/structs.h | 6 | ||||
-rw-r--r-- | src/testdir/test_vim9_script.vim | 47 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9script.c | 30 |
7 files changed, 101 insertions, 38 deletions
diff --git a/src/ex_cmds.h b/src/ex_cmds.h index 5e61c3e7e7..75bb7fb943 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -1680,7 +1680,7 @@ EXCMD(CMD_vimgrepadd, "vimgrepadd", ex_vimgrep, EX_RANGE|EX_BANG|EX_NEEDARG|EX_EXTRA|EX_NOTRLCOM|EX_TRLBAR|EX_XFILE|EX_LOCK_OK, ADDR_OTHER), EXCMD(CMD_vim9script, "vim9script", ex_vim9script, - EX_CMDWIN|EX_LOCK_OK, + EX_WORD1|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), EXCMD(CMD_viusage, "viusage", ex_viusage, EX_TRLBAR, diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 69e3f12e69..156f0df16a 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -2594,7 +2594,7 @@ do_one_cmd( // Set flag that any command was executed, used by ex_vim9script(). if (getline_equal(ea.getline, ea.cookie, getsourceline) && current_sctx.sc_sid > 0) - SCRIPT_ITEM(current_sctx.sc_sid)->sn_had_command = TRUE; + SCRIPT_ITEM(current_sctx.sc_sid)->sn_state = SN_STATE_HAD_COMMAND; /* * If the command just executed called do_cmdline(), any throw or ":return" diff --git a/src/scriptfile.c b/src/scriptfile.c index 327500bd07..38704a7fd7 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -1320,43 +1320,27 @@ do_source( if (sid > 0) { hashtab_T *ht; - int is_vim9 = si->sn_version == SCRIPT_VERSION_VIM9; + int todo; + hashitem_T *hi; + dictitem_T *di; // loading the same script again - si->sn_had_command = FALSE; + si->sn_state = SN_STATE_RELOAD; si->sn_version = 1; current_sctx.sc_sid = sid; - // In Vim9 script all script-local variables are removed when reloading - // the same script. In legacy script they remain but "const" can be - // set again. + // 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); - if (is_vim9) - { - hashtab_free_contents(ht); - hash_init(ht); - } - else - { - int todo = (int)ht->ht_used; - hashitem_T *hi; - dictitem_T *di; - - for (hi = ht->ht_array; todo > 0; ++hi) - if (!HASHITEM_EMPTY(hi)) - { - --todo; - di = HI2DI(hi); - di->di_flags |= DI_FLAGS_RELOAD; - } - } - - // old imports and script variables are no longer valid - free_imports_and_script_vars(sid); - - // in Vim9 script functions are marked deleted - if (is_vim9) - delete_script_functions(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; + } } else { @@ -1390,8 +1374,10 @@ do_source( fname_exp = vim_strsave(si->sn_name); // used for autocmd if (ret_sid != NULL) *ret_sid = current_sctx.sc_sid; + + // Used to check script variable index is still valid. + si->sn_script_seq = current_sctx.sc_seq; } - si->sn_script_seq = current_sctx.sc_seq; # ifdef FEAT_PROFILE if (do_profiling == PROF_YES) diff --git a/src/structs.h b/src/structs.h index ea994f8b70..93a6b0ad52 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1821,7 +1821,7 @@ typedef struct int sn_last_block_id; // Unique ID for each script block int sn_version; // :scriptversion - int sn_had_command; // TRUE if any command was executed + int sn_state; // SN_STATE_ values char_u *sn_save_cpo; // 'cpo' value when :vim9script found # ifdef FEAT_PROFILE @@ -1845,6 +1845,10 @@ typedef struct # endif } scriptitem_T; +#define SN_STATE_NEW 0 // newly loaded script, nothing done +#define SN_STATE_RELOAD 1 // script loaded before, nothing done +#define SN_STATE_HAD_COMMAND 9 // a command was executed + // Struct passed through eval() functions. // See EVALARG_EVALUATE for a fixed value with eval_flags set to EVAL_EVALUATE. typedef struct { diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 1e64daaec3..cdd83c348b 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -1158,6 +1158,53 @@ def Run_Test_import_fails_on_command_line() StopVimInTerminal(buf) enddef +def Test_vim9script_reload_noclear() + var lines =<< trim END + vim9script noclear + g:loadCount += 1 + var s:reloaded = 'init' + + def Again(): string + return 'again' + enddef + + if exists('s:loaded') | finish | endif + var s:loaded = true + + var s:notReloaded = 'yes' + s:reloaded = 'first' + def g:Values(): list<string> + return [s:reloaded, s:notReloaded, Once()] + enddef + def g:CallAgain(): string + return Again() + enddef + + def Once(): string + return 'once' + enddef + END + writefile(lines, 'XReloaded') + g:loadCount = 0 + source XReloaded + assert_equal(1, g:loadCount) + assert_equal(['first', 'yes', 'once'], g:Values()) + assert_equal('again', g:CallAgain()) + source XReloaded + assert_equal(2, g:loadCount) + assert_equal(['init', 'yes', 'once'], g:Values()) + assert_fails('call g:CallAgain()', 'E933:') + source XReloaded + assert_equal(3, g:loadCount) + assert_equal(['init', 'yes', 'once'], g:Values()) + assert_fails('call g:CallAgain()', 'E933:') + + delete('Xreloaded') + delfunc g:Values + delfunc g:CallAgain + unlet g:loadCount +enddef + def Test_vim9script_reload_import() var lines =<< trim END vim9script diff --git a/src/version.c b/src/version.c index ba5df927a6..f488d77c32 100644 --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2222, +/**/ 2221, /**/ 2220, diff --git a/src/vim9script.c b/src/vim9script.c index 163b8a7f35..70efc4065b 100644 --- a/src/vim9script.c +++ b/src/vim9script.c @@ -32,6 +32,7 @@ in_vim9script(void) void ex_vim9script(exarg_T *eap) { + int sid = current_sctx.sc_sid; scriptitem_T *si; if (!getline_equal(eap->getline, eap->cookie, getsourceline)) @@ -39,15 +40,35 @@ ex_vim9script(exarg_T *eap) emsg(_(e_vim9script_can_only_be_used_in_script)); return; } - si = SCRIPT_ITEM(current_sctx.sc_sid); - if (si->sn_had_command) + + si = SCRIPT_ITEM(sid); + if (si->sn_state == SN_STATE_HAD_COMMAND) { emsg(_(e_vim9script_must_be_first_command_in_script)); return; } + if (!IS_WHITE_OR_NUL(*eap->arg) && STRCMP(eap->arg, "noclear") != 0) + { + semsg(_(e_invarg2), eap->arg); + return; + } + if (si->sn_state == SN_STATE_RELOAD && IS_WHITE_OR_NUL(*eap->arg)) + { + 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; + current_sctx.sc_version = SCRIPT_VERSION_VIM9; si->sn_version = SCRIPT_VERSION_VIM9; - si->sn_had_command = TRUE; if (STRCMP(p_cpo, CPO_VIM) != 0) { @@ -719,6 +740,9 @@ free_all_script_vars(scriptitem_T *si) hash_init(ht); ga_clear(&si->sn_var_vals); + + // existing commands using script variable indexes are no longer valid + si->sn_script_seq = current_sctx.sc_seq; } /* |