I'm trying to populate the quickfix list using an autoload function, i.e.:
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!
The problem I've run into is I can't figure out a way to get the filename and line number from the code that called the autoload function. Any suggestions?
Out of the box. This is not possible.
However, depending on the exact scenario, here are a few leads.
I've attempted to write a function that decodes the callstack from v:throwpoint
when an exception is caught. It's still experimental. See https://github.com/LucHermitte/lh-vim-lib/blob/master/autoload/lh/exception.vim
From my test unit framework, I know precisely which test-file/line is failing. To do so, I had to parse the UT file in order to inject the line number of the caller into the :Assert*
commands.
As you see, none of these solutions is very good. But there are none other right now. The callstack isn't available, except from v:throwpoint
in an exception context. The only other solution is to have callers inject their references (~__FILE__
+ ~__LINE__
) when calling. And the only way to automate this is to compile the caller script into another script that automatically injects the missing information.
By right now, understand there had been a proposal on vim-dev mailing list this last month in order to permit to have access to the call stack, but alas, only during debugging sessions: https://github.com/vim/vim/pull/433 If this is accepted, may be it could be extended later to offer a viml function that'll export this information.
EDIT: Your question inspired me to write a simplistic logging facility for vim:
" 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
Which use this other function of mine that decodes the callstack.