1

Suppose we do the following steps:

  1. Visually select something
  2. Type :some stuff
  3. press escape

when we do the last step, the command mode is exited but also we are left in normal mode - not visual mode. How do I make Vim go back to visual mode with the current selection when pressing escape?

1

You can go back to the previous selection with gv. So after you type esc you can type gv and the old selection is active again. (see gv)

To do this automatically is a little difficult. I did not find a full working solution right away. My basic idea was to map esc in command mode (see :cnoremap).

A plain

cnoremap <esc> <esc>gv

does not really work well as it is always used the pressing esc in the command line. But I think it should only activate the last selection when you entered the command line from visual mode.

Now I thought about an expression mapping (see :map-expression). But if I use mode() like this it obviously doesn't work as we are always in command mode:

cnoremap <expr> <esc> mode()=='v' ? "\<esc>gv" : "\<esc>"

But if we can save the information that we have been in visual mode when pressing : in the first place we can use it to do the right thing when pressing esc later. For this we need two functions and two mappings:

let s:was_visual = 0
function! EnterCommandLineFromVisualMode()
  let s:was_visual = 1
  return ':'
endfunction
function! HandleEscapeInCommandLine()
  if s:was_visual
    let s:was_visual = 0
    return "\<esc>gv"
  endif
  return "\<esc>"
endfunction
vnoremap <expr> : EnterCommandLineFromVisualMode()
cnoremap <expr> <esc> HandleEscapeInCommandLine()

Put this code into your vimrc or a new file in the plugin directory and it should work. The result might be inconsistent when you press CTRLC in the command line though as the s:was_visual variable will not get updated. You will need an extra cmap for this. Maybe there are other corner cases like this that I did not think of right now.

  • Man, that was a rather unexpectedly complex solution! Thank you for all your time and effort you put into this! – Dylanthepiguy Jul 8 '18 at 6:41
  • Hey sorry to bother you again, but I have noticed a bug with the code you wrote above. Suppose I type :something and then decide I don't want to run it, so press escape. But the command still runs, and logs an error saying Not an editor command: something. I have tried debugging this, and have determined that simply having the mapping calling the functions causes the bug to occur. What do you think about this? – Dylanthepiguy Jul 14 '18 at 8:47

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.