如何获取正在执行的vim脚本的路径?

72

在我的 vim 插件中,我有两个文件:

myplugin/plugin.vim
myplugin/plugin_helpers.py

我想使用vim的python支持,从plugin.vim文件中导入plugin_helpers,因此我认为我首先需要将我的插件目录放在python的sys.path中。

如何在vimscript中获取当前正在执行脚本的路径?在python中,这是__file__。在ruby中,它是__FILE__。通过谷歌搜索,我找不到任何类似于vim的东西,这可行吗?

注意:我不是在寻找当前编辑的文件("%:p"和friends)。


1
相对于当前脚本的路径:execute 'source ' . expand('<sfile>:p:h') . '/another.vim' - Ciro Santilli OurBigBook.com
4个回答

112
" 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')

我经常使用最后一个,因为我的~/.vimrc是指向 git 存储库中脚本的符号链接。


2
谢谢!这个问题早已得到解答,但我现在会回答它,因为额外的信息可能会有用。 - gfxmonk

39

找到了:

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

24
如果有帮助到其他人的话,确保在最高级别的作用域中执行此操作。如果您尝试在函数内部运行它,您最终会获得函数名称而不是包含函数的文件的路径。 - Mat Schaffer
4
我很惊讶在互联网上找到这个信息是多么的困难,非常感谢! - Jesse the Game
3
"<sfile>:p" 表示绝对路径。"<sfile>:p:h" 表示脚本所在的目录。 - Zenexer
3
另外注意:你可能需要用 resolve() 将这个内容包起来,因为 <sfile> 可能是一个符号链接。 - Zenexer

18
值得一提的是,上述解决方案仅在函数外部起作用。 这样做将无法得到期望的结果:
function! MyFunction()
let s:current_file=expand('<sfile>:p:h')
echom s:current_file
endfunction

但是这将会:

let s:current_file=expand('<sfile>')
function! MyFunction()
echom s:current_file
endfunction

以下是针对 OP 的原始问题的完整解决方案:

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
谢谢!在阅读了一些“资料”之后,我终于有足够的见解来做到这一点。我在Ruby中使用它,并使用load而不是require每次重新加载脚本,这使得在对lib进行更改时更加容易。 - Emile Vrijdags

0
如果你真的想在函数内获取脚本路径(这是我想要的),你仍然可以使用 <sfile> 的第二个语义,或者它的等效物 <stack>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 .
然而,你可能不想在插件中使用它,因为你可以在插件中使用自动加载函数,使用这种`relative#path#to#plugin#root#script`的表示方法。
我用这个来进行资源引用:
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>)

然后,您可以在任何脚本中使用SourceLocal来相对于它引用另一个脚本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接