The topic is about obtaining the current function call stack. Its main applications relate to plugin maintenance: debugging, unit testing, DbC, logging ...
While Vim knows internally its current call stack, this information wasn't
directly available to us up until Vim 8.2.1297 which introduces
expand(<stack>)
.
Unfortunatelly the result is in text format and it still needs parsing, but at
least this string isn't localized.
In a ideal world we would have been able to obtain real callstack object...
Up until Vim 8.2.1297, we had to trick vim into giving us the information.
The idea was to throw an exception and to decode
v:throwpoint
. Note
however that this must not be abused as it could cripple down your plugin
performances. Fortunatelly v:throwpoint
and expand(<stack>)
are almost in
the same format.
Parses throwpoint
, in the current locale, to extract the function call stack.
This function is compatible with
v:throwpoint
and
expand(<stack>)
.
Returns a list of:
"script"
: filename of the vim script where the function is defined"pos"
: absolute line number in this script file"fname"
: function name"fstart"
: line where the function is defined in the script"offset"
: offset, from the start of the function, of the line where the exception was thrown
In case the script file could not be obtained, "script"
will value "???"
,
"fstart"
will value 0, and "pos"
will value "offset"
.
Example:
function! s:some_func() abort
try
throw "dummy"
catch /.*/
let callstack = lh#exception#callstack(v:throwpoint)
endtry
do_something_with(callstack)
endfunction
" or
function! s:some_func() abort
let callstack = lh#exception#callstack(expand('<stack>'))
do_something_with(callstack)
endfunction
Note: In a *nix world, or precisely when bash
is detected, the call stack
is correctly analysed whatever the current locale is. On a pure windows system,
you'd need to stay in a C locale to make sure v:throwpoint
could be correctly
decoded.
Given a throwpoint (or expand(<stack>)
), creates an object
containing call stack information.
The object is made of:
"callstack"
: list returned bylh#exception#callstack()
."as_qf()"
: method that converts the call stack object into a list accepted bysetqflist()
.
Helper function to obtain the call stack at the current call-site. It takes
care of returning expand('<stack>')
if possible, or of throwing the dummy
exception otherwise. You can see this function as the first main entry point.
It returns the object returned by lh#exception#decode()
.
Notes:
- As of vim 8.0-314, the size of the call stack is always of 1 when called from a "script. See Vim issue#1480.
- It clears the current function level (i.e. the context of
lh#exception#get_callstack()
function).
Returns the call stack as a list compatible with
setqflist()
. You
can see this function as the second main entry point.
Internally it returns
lh#exception#get_callstack().as_qf()
filtered
(by filter()
)
with filter
parameter.
The typical use case for this function is from plugins that wish to display the call stack. This way, we can ignore the context injected by these plugins to display only pertinent information.
This function has been inspired by https://github.com/tweekmonster/exception.vim It analyses last error message reported by Vim, the call stack is expanded into as many entries as required, and the result is displayed in the quickfix window.
A neat way to use it consists in defining the following command (in your
.vimrc
for instance) -- at this time I don't provide the command
automatically in a plugin script:
" .vimrc
" Parameter: number of errors to decode, default: "1"
command! -nargs=? WTF call lh#exception#say_what(<q-args>)
The differences (with tweekmonster/exception.vim
) are the following:
- It supports localized messages
- It supports autoloaded functions, even when
#
isn't in'isk'
(that may happen depending on the filetype of the current buffer) - It uses a framework that have been here for little time for other topics (logging, unit testing)
- It has as few loops as possible -- 1. I hate debugging them, 2. This permits to run faster.
In the end of DbC framework demo, you'll see a live application of
lh#exception#say_what()
. You'll also see applications of the other call stack
related functions to display the call stack on failed assertions.