mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 11:15:14 -07:00
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:
parent
42e9fe7d95
commit
ffa1335047
@ -2013,6 +2013,8 @@ expand({string} [, {nosuf} [, {list}]]) *expand()*
|
|||||||
a function
|
a function
|
||||||
<SID> "<SNR>123_" where "123" is the
|
<SID> "<SNR>123_" where "123" is the
|
||||||
current script ID |<SID>|
|
current script ID |<SID>|
|
||||||
|
<script> sourced script file, or script file
|
||||||
|
where the current function was defined
|
||||||
<stack> call stack
|
<stack> call stack
|
||||||
<cword> word under the cursor
|
<cword> word under the cursor
|
||||||
<cWORD> WORD under the cursor
|
<cWORD> WORD under the cursor
|
||||||
|
@ -881,7 +881,7 @@ Note: these are typed literally, they are not special keys!
|
|||||||
file name of the sourced file. *E498*
|
file name of the sourced file. *E498*
|
||||||
When executing a function, is replaced with the call stack,
|
When executing a function, is replaced with the call stack,
|
||||||
as with <stack> (this is for backwards compatibility, using
|
as with <stack> (this is for backwards compatibility, using
|
||||||
<stack> is preferred).
|
<stack> or <script> is preferred).
|
||||||
Note that filename-modifiers are useless when <sfile> is
|
Note that filename-modifiers are useless when <sfile> is
|
||||||
not used inside a script.
|
not used inside a script.
|
||||||
*:<stack>* *<stack>*
|
*:<stack>* *<stack>*
|
||||||
@ -891,6 +891,12 @@ Note: these are typed literally, they are not special keys!
|
|||||||
".." in between items. E.g.:
|
".." in between items. E.g.:
|
||||||
"function {function-name1}[{lnum}]..{function-name2}[{lnum}]"
|
"function {function-name1}[{lnum}]..{function-name2}[{lnum}]"
|
||||||
If there is no call stack you get error *E489* .
|
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>* *<slnum>*
|
||||||
<slnum> When executing a `:source` command, is replaced with the
|
<slnum> When executing a `:source` command, is replaced with the
|
||||||
line number. *E842*
|
line number. *E842*
|
||||||
|
@ -94,6 +94,12 @@ static char e_ambiguous_use_of_user_defined_command[]
|
|||||||
= N_("E464: Ambiguous use of user-defined command");
|
= N_("E464: Ambiguous use of user-defined command");
|
||||||
static char e_not_an_editor_command[]
|
static char e_not_an_editor_command[]
|
||||||
= N_("E492: 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 int quitmore = 0;
|
||||||
static bool ex_pressedreturn = false;
|
static bool ex_pressedreturn = false;
|
||||||
@ -6564,6 +6570,7 @@ enum {
|
|||||||
SPEC_SFILE,
|
SPEC_SFILE,
|
||||||
SPEC_SLNUM,
|
SPEC_SLNUM,
|
||||||
SPEC_STACK,
|
SPEC_STACK,
|
||||||
|
SPEC_SCRIPT,
|
||||||
SPEC_AFILE,
|
SPEC_AFILE,
|
||||||
SPEC_ABUF,
|
SPEC_ABUF,
|
||||||
SPEC_AMATCH,
|
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_SFILE] = "<sfile>", // ":so" file name
|
||||||
[SPEC_SLNUM] = "<slnum>", // ":so" file line number
|
[SPEC_SLNUM] = "<slnum>", // ":so" file line number
|
||||||
[SPEC_STACK] = "<stack>", // call stack
|
[SPEC_STACK] = "<stack>", // call stack
|
||||||
|
[SPEC_SCRIPT] = "<script>", // script file name
|
||||||
[SPEC_AFILE] = "<afile>", // autocommand file name
|
[SPEC_AFILE] = "<afile>", // autocommand file name
|
||||||
[SPEC_ABUF] = "<abuf>", // autocommand buffer number
|
[SPEC_ABUF] = "<abuf>", // autocommand buffer number
|
||||||
[SPEC_AMATCH] = "<amatch>", // autocommand match name
|
[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;
|
break;
|
||||||
|
|
||||||
case SPEC_SFILE: // file name for ":so" command
|
case SPEC_SFILE: // file name for ":so" command
|
||||||
case SPEC_STACK: // call stack
|
result = estack_sfile(ESTACK_SFILE);
|
||||||
result = estack_sfile(spec_idx == SPEC_SFILE ? ESTACK_SFILE : ESTACK_STACK);
|
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
*errormsg = spec_idx == SPEC_SFILE
|
*errormsg = _(e_no_source_file_name_to_substitute_for_sfile);
|
||||||
? _("E498: no :source file name to substitute for \"<sfile>\"")
|
return NULL;
|
||||||
: _("E489: no call stack to substitute for \"<stack>\"");
|
}
|
||||||
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
resultbuf = result; // remember allocated string
|
resultbuf = result; // remember allocated string
|
||||||
|
@ -100,7 +100,8 @@ void estack_pop(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current value for <sfile> in allocated memory.
|
/// 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)
|
char *estack_sfile(estack_arg_T which)
|
||||||
{
|
{
|
||||||
estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1;
|
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);
|
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.
|
// 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:
|
// For a function we compose the call stack, as it was done in the past:
|
||||||
// "function One[123]..Two[456]..Three"
|
// "function One[123]..Two[456]..Three"
|
||||||
|
@ -47,6 +47,7 @@ typedef enum {
|
|||||||
ESTACK_NONE,
|
ESTACK_NONE,
|
||||||
ESTACK_SFILE,
|
ESTACK_SFILE,
|
||||||
ESTACK_STACK,
|
ESTACK_STACK,
|
||||||
|
ESTACK_SCRIPT,
|
||||||
} estack_arg_T;
|
} estack_arg_T;
|
||||||
|
|
||||||
typedef struct scriptitem_S {
|
typedef struct scriptitem_S {
|
||||||
|
@ -147,4 +147,54 @@ func Test_expandcmd_shell_nonomatch()
|
|||||||
call assert_equal('$*', expandcmd('$*'))
|
call assert_equal('$*', expandcmd('$*'))
|
||||||
endfunc
|
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
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@ -166,6 +166,7 @@ describe(':source', function()
|
|||||||
vim.g.sourced_lua = 1
|
vim.g.sourced_lua = 1
|
||||||
vim.g.sfile_value = vim.fn.expand('<sfile>')
|
vim.g.sfile_value = vim.fn.expand('<sfile>')
|
||||||
vim.g.stack_value = vim.fn.expand('<stack>')
|
vim.g.stack_value = vim.fn.expand('<stack>')
|
||||||
|
vim.g.script_value = vim.fn.expand('<script>')
|
||||||
]])
|
]])
|
||||||
|
|
||||||
command('set shellslash')
|
command('set shellslash')
|
||||||
@ -173,6 +174,7 @@ describe(':source', function()
|
|||||||
eq(1, eval('g:sourced_lua'))
|
eq(1, eval('g:sourced_lua'))
|
||||||
matches([[/test%.lua$]], meths.get_var('sfile_value'))
|
matches([[/test%.lua$]], meths.get_var('sfile_value'))
|
||||||
matches([[/test%.lua$]], meths.get_var('stack_value'))
|
matches([[/test%.lua$]], meths.get_var('stack_value'))
|
||||||
|
matches([[/test%.lua$]], meths.get_var('script_value'))
|
||||||
|
|
||||||
os.remove(test_file)
|
os.remove(test_file)
|
||||||
end)
|
end)
|
||||||
@ -214,6 +216,7 @@ describe(':source', function()
|
|||||||
"\ 2]=]
|
"\ 2]=]
|
||||||
vim.g.sfile_value = vim.fn.expand('<sfile>')
|
vim.g.sfile_value = vim.fn.expand('<sfile>')
|
||||||
vim.g.stack_value = vim.fn.expand('<stack>')
|
vim.g.stack_value = vim.fn.expand('<stack>')
|
||||||
|
vim.g.script_value = vim.fn.expand('<script>')
|
||||||
]])
|
]])
|
||||||
|
|
||||||
command('edit '..test_file)
|
command('edit '..test_file)
|
||||||
@ -223,6 +226,7 @@ describe(':source', function()
|
|||||||
eq(' \\ 1\n "\\ 2', exec_lua('return _G.a'))
|
eq(' \\ 1\n "\\ 2', exec_lua('return _G.a'))
|
||||||
eq(':source (no file)', meths.get_var('sfile_value'))
|
eq(':source (no file)', meths.get_var('sfile_value'))
|
||||||
eq(':source (no file)', meths.get_var('stack_value'))
|
eq(':source (no file)', meths.get_var('stack_value'))
|
||||||
|
eq(':source (no file)', meths.get_var('script_value'))
|
||||||
|
|
||||||
os.remove(test_file)
|
os.remove(test_file)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user