I have a problem: I need to pass « any » caller-session trace into a user command… Was trying with:

command WantToKnowWhosCalling call Impl("\<SID>",
    \ expand("<SID>"), eval('expand("<SID>")'),
    \ expand('<sfile>'))

all methods were failing — <SID> because it's fixed-straight (it's almost like if Bram was brushing some potential security issues…) to point to the «command-defining» session. <sfile> was ·almost· there, however… It returns the script-file path (a very good ID…) only at the time of the :source, later, when expanded from the script-defined functions, it's <stack>

Has someone any more ideas? I need to: « identify the command-caller », basically… It can be a random-ID, but stable-assigned and unique. The goal is to know that it's a « client script-A returning », i.e.: recognized and associated with its previous calls to the custom :Command.

  • 1
    Not sure I understand correctly. Are you looking for expand('<SID>') (needs patch 8.2.1347)? – Christian Brabandt Sep 9 '20 at 12:24
  • As I IMHO clearly described, expand('<SID>') on the RHS of a :command-def returns the <SID> of the command's owning script, not of the script where the user-command is called. – Mooncer Sep 9 '20 at 12:41

By throwing an exception you should be able to obtain the full (functions) callstack. I've described part the process in a section of the documentation of my library plugin along with the related functions I provide to decode v:throwpoint. IIRC, there is another Q/A where I delved more in details about how its works... Found it! And also here.

There are a few limitations: it only returns calling functions. If your function is called only through commands or mappings, you won't see anything useful. It's also extremely slow: do not abuse of the feature.

EDIT: it seems that v:throwpoint and Vim 8.2.1297 expand('<stack>') return a string (almost) in the same format. Split it at ... Then each element will contain a function name (and may a line number). From there the best way to know where it's defined is with verbose function {funcname}. The difficulty is that the message will be localized, and sometimes anonymous functions have already been garbage collected (or why I don't use them any more).

My library already takes care of all these issues. I'll eventually upgrade it to use expand('<stack>') whenever it's possible as I expect better performances.

  • 2
    We can get the callstack with expand('<stack>') since 8.2.1297. – user938271 Sep 9 '20 at 13:26
  • @user938271 Thanks. This is good to know. As github.com/vim/vim/issues/1125 hasn't been updated I've missed the information. I see we miss a little bit of information: my API returns the line where callstack request happens, with a little wrapper it should be fine! – Luc Hermitte Sep 9 '20 at 13:42
  • Yes I've already noticed the usefulness of <stack>, however in different way — the function call stack isn't a good ID as it fluctuates depending on the call tree… However if there is a script-local s:otherScriptFunction, then the stack will leak the other's script <SID>, because it'll be right there in the function-name as e.g.: <SNR>112_otherScriptFunction. – Mooncer Sep 9 '20 at 13:46
  • @Mooncer In lh-vim-lib I've implemented a way to convert function -> scriptname as one of the prime use case of my lh#exception#... functions is to fill the quickfix window. – Luc Hermitte Sep 9 '20 at 13:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.