3

I'm trying to build a very simple plugin that allows for pressing a keymapping <Leader>, to call a function that prompts for a single keypress:

function! ControlKey()
    echo "Key → <C-Key> » "
    let l:key = getchar()
    let l:key = ((l:key >= 97 && l:key <= 122) ? l:key - 32 : l:key) - 64
    if l:key < 0 || l:key > 31
        echoerr "Invalid Key Conbination! "
    endif
    call feedkeys(nr2char(l:key), 't') | return ''
endfunction

cnoremap <Leader>, <C-r>=ControlKey()<Cr>
inoremap <Leader>, <C-r>=ControlKey()<Cr>
nnoremap <Leader>, :call ControlKey()<Cr>

The function takes this keypress (for example, a) and then uses feedkeys to send <C-a> (essentially behaving as a sticky control key). This works fine in normal mode, as well as in insert and command (by (ab)using the expression register to make the requisite function call). I run into issues when wanting to use this function in operator pending mode, because I can't see a way to make make a call to the function that won't clobber the operator (d,y, etc) expecting a range or motion. Is there a way to achieve this or am I trying to stretch vim too far?

1
  • 1
    I am not sure I understand what you mean with it will clobber the operator. Please provide an example for that. But note the current operator should be available in v:operator Sep 26, 2019 at 8:06

1 Answer 1

1

I'm not sure if you're having the issue with a mapping for an operator that takes a motion or a mapping for the motion itself...

Either way, you might want to try a different approach by using a :map <expr> together with a recursive mapping, which should be better than using feedkeys() as it's likely to produce less interferences with the following keypresses.

For example:

function! ControlKey()
    let l:key = getchar()
    let l:key = ((l:key >= 97 && l:key <= 122) ? l:key - 32 : l:key) - 64
    if l:key < 0 || l:key > 31
        echoerr "Invalid Key Combination! "
    endif
    return nr2char(l:key)
endfunction

nmap <expr> <Leader>, ControlKey()
omap <expr> <Leader>, ControlKey()

I believe something like this should work better. Try it and see if it solves the problem you're trying to solve.

am I trying to stretch vim too far?

In my opinion, yes. Vim mappings are great to act on Vim operations but not really that great to act on specific keystrokes.

You seem to be trying to replace the Ctrl key. I think it's better if you find a solution for that on your OS's keyboard driver instead. Then that would work regardless of context (Vim mappings depend on the specific context) and it would work not only in Vim, but in other applications as well.

3
  • "I'm not sure if you're having the issue with a mapping for an operator that takes a motion or a mapping for the motion itself...". Apologies for not clarifying, I meant the motion itself. I intend for keystokes like d<Leader>,e to delete to the end of the line, where <Leader>, takes e and effectively produces a <c-e> keypress.
    – myc3lium
    Sep 26, 2019 at 0:40
  • I think the omap <expr> ... will work for that... Try it out and see if it fixes the problem for you!
    – filbranden
    Sep 26, 2019 at 1:30
  • 1
    @myc3lium my only question is—de does what you need. Why d<leader>,e (or d<C-e>)? That surely wouldnt do what you actually want!
    – D. Ben Knoble
    Sep 26, 2019 at 2:14

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.