patch 8.2.4726: cannot use expand() to get the script name v8.2.4726
authorLemonBoy <thatlemon@gmail.com>
Sat, 9 Apr 2022 20:42:10 +0000 (21:42 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 9 Apr 2022 20:42:10 +0000 (21:42 +0100)
Problem:    Cannot use expand() to get the script name.
Solution:   Support expand('<script>'). (closes #10121)

runtime/doc/cmdline.txt
src/errors.h
src/ex_docmd.c
src/scriptfile.c
src/testdir/test_expand.vim
src/version.c
src/vim.h

index 0867c47fa47f6d786166000da46f56251ad7c48f..cd9b988a749c5aa36e3c0597f23e07f1d0c0353c 100644 (file)
@@ -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*
index 82c585e7e6f1983ea2708e1422174bff82277526..228a1d2bd9f8836fb53c5507f0c1518f5400549a 100644 (file)
@@ -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>\""));
index 7e3cb7ec37b971fed64130d399c9ea68371fdc0f..42824d7bb494ac681be4a49de33ec9a13ee82d37 100644 (file)
@@ -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
index ec47edf72d2f4fb2807e99fec377f233efc127b5..7e14cdc6e351f75e44fe6f934ba0831f70001302 100644 (file)
@@ -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"
index 638f9c7c3466d6171265318974702d1df54ddb1e..fee5f2fe860c050cc8062ebc28a55aa39d2bb465 100644 (file)
@@ -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
index 740c32d482dc2ddc11ec113fb413704693f6dc77..8b4f302a2ba88a485e41e8c873677b4361726120 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4726,
 /**/
     4725,
 /**/
index f9ec6e54a7fea20bbcefff628da0ba68908c20c0..0dcadd1b4e9e49ea8f98c3d847519392338369bd 100644 (file)
--- 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.