1

Is it possible to do this:

function Foo(func_ref) abort
  nnoremap <buffer> <cr> :find_a_way_to_call_func_ref
endfunction

function s:callback() abort
  echo "123"
endfunction

command Test call Foo(function('s:callback'))

To be clear, :h Funcref is not String, it's type is v:t_func.

6
  • 1
    I like the question! But you might still want to clarify it. What kind of func_ref are you passing? A string with a function name? Or a lambda? I can see how the latter is a lot more challenging...
    – filbranden
    Apr 17, 2020 at 11:43
  • @filbranden v:t_func
    – dedowsdi
    Apr 17, 2020 at 11:56
  • 1
    Yes, in fact :help Funcref talks more about that and mentions lambdas explicitly... What I'm saying is that you might want to clarify your question with an example call of Foo (perhaps with a lambda?) to make it absolutely clear what you're trying to accomplish... As it stands, your question is likely to attract incorrect answers (such as the one with execute), which might not be the case if you had an example call that would make it clear that wouldn't have worked.
    – filbranden
    Apr 17, 2020 at 12:24
  • 1
    @filbranden I thought it should be clear as I use capital Funcref, but you are right, it's still confusing, I clarified it in the update.
    – dedowsdi
    Apr 17, 2020 at 12:32
  • Awesome! Looks pretty clear now! (Unfortunately I don't know that this is actually possible to do...)
    – filbranden
    Apr 17, 2020 at 12:43

3 Answers 3

3

It's really doable with execute... and call()

function Foo(func_ref) abort
    execute printf('nnoremap <buffer><cr> :call call(%s, [])<CR>',
        \ string(get(a:func_ref, 'name')))
 endfunction
7
  • Interesting, when closures were added to vim?
    – Maxim Kim
    Apr 17, 2020 at 17:49
  • 1
    @MaximKim Around the time the lambdas were added (version 7.4.xxxx).
    – Matt
    Apr 17, 2020 at 18:07
  • Wow, don't know how did I miss it! Thx!
    – Maxim Kim
    Apr 17, 2020 at 18:09
  • @dedowsdi Ah, sorry. So you need execute with proper quotes...
    – Matt
    Apr 18, 2020 at 5:11
  • 1
    @dedowsdi Yes, but you must ensure that lambda won't be dropped by Vim by that moment (i.e. storing Funcref keeps a referred function/lambda alive, but storing just a name string, obviously, does not).
    – Matt
    Apr 18, 2020 at 7:05
2

I don't think it is possible to directly call this funcref from within mapping -- by the time you press mapped key funcref is already disposed/freed/unavailable.

You can try to persist funcref though (either in global or script local dict):

let g:my_funcs={}

function! Foo(func_ref) abort
    let g:my_funcs.f = a:func_ref
    nnoremap <buffer> <cr> :call g:my_funcs.f()<CR>
endfunction

function! Callback() abort
  echom "123"
endfunction

command! Test call Foo(function('Callback'))

enter image description here

It is not necessary to use dictionary, you can have regular global var I think. But for the dictionary you can come up with some clever things, like having array of functions, caching or whatever else.

5
  • 1
    Thanks, this should work. Will accept if no other better answer in a few days.
    – dedowsdi
    Apr 17, 2020 at 13:46
  • 1
    Similar to my approach github.com/benknoble/vim-simpl
    – D. Ben Knoble
    Apr 17, 2020 at 13:54
  • 1
    @D.BenKnoble simpl#register? indeed!
    – Maxim Kim
    Apr 17, 2020 at 14:07
  • Confirmed that this works with a function(...) including arguments, with a lambda and with a funcref() for a function that has been overwritten. Good job!
    – filbranden
    Apr 17, 2020 at 14:30
  • @dedowsdi glad I could help you
    – Maxim Kim
    Apr 17, 2020 at 14:55
0

Sure, you want to use the execute command, which acts like an eval:

function Foo(func_ref) abort
  exe"nnoremap <buffer> <cr> :".func_ref."()<cr>"
endfunction
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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