74

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).

2
  • 1
    Source with path relative to the current script: execute 'source ' . expand('<sfile>:p:h') . '/another.vim' Commented Jun 25, 2015 at 8:44
  • About "relative source": Interestingly source <script>:p:h/foo.vim works for me as well. Commented Nov 10, 2024 at 15:37

4 Answers 4

116
" 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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! The question was already long answered, but I'll take this one now since the extra info is likely to be useful.
For future readers: use <script> to always get the file path. <sfile> gives the function name when expanded from within a function. See :help <sfile> and :help <script>.
39

Found it:

let s:current_file=expand("<sfile>")

4 Comments

Incase it helps anyone else. Make sure to do this at the top level scope. If you try to run it inside of a function you'll end up getting the function name rather than the path to the file containing the function.
I'm amazed how hard it was to find this information on the internet, thanks a bunch!
<sfile>:p for an absolute path. <sfile>:p:h for the directory in which the script resides.
Another note: You might want to enclose this in resolve(), as <sfile> could be a symbolic link.
18

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

1 Comment

Thanks! After reading a few 'sources', this finally gave me enough insight to get it right. I used it in ruby, and use load rather than require to reload the script every time, which makes it much easier when making changes to the lib.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.