21

I am a happy VIM user, although I admit I'm quite far from being fluent. I found this nice post: Vim clear last search highlighting and I thought I'd become a better person if I didn't have to hammer away a random character sequence every time I did a search. Now, I'm also using the vimrc config from here:

http://amix.dk/vim/vimrc.html

and the problem I have is that when I add the line nnoremap <esc> :noh<return><esc> to it (it doesn't seem to make a difference where I put it) I get awkward behaviour when I use arrows in command mode, namely letters from A to D appear in a newline and I get switched to insert mode.

There has to be some mapping conflict but for the life of me I can't figure out where it is.

EDIT: As it follows from the answers it turns out the Ultimate vimrc part is not relevant, the mentioned nnoremap command will cause altered arrow behaviour even if it's the only vimrc entry. Changing title to a more informative one.

PS. I know I shouldn't use arrows, hopefully I'll get there one day.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Tomek Kaftal
  • 528
  • 5
  • 15

5 Answers5

20

The mapping

nnoremap <esc> :noh<return><esc>

will conflict with so called "grey keys" and I believe that it should be used either in GVim only or in terminal Vim by someone who does not use special keys like arrows.

From what I know (and guess) how Vim processes keys, I would say that it's impossible to do anything with this. For Vim to recognize special key all its components should go in a row, so when you press Arrow Left Vim gets the following sequence of codes:

<esc> [ D

But after your mapping Arrow Left becomes:

: n o h l <cr> <esc>

[ D

Vim sees two separate sequences and treats <esc> as a single press of Escape key, thus next two codes of Left Arrow key lose their special meaning.

So I suggest you to map :noh to some other key sequence (e.g. to one starting with <leader>, see :help mapleader; I don't recommend you to use F-keys, using them is as bad as using of arrow keys).

Nate Cook
  • 8,395
  • 5
  • 46
  • 37
xaizek
  • 5,098
  • 1
  • 34
  • 60
18

The cause had been explained well, but solution was not mentioned. However there is a straight one.

If you’ll tell to Vim explicitly that there are key sequences starting from <esc>[

:nnoremap <silent><esc> :noh<CR>
:nnoremap <esc>[ <esc>[

than when single <esc> will be pressed Vim will wait for a second (or different time, see :h 'timeoutlen') or for a next key (second <esc> for example) and only then replace it with :noh<CR>.

Dmitry Alexandrov
  • 1,693
  • 12
  • 14
  • 3
    `:nnoremap ^[ ^[` – David Unric Apr 07 '15 at 08:41
  • Can those two lines be included in the `.vimrc` file, and if so, literally as expressed or do they need modification? – Ari Feb 19 '17 at 03:51
  • 5
    Half year later... @fanuch or anyone else wondering the same: Yes, those two lines can certainly go in your .vimrc. Just **leave out the starting colon**, and make sure you don't put any comment to the right of the mappings (above or below would be a good idea, to remind you why you have them or what they do). Half year later, oh well – fede s. Apr 09 '17 at 00:24
  • This is a genius approach to this problem and other related ones. – Spidey Aug 01 '18 at 02:12
  • Unfortunately, it didn't work here on Vim on Git Bash (MSYS2, on Windows 10). – Spidey Aug 01 '18 at 02:20
14

This solution preserves the ESC mapping to :nohlsearch.

The comment on this answer explaining why this is happening tells us that the root cause is the TermResponse behavior of vim. This can be compensated for by wrapping the mapping in an autocommand for the TermResponse event.

This ensures that the binding doesn't happen until after the term response is set, which prevents Esc from also sending a string like ]>1;3201;0c to vim.

Change your line in vimrc to this:

augroup no_highlight
    autocmd TermResponse * nnoremap <esc> :noh<return><esc>
augroup END

The augroup commands are not strictly necessary, but they prevent multiple mappings when you reload your vimrc without quitting vim.

EDIT: If you also use a graphical vim like Gvim or Macvim, the TermResponse event will not fire. Assuming you use a single vimrc, you'll need some additional code like

if has('gui_running')
  nnoremap <silent> <esc> :nohlsearch<return><esc>
else
  " code from above
  augroup no_highlight
    autocmd TermResponse * nnoremap <esc> :noh<return><esc>
  augroup END

end
Community
  • 1
  • 1
Eric Hu
  • 18,048
  • 9
  • 51
  • 67
  • In my case simply commenting out this line: nnoremap :noh worked for me. It was added by copy/pasting code written by someone else. Lesson learned. +1 for getting me on the right track. – Jason Elwood Dec 31 '15 at 00:34
  • 1
    I like this idea but it didn't work for me. Both of the versions here (the one that's just for terminal vim, and the one that has the if/else to work for GUI and terminal) leave me with broken arrow keys when running in a terminal. My terminal vim is VIM 7.3 provided by Apple as part of Mac OS X 10.11 "El Capitan"; maybe it depends on features in a later version of VIM? – jbyler Sep 28 '17 at 18:11
  • [The TermResponse method doesn't work well for me, either](https://vi.stackexchange.com/questions/2614/why-does-this-esc-normal-mode-mapping-affect-startup#comment41245_15572). When Vim starts up, it's left in command-line mode, with the command line containing the following contents: :83/94/95^G (that's a literal CTRL-G at the end). – Rich Feb 04 '20 at 09:57
3

I have had good luck with this

if $TERM =~ 'xterm'
  set noek
endif
nnoremap <silent> <esc> <esc>:noh<cr>

The disadvantage is that function keys can not be used in insert mode.

:h ek
Peter Rincker
  • 43,539
  • 9
  • 74
  • 101
  • Unfortunately it does the same thing for me :( – Tomek Kaftal Aug 13 '12 at 19:26
  • try it w/o the if statement. so just `set noek` and `nnoremap :noh` – Peter Rincker Aug 13 '12 at 19:26
  • Sorry. This is what works for me and my terminal. I guess you have different keycodes being sent. Do you know what your $TERM is? – Peter Rincker Aug 13 '12 at 19:32
  • @PeterRincker: according to documentation (and my tests) this option works for insert mode only. Are you sure it changes anything for you? – xaizek Aug 13 '12 at 19:34
  • Sorry this doesn't work for you. @xaizek: works well for the machines i use it for. If I take out `set noek` any time I open up vim in the terminal it will start with some initial commands. I know it is at least `2c` b/c I have `set showcmd`. – Peter Rincker Aug 13 '12 at 20:51
3

Problem is that when you press an arrow terminal emits something like <Esc>OA. Vim part that supports terminal seems to use the same mapping mechanism to do the job as you are using: while nmap <Esc>OA will tell you nothing, call feedkeys("\eOA") will move one line up and call feedkeys("\eOA", 'n') will add letter A beyond current line. With your mapping being noremappable you forbid vim to use <Esc> as a part of the key. The problem is that you need remappable mapping here, but can have remappable mapping without it being recursive as well only if it starts with {lhs}, but <Esc>:noh<CR>OA is not going to work. I thought the following code will (it uses <expr> and function with side effect to make <Esc> be the first character of the actual {rhs} and still launch :noh), but in fact it does not:

function s:NoHlSearch()
    nohlsearch
    return "\e"
endfunction
nmap <expr> <Esc> <SID>NoHlSearch()

. I have no other idea how to solve the problem of having non-recursive remappable mapping which includes {lhs} but not at the start.

ZyX
  • 52,536
  • 7
  • 114
  • 135