0

The two functions in the script below can be called independently via key mappings <leader>1 and <leader>2. In a perfect world, <leader>1 will always be called first. If the user forgets to do that, I want s:RunMe2nd() to be helpful and call s:RunMe1st(). However, it needs to use the user-defined command to display the legal values and get the one that will be passed to the function.

After some tinkering, I was able to do that with call feedkeys(":RunMe1st \<C-Z>", "t"), but also I would like the execution of s:RunMe2nd() to be blocked until :RunMe1st finishes. Is that possible, and if so, how would I do it?

To see what I'm talking about, source the script, and then type <leader>2. You will see the pop-up menu for the completion items, but underneath it you'll also see an error saying b:init is undefined. echomsg doesn't wait for feedkeys to finish. Source the file again, and type <leader>1 then <leader>2 to see how it works when following the rules.

unlet! b:init   " Re-source this file to reset.

command! -buffer -nargs=1 -complete=customlist,<SID>LegalValues RunMe1st :call <SID>RunMe1st("<args>")
setlocal wildcharm=<C-Z>   " Used to open completion menu.
nnoremap <leader>1 :RunMe1st<space><C-Z>
nnoremap <leader>2 :call <SID>RunMe2nd()<CR>

function! s:LegalValues(ArgLead, CmdLine, CursorPos)
    return ["hello", "world", "42"]
endfunction

function! s:RunMe1st(arg)
    let b:init = a:arg
endfunction

function! s:RunMe2nd()
    if !exists("b:init")
        echomsg "You didn't run RunMe1st first. Let me help you."

        " How do I get Vim to wait for the next statement to finish?
        call feedkeys(":RunMe1st \<C-Z>", "t")
    endif
    echomsg "All good. You chose ".b:init
endfunction
2
  • Have a look at vi.stackexchange.com/a/28977/10604
    – D. Ben Knoble
    Nov 10, 2022 at 21:37
  • That did it, @D. Ben Knoble. I wasn't aware that input() could use the same completion list as :command. That's a much better solution than using feedkeys().
    – Phil R
    Nov 14, 2022 at 14:52

1 Answer 1

1

Here is the solution I came up with after reading the link in @D. Ben Knoble's comment. The only thing I'm not terribly happy with is the expand('<SID>') workaround I used. It just seems like a bit of a hack, but it prevents the errors:

  • E120: Using <SID> not in a script context: s:LegalValues or
  • E120: Using <SID> not in a script context: <SID>LegalValues
unlet! b:init   " Re-source this file to reset.

command! -buffer -nargs=1 -complete=customlist,<SID>LegalValues RunMe1st :call <SID>RunMe1st("<args>")
setlocal wildcharm=<C-Z>   " Used to open completion menu.
nnoremap <leader>1 :RunMe1st<space><C-Z>
nnoremap <leader>2 :call <SID>RunMe2nd()<CR>

function! s:LegalValues(ArgLead, CmdLine, CursorPos)
    return ["hello", "world", "42"]
endfunction

function! s:RunMe1st(arg)
    let b:init = a:arg
endfunction

function! s:RunMe2nd()
    if !exists("b:init")
        echomsg "You didn't run RunMe1st first. Let me help you."
        let answer = input(':RunMe1st ',"\<C-Z>",'customlist,'.expand('<SID>').'LegalValues')
        call s:RunMe1st(answer)
    endif
    echomsg "All good. You chose ".b:init
endfunction
3
  • In RunMe2nd, why do you have execute? Would call s:RunMe1st(answer) not work? It looks like you wanted to quote the value of answer, would almost certainly fail if answer contained double-quotes.
    – D. Ben Knoble
    Nov 14, 2022 at 16:18
  • I suppose you could also execute 'RunMe1st' answer
    – D. Ben Knoble
    Nov 14, 2022 at 16:39
  • You're right. It does work. That must have been a remnant of my trial and error iterations. I'll edit to clear that up.
    – Phil R
    Nov 14, 2022 at 16:40

Your Answer

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

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