获取调用 vim 自动加载函数的文件名和行号

Get filename and line number that called vim autoload function

我正在尝试使用自动加载功能填充 quickfix 列表,即:

function! myplugin#myfunc(msg)

  " this doesn't work from *inside* an autoload function
  let filename = fnamemodify(resolve(expand('<sfile>:p')))

  " not sure if it's possible to get the line number from where
  " a function was called
  let linenum = '?#'

  " create qf dict object
  " set filename, line number, bufnr, text, etc
  " add dict to qflist
  " setqflist(qfdictlist)
endfunction!

我 运行 遇到的问题是我无法找到一种方法来从 调用 自动加载函数的代码中获取文件名和行号.有什么建议吗?

开箱即用。这是不可能的。

但是,根据具体情况,这里有一些线索。

如您所见,none 这些解决方案非常好。但是现在还有 none 其他。调用堆栈不可用,异常上下文中的 v:throwpoint 除外。唯一的其他解决方案是让调用者在调用时注入他们的引用 (~__FILE__ + ~__LINE__)。实现自动化的唯一方法是 将调用者脚本编译 到另一个自动注入缺失信息的脚本中。

现在,了解到上个月在 vim-dev 邮件列表上提出了一项提案,以允许访问调用堆栈,但遗憾的是,仅在调试会话期间:https://github.com/vim/vim/pull/433 如果这被接受,它可能会在以后扩展以提供 viml 函数来导出此信息。


编辑:你的问题激发了我为 vim 写一个 simplistic logging facility:

" Function: lh#log#new(where, kind) {{{3
" - where: "vert"/""/...
" - kind:  "qf"/"loc" for loclist
" NOTE: In order to obtain the name of the calling function, an exception is
" thrown and the backtrace is analysed.
" In order to work, this trick requires:
" - a reasonable callstack size (past a point, vim shortens the names returned
"   by v:throwpoint
" - named functions ; i.e. functions defined on dictionaries (and not attached
"   to them) will have their names mangled (actually it'll be a number) and
"   lh#exception#callstack() won't be able to decode them.
"   i.e.
"      function s:foo() dict abort
"         logger.log("here I am");
"      endfunction
"      let dict.foo = function('s:foo')
"   will work correctly fill the quicklist/loclist, but
"      function dict.foo() abort
"         logger.log("here I am");
"      endfunction
"   won't
" TODO: add verbose levels
function! lh#log#new(where, kind) abort
  let log = { 'winnr': bufwinnr('%'), 'kind': a:kind, 'where': a:where}

  " open loc/qf window {{{4
  function! s:open() abort dict
    try
      let buf = bufnr('%')
      exe 'silent! '.(self.where). ' '.(self.kind == 'loc' ? 'l' : 'c').'open'
    finally
      call lh#buffer#find(buf)
    endtry
  endfunction

  " add {{{4
  function! s:add_loc(msg) abort dict
    call setloclist(self.winnr, [a:msg], 'a')
  endfunction
  function! s:add_qf(msg) abort dict
    call setqflist([a:msg], 'a')
  endfunction

  " clear {{{4
  function! s:clear_loc() abort dict
    call setloclist(self.winnr, [])
  endfunction
  function! s:clear_qf() abort dict
    call setqflist([])
  endfunction

  " log {{{4
  function! s:log(msg) abort dict
    let data = { 'text': a:msg }
    try
      throw "dummy"
    catch /.*/
      let bt = lh#exception#callstack(v:throwpoint)
      if len(bt) > 1
        let data.filename = bt[1].script
        let data.lnum     = bt[1].pos
      endif
    endtry
    call self._add(data)
  endfunction

  " reset {{{4
  function! s:reset() dict abort
    call self.clear()
    call self.open()
    return self
  endfunction

  " register methods {{{4
  let log.open  = function('s:open')
  let log._add  = function('s:add_'.a:kind)
  let log.clear = function('s:clear_'.a:kind)
  let log.log   = function('s:log')
  let log.reset = function('s:reset')

  " open the window {{{4
  call log.reset()
  return log
endfunction

它使用我的另一个函数来解码调用堆栈。

好吧,如果你不能从 inside 自动加载函数中获取文件和行,你必须将那个 传递给 你的功能。

您的自动加载函数以某种方式调用,通过自定义映射、命令或在 :autocmd 事件中调用。从那里,您可以解析当前文件(expand('%') 和行号('line('.'))并将其传入。

但是为什么你需要那个?!对于正常的编辑任务,我无法想象为什么。如果您正在编写自定义 Vim 调试插件,好的,那可能会有用。但是通过 Vimscript 进行调试很困难(如您所知),调用堆栈未公开。最好坚持使用内置的 :debug:breakadd;到目前为止,我发现它们已经足够了。