diff options
author | LemonBoy <thatlemon@gmail.com> | 2022-04-09 21:42:10 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-04-09 21:42:10 +0100 |
commit | 6013d0045dec7ca7c0068fbe186c42d754a7368b (patch) | |
tree | 739c5e84ced49602b15e033e3af9c909f9cc3e50 | |
parent | 2ce97ae6aaec7007cca16a446d73161b82f2ba69 (diff) | |
download | vim-git-6013d0045dec7ca7c0068fbe186c42d754a7368b.tar.gz |
patch 8.2.4726: cannot use expand() to get the script namev8.2.4726
Problem: Cannot use expand() to get the script name.
Solution: Support expand('<script>'). (closes #10121)
-rw-r--r-- | runtime/doc/cmdline.txt | 8 | ||||
-rw-r--r-- | src/errors.h | 2 | ||||
-rw-r--r-- | src/ex_docmd.c | 28 | ||||
-rw-r--r-- | src/scriptfile.c | 29 | ||||
-rw-r--r-- | src/testdir/test_expand.vim | 50 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim.h | 3 |
7 files changed, 113 insertions, 9 deletions
diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt index 0867c47fa..cd9b988a7 100644 --- a/runtime/doc/cmdline.txt +++ b/runtime/doc/cmdline.txt @@ -939,7 +939,7 @@ Note: these are typed literally, they are not special keys! file name of the sourced file. *E498* When executing a legacy function, is replaced with the call stack, as with <stack> (this is for backwards - compatibility, using <stack> is preferred). + compatibility, using <stack> or <script> is preferred). In Vim9 script using <sfile> in a function gives error *E1245* . Note that filename-modifiers are useless when <sfile> is @@ -951,6 +951,12 @@ Note: these are typed literally, they are not special keys! ".." in between items. E.g.: "function {function-name1}[{lnum}]..{function-name2}[{lnum}]" If there is no call stack you get error *E489* . + *:<script>* *<script>* + <script> When executing a `:source` command, is replaced with the file + name of the sourced file. When executing a function, is + replaced with the file name of the script where it is + defined. + If the file name cannot be determined you get error *E1274* . *:<slnum>* *<slnum>* <slnum> When executing a ":source" command, is replaced with the line number. *E842* diff --git a/src/errors.h b/src/errors.h index 82c585e7e..228a1d2bd 100644 --- a/src/errors.h +++ b/src/errors.h @@ -3258,3 +3258,5 @@ EXTERN char e_using_type_not_in_script_context_str[] #endif EXTERN char e_nfa_regexp_missing_value_in_chr[] INIT(= N_("E1273: (NFA regexp) missing value in '\\%%%c'")); +EXTERN char e_no_script_file_name_to_substitute_for_script[] + INIT(= N_("E1274: No script file name to substitute for \"<script>\"")); diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 7e3cb7ec3..42824d7bb 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -8957,8 +8957,10 @@ find_cmdline_var(char_u *src, int *usedlen) #define SPEC_SLNUM (SPEC_SFILE + 1) "<stack>", // call stack #define SPEC_STACK (SPEC_SLNUM + 1) + "<script>", // script file name +#define SPEC_SCRIPT (SPEC_STACK + 1) "<afile>", // autocommand file name -#define SPEC_AFILE (SPEC_STACK + 1) +#define SPEC_AFILE (SPEC_SCRIPT + 1) "<abuf>", // autocommand buffer number #define SPEC_ABUF (SPEC_AFILE + 1) "<amatch>", // autocommand match name @@ -9226,14 +9228,28 @@ eval_vars( break; case SPEC_SFILE: // file name for ":so" command + result = estack_sfile(ESTACK_SFILE); + if (result == NULL) + { + *errormsg = _(e_no_source_file_name_to_substitute_for_sfile); + return NULL; + } + resultbuf = result; // remember allocated string + break; case SPEC_STACK: // call stack - result = estack_sfile(spec_idx == SPEC_SFILE - ? ESTACK_SFILE : ESTACK_STACK); + result = estack_sfile(ESTACK_STACK); + if (result == NULL) + { + *errormsg = _(e_no_call_stack_to_substitute_for_stack); + return NULL; + } + resultbuf = result; // remember allocated string + break; + case SPEC_SCRIPT: // script file name + result = estack_sfile(ESTACK_SCRIPT); if (result == NULL) { - *errormsg = spec_idx == SPEC_SFILE - ? _(e_no_source_file_name_to_substitute_for_sfile) - : _(e_no_call_stack_to_substitute_for_stack); + *errormsg = _(e_no_script_file_name_to_substitute_for_script); return NULL; } resultbuf = result; // remember allocated string diff --git a/src/scriptfile.c b/src/scriptfile.c index ec47edf72..7e14cdc6e 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -118,7 +118,8 @@ estack_pop(void) /* * Get the current value for <sfile> in allocated memory. - * "which" is ESTACK_SFILE for <sfile> and ESTACK_STACK for <stack>. + * "which" is ESTACK_SFILE for <sfile>, ESTACK_STACK for <stack> or + * ESTACK_SCRIPT for <script>. */ char_u * estack_sfile(estack_arg_T which UNUSED) @@ -156,6 +157,32 @@ estack_sfile(estack_arg_T which UNUSED) return NULL; } + // If evaluated in a function return the path of the script where the + // function is defined, at script level the current script path is returned + // instead. + if (which == ESTACK_SCRIPT) + { + if (entry->es_type == ETYPE_UFUNC) + { + sctx_T *def_ctx = &entry->es_info.ufunc->uf_script_ctx; + + if (def_ctx->sc_sid > 0) + return vim_strsave(SCRIPT_ITEM(def_ctx->sc_sid)->sn_name); + } + else if (exestack.ga_len > 0) + { + // Walk the stack backwards, starting from the current frame. + for (idx = exestack.ga_len - 1; idx; --idx) + { + entry = ((estack_T *)exestack.ga_data) + idx; + + if (entry->es_type == ETYPE_SCRIPT) + return vim_strsave(entry->es_name); + } + } + return NULL; + } + // Give information about each stack entry up to the root. // For a function we compose the call stack, as it was done in the past: // "function One[123]..Two[456]..Three" diff --git a/src/testdir/test_expand.vim b/src/testdir/test_expand.vim index 638f9c7c3..fee5f2fe8 100644 --- a/src/testdir/test_expand.vim +++ b/src/testdir/test_expand.vim @@ -159,4 +159,54 @@ func Test_expandcmd_shell_nonomatch() call assert_equal('$*', expandcmd('$*')) endfunc +func Test_expand_script_source() + let lines0 =<< trim [SCRIPT] + let g:script_level[0] = expand('<script>:t') + so Xscript1 + func F0() + let g:func_level[0] = expand('<script>:t') + endfunc + [SCRIPT] + + let lines1 =<< trim [SCRIPT] + let g:script_level[1] = expand('<script>:t') + so Xscript2 + func F1() + let g:func_level[1] = expand('<script>:t') + endfunc + [SCRIPT] + + let lines2 =<< trim [SCRIPT] + let g:script_level[2] = expand('<script>:t') + func F2() + let g:func_level[2] = expand('<script>:t') + endfunc + [SCRIPT] + + call writefile(lines0, 'Xscript0') + call writefile(lines1, 'Xscript1') + call writefile(lines2, 'Xscript2') + + " Check the expansion of <script> at script and function level. + let g:script_level = ['', '', ''] + let g:func_level = ['', '', ''] + + so Xscript0 + call F0() + call F1() + call F2() + + call assert_equal(['Xscript0', 'Xscript1', 'Xscript2'], g:script_level) + call assert_equal(['Xscript0', 'Xscript1', 'Xscript2'], g:func_level) + + unlet g:script_level g:func_level + delfunc F0 + delfunc F1 + delfunc F2 + + call delete('Xscript0') + call delete('Xscript1') + call delete('Xscript2') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 740c32d48..8b4f302a2 100644 --- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 4726, +/**/ 4725, /**/ 4724, @@ -2220,7 +2220,8 @@ typedef enum { typedef enum { ESTACK_NONE, ESTACK_SFILE, - ESTACK_STACK + ESTACK_STACK, + ESTACK_SCRIPT, } estack_arg_T; // Flags for assignment functions. |