summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLemonBoy <thatlemon@gmail.com>2022-04-09 21:42:10 +0100
committerBram Moolenaar <Bram@vim.org>2022-04-09 21:42:10 +0100
commit6013d0045dec7ca7c0068fbe186c42d754a7368b (patch)
tree739c5e84ced49602b15e033e3af9c909f9cc3e50
parent2ce97ae6aaec7007cca16a446d73161b82f2ba69 (diff)
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.txt8
-rw-r--r--src/errors.h2
-rw-r--r--src/ex_docmd.c28
-rw-r--r--src/scriptfile.c29
-rw-r--r--src/testdir/test_expand.vim50
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h3
7 files changed, 113 insertions, 9 deletions
diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt
index 0867c47fa4..cd9b988a74 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 82c585e7e6..228a1d2bd9 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 7e3cb7ec37..42824d7bb4 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 ec47edf72d..7e14cdc6e3 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 638f9c7c34..fee5f2fe86 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 740c32d482..8b4f302a2b 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,
diff --git a/src/vim.h b/src/vim.h
index f9ec6e54a7..0dcadd1b4e 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -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.