4

In terminal, the command of the line of the input prompt can be cleared with <C-U>, and is recoverable with <C-Y>.

In vim, the colon command can be cleared with <C-U>, but it is not recoverable with <C-Y>. Is it possible to recover those erased commands?

1
  • 1
    I don't think it's possible natively (at least I didn't find anything relevant in the doc). Saving what you typed before using <c-u> can be done with :h CmdlineChanged and :h getcmdline() but modifying the command line with a mapping is the non trivial part.
    – statox
    Apr 26, 2021 at 19:31

3 Answers 3

3

Somewhat workaround if you have recent vim with <cmd> support:

cnoremap <C-u> <cmd>let g:CCtrlU = strpart(getcmdline(),0,getcmdpos()-1)<CR><C-u>
cnoremap <C-y> <C-r>=get(g:, "CCtrlU", "")<CR><cmd>let g:CCtrlU = ''<CR>

With <cmd> it is possible to run arbitrary vimscript without changing modes, so here with

  • <C-u> part of the cmdline is saved from beginning to the cursor pos, then original <C-u> deletes what it should.
  • <C-y> uses expression register = to output saved cmdline (g:CCtrlU is in safe form, checking existence with default value "") and then cleans up variable that holds saved cmdline.

PS, alternatively if you don't mind <C-u> to cut text into unnamed register, it could be simplified to:

cnoremap <C-u> <cmd>let @" = strpart(getcmdline(),0,getcmdpos()-1)<CR><C-u>
cnoremap <C-y> <C-r>"

PPS, and if you don't have <cmd> in your vim you could try this with <expr> and additional func:

func! CCtrlU() abort
    let @" = strpart(getcmdline(),0,getcmdpos()-1)
    return "\<C-u>"
endfunc
cnoremap <expr> <C-u> CCtrlU()
cnoremap <C-y> <C-r>"
1

I have an idea which is probably not ideal but could be in the right direction. The idea is to make use of the event :h CmdlineChanged which is triggered each time a character is changed in the command line.

On this event we get the content of the command line with :h getcmdline() and we use :h :execute to remap <C-y> to this string we got.

augroup CmdSave
    autocmd!
    autocmd CmdlineChanged * execute "cnoremap <C-y> " . getcmdline()
augroup END

As the autocommand is triggered also by <C-u> you can then press <C-y> to get the content back. The drawback is that if you press <C-y> at any moment other than right after <C-u> that will mess up your command line. Also it's very probable that some special characters will break the mapping (e.g. this substitution s/./^v/g with <CR> entered with Ctrl+v will end up in two commands)

EDIT Yeah so there are some side effects. I won't investigate the reason but my autocommand breaks the :Git commit feature of vim-figutive, so I also probably breaks other things. Once could try to wrap everything in a try...catch block but at this point it become really too hacky.

1

First, <c-u> doesn't actually clear the entire cmdline, only the part before the cursor. There is a note in :help c_CTRL-U about this. I'll assume from the question you want to clear the entire cmdline.

On the cmdline, another way to clear the entry is <c-c>. Unlike <c-u> this adds the current text to the history. I suggest the following map:

cnoremap <c-u> <c-c>:

Then, to recover the line after clearing simply press up.

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.