Reputation: 8746
In my vim plugin, I have two files:
myplugin/plugin.vim
myplugin/plugin_helpers.py
I would like to import plugin_helpers from plugin.vim (using the vim python support), so I believe I first need to put the directory of my plugin on python's sys.path.
How can I (in vimscript) get the path to the currently executing script? In python, this is __file__
. In ruby, it's __FILE__
. I couldn't find anything similar for vim by googling, can it be done?
Note: I am not looking for the currently edited file ("%:p" and friends).
Upvotes: 73
Views: 19393
Reputation: 322
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.
Upvotes: 0
Reputation: 187
It is worth mentioning that the above solution will only work outside of a function.
This will not give the desired result:
function! MyFunction()
let s:current_file=expand('<sfile>:p:h')
echom s:current_file
endfunction
But this will:
let s:current_file=expand('<sfile>')
function! MyFunction()
echom s:current_file
endfunction
Here's a full solution to OP's original question:
let s:path = expand('<sfile>:p:h')
function! MyPythonFunction()
import sys
import os
script_path = vim.eval('s:path')
lib_path = os.path.join(script_path, '.')
sys.path.insert(0, lib_path)
import vim
import plugin_helpers
plugin_helpers.do_some_cool_stuff_here()
vim.command("badd %(result)s" % {'result':plugin_helpers.get_result()})
EOF
endfunction
Upvotes: 18
Reputation: 19611
" Relative path of script file:
let s:path = expand('<sfile>')
" Absolute path of script file:
let s:path = expand('<sfile>:p')
" Absolute path of script file with symbolic links resolved:
let s:path = resolve(expand('<sfile>:p'))
" Folder in which script resides: (not safe for symlinks)
let s:path = expand('<sfile>:p:h')
" If you're using a symlink to your script, but your resources are in
" the same directory as the actual script, you'll need to do this:
" 1: Get the absolute path of the script
" 2: Resolve all symbolic links
" 3: Get the folder of the resolved absolute file
let s:path = fnamemodify(resolve(expand('<sfile>:p')), ':h')
I use that last one often because my ~/.vimrc
is a symbolic link to a script in a git repository.
Upvotes: 114