2

I want to map a keybinding to a command which includes <C-U> not for clearing the command line but for scrolling the page up. Executing a command like this in my vim session works totally fine:

:exe "normal \<C-U>"

But when I try to map something to the exact same command in my .vimrc, it doesn't work:

" My .vimrc
nnoremap <leader>u :exe "normal \<C-U>"<CR>

Now when I do <leader>u it leaves :" in my status bar which indicates <C-U> is clearing the line instead of scrolling the page. What is the problem?


Edit: I oversimplified the keybinding that I'm actually using to only point to what causes the problem and avoid confusion. I am using <C-U> in the context of a much more complicated keybinding but I need it to mean "scroll-up" instead of "clear the line." I'm using this binding nnoremap <leader>wu :<C-U>call win_execute(win_getid(winnr('#')), ":exe 'normal \<C-U>'")<CR> to scroll another window without switching directly to it. I already used it with <C-D> for scrolling down and it works perfectly fine but this one doesn't work because of the other meaning that <C-U> has in command mode.

0
2

Alright, so: I am having a remarkably hard time finding the section of the documentation that discusses how the right-hand-side of a mapping is interpreted (i.e., how the keycodes are read during :map and then later used upon execution). What I did discover with some trial-and-error, though, is this:

  1. nnoremap ... :execute "normal! <C-u>"<CR> has a literal <C-u> already in it, so that's why that fails. This happens even with the backslash, I think because nnoremap processes the <C-u> before execute/normal/double-quotes ever get to it.
  2. To work around that, we need to escape the < using <lt>. However, then we have the mapping running :execute "normal! <C-u>" which already doesn't work.
  3. To get around that, we need to put a backslash back into the string; for some reason, I couldn't make \\ work, even though that is supposed too—I may have needed to double (\\\\), but I didn't want to do that. So, I used <Bslash>.

The final mapping is

nnoremap ... :execute "normal! <Bslash><lt>C-u>"<CR>

Phew 😅

P.S. I was able to work through this by reading the output of :map {rhs} and realizing what characters had been pre-processed and what hadn't, as well as actually running the mapping to see what had happened.

P.P.S. I still don't think these shenanigans should be necessary for win_execute; it should be sufficient to pass the normal! command directly (with some pre-escaping if it's in a mapping). For example,

call win_execute(win_getid(winnr()), "normal! \<C-u>")

worked for me. You would probably need to use <Bslash> and <lt>C-u> in the mapping version.

2
  • Wow! The level of effort you put into it is just heroic. Even though it's advised to not send comments to thank someone, I found it unfair not to! So thanks so much. Jul 25 '20 at 20:55
  • @SaeedAhadian helping you is thanks enough; and the rep helps :P youre very welcome. I’m just glad for this community in so many ways, and I want to see it thrive. I think I’m going to clean up pur comment convo and move some info into your question for posterity.
    – D. Ben Knoble
    Jul 25 '20 at 20:57

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.