vim-patch:8.2.4726: cannot use expand() to get the script name

Problem:    Cannot use expand() to get the script name.
Solution:   Support expand('<script>'). (closes vim/vim#10121)
6013d0045d

Use `.sn_name` instead of `->sn_name` as v8.2.0154 hasn't been ported.
Cherry-pick builtin.txt expand() doc from latest Vim.
This commit is contained in:
zeertzjq
2022-08-20 07:54:14 +08:00
parent 42e9fe7d95
commit ffa1335047
7 changed files with 113 additions and 7 deletions

View File

@@ -94,6 +94,12 @@ static char e_ambiguous_use_of_user_defined_command[]
= N_("E464: Ambiguous use of user-defined command");
static char e_not_an_editor_command[]
= N_("E492: Not an editor command");
static char e_no_source_file_name_to_substitute_for_sfile[]
= N_("E498: no :source file name to substitute for \"<sfile>\"");
static char e_no_call_stack_to_substitute_for_stack[]
= N_("E489: no call stack to substitute for \"<stack>\"");
static char e_no_script_file_name_to_substitute_for_script[]
= N_("E1274: No script file name to substitute for \"<script>\"");
static int quitmore = 0;
static bool ex_pressedreturn = false;
@@ -6564,6 +6570,7 @@ enum {
SPEC_SFILE,
SPEC_SLNUM,
SPEC_STACK,
SPEC_SCRIPT,
SPEC_AFILE,
SPEC_ABUF,
SPEC_AMATCH,
@@ -6588,6 +6595,7 @@ ssize_t find_cmdline_var(const char_u *src, size_t *usedlen)
[SPEC_SFILE] = "<sfile>", // ":so" file name
[SPEC_SLNUM] = "<slnum>", // ":so" file line number
[SPEC_STACK] = "<stack>", // call stack
[SPEC_SCRIPT] = "<script>", // script file name
[SPEC_AFILE] = "<afile>", // autocommand file name
[SPEC_ABUF] = "<abuf>", // autocommand buffer number
[SPEC_AMATCH] = "<amatch>", // autocommand match name
@@ -6801,12 +6809,25 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
break;
case SPEC_SFILE: // file name for ":so" command
case SPEC_STACK: // call stack
result = estack_sfile(spec_idx == SPEC_SFILE ? ESTACK_SFILE : ESTACK_STACK);
result = estack_sfile(ESTACK_SFILE);
if (result == NULL) {
*errormsg = spec_idx == SPEC_SFILE
? _("E498: no :source file name to substitute for \"<sfile>\"")
: _("E489: no call stack to substitute for \"<stack>\"");
*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(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 = _(e_no_script_file_name_to_substitute_for_script);
return NULL;
}
resultbuf = result; // remember allocated string

View File

@@ -100,7 +100,8 @@ void estack_pop(void)
}
/// Get the current value for <sfile> in allocated memory.
/// @param which ESTACK_SFILE for <sfile> and ESTACK_STACK for <stack>.
/// @param which ESTACK_SFILE for <sfile>, ESTACK_STACK for <stack> or
/// ESTACK_SCRIPT for <script>.
char *estack_sfile(estack_arg_T which)
{
estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1;
@@ -111,6 +112,27 @@ char *estack_sfile(estack_arg_T which)
return xstrdup(entry->es_name);
}
// 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 xstrdup((char *)(SCRIPT_ITEM(def_ctx->sc_sid).sn_name));
}
} else if (exestack.ga_len > 0) {
// Walk the stack backwards, starting from the current frame.
for (int idx = exestack.ga_len - 1; idx; idx--) {
entry = ((estack_T *)exestack.ga_data) + idx;
if (entry->es_type == ETYPE_SCRIPT) {
return xstrdup(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"

View File

@@ -47,6 +47,7 @@ typedef enum {
ESTACK_NONE,
ESTACK_SFILE,
ESTACK_STACK,
ESTACK_SCRIPT,
} estack_arg_T;
typedef struct scriptitem_S {

View File

@@ -147,4 +147,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