If you really want to get the script path inside a function (which is what I'd like to), you can still use <sfile>
's second semantic, or its equivalent <stack>
inside expand()
.
<sfile> ...
When executing a legacy function, is replaced with the call
stack, as with <stack>
...
:<stack> <stack>
<stack> is replaced with the call stack, using
"function {function-name}[{lnum}]" for a function line
and "script {file-name}[{lnum}]" for a script line, and
".." in between items. E.g.:
"function {function-name1}[{lnum}]..{function-name2}[{lnum}]"
If there is no call stack you get error E489 .
However you possibly don't want to use it in a plugin, as you can use autoload functions in plugin, using this relative#path#to#plugin#root#script
notation.
I use this for sourcing purpose:
function! s:SourceLocal(script)
let l:callstack = expand("<stack>")
let l:list = split(l:callstack, '\.\.')
" list[-1] is SourceLocal function itself
" list[-2] is the calling script
let l:script_name = matchstr(l:list[-2], '^\(script \)\=\zs.\+\ze\[\d\+\]$')
let l:script_path = fnamemodify(l:script_name, ":p:h")
" l:script_path is the path where the script calling this function resides
execute printf("source %s/%s", l:script_path, a:script)
endfunction
command! -nargs=1 SourceLocal :call s:SourceLocal(<f-args>)
Then you can SourceLocal
inside any script to source another script relative to it.