关于vim:Mapping< esc>


Mapping <esc> in vimrc causes bizarre arrow behaviour

我是一个快乐的vim用户,尽管我承认我还远没有流利。我找到了这篇好文章:Vim清除了上次搜索的突出显示,我想如果我不必每次搜索都删除一个随机字符序列,我会成为一个更好的人。现在,我还在这里使用vimrc配置:

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

我的问题是,当我把行nnoremap :noh加到它上面时(我把它放在哪里似乎没有什么区别),当我在命令模式下使用箭头时,我会遇到尴尬的行为,也就是从a到d的字母会出现在新行中,而我会切换到插入模式。

必须要有一些映射冲突,但对于我的生活,我不知道它在哪里。

编辑:从答案中可以看出,最终的VIMRC部分是不相关的,所提到的nnoremap命令将导致改变的箭头行为,即使它是唯一的VIMRC条目。将标题改为更具信息性的标题。

我知道我不应该用箭,希望有一天我能到那里。


映射

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

将与所谓的"灰色钥匙"冲突,我相信它应该被不使用特殊钥匙(如箭头)的人仅用于GVIM或终端VIM。

根据我对Vim如何处理键的了解(和猜测),我会说这是不可能的。为了让VIM识别特殊键,它的所有组件都应该排成一行,所以当您按下ARROW LEFT时,VIM得到以下代码序列:

[ d

但在映射arrow left之后:

: n o habbd l

[ D

VIM看到两个独立的序列,并将视为一次按escapebkbd键,因此接下来的两个left arrow键代码失去了它们的特殊含义。

因此,我建议您将:noh映射到其他一些键序列(例如,从开始的键序列,请参见:help mapleader;我不建议您使用f键,使用它们与使用箭头键一样糟糕)。


此解决方案保留到:nohlsearchesc映射。

对这个答案的评论解释了为什么会发生这种情况,告诉我们根本原因是vim的term响应行为。这可以通过在TermResponse事件的自动命令中包装映射来补偿。

这样可以确保在设置术语响应之前不会发生绑定,从而防止esc也向vim发送像]>1;3201;0c这样的字符串。

将VIMRC中的行更改为:

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

augroup命令不是严格必需的,但是当您在不退出vim的情况下重新加载vimrc时,它们会阻止多个映射。

编辑:如果您还使用图形化VIM(如GVIM或MacVim),则不会触发TermResponse事件。假设您使用单个VIMRC,您将需要一些额外的代码,比如

1
2
3
4
5
6
7
8
9
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


原因解释得很好,但没有提到解决办法。但是有一条直线。

如果你明确地告诉Vim有一些关键序列从[开始

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

当按下单个时,VIM将等待一秒钟(或不同的时间,见:h 'timeoutlen'或下一个键(例如第二个键),然后用:noh替换它。


问题是,当按下箭头终端时,会发出类似于OA的信号。支持终端的VIM部分似乎和您使用的映射机制一样:虽然nmap OA不会告诉您什么,但call feedkeys("\eOA")会向上移动一行,call feedkeys("\eOA", 'n')会在当前行之外添加字母A。由于您的映射是不可应用的,所以您禁止VIM将用作键的一部分。问题是,您需要在这里进行可重映射,但只有当它以{lhs}开头,而:nohOA不起作用时,它才能在不递归的情况下进行可重映射。我认为下面的代码(它使用和带有副作用的函数使成为实际{rhs}的第一个字符,并且仍然启动:noh,但实际上它没有:

1
2
3
4
5
function s:NoHlSearch()
    nohlsearch
    return"\e"
endfunction
nmap <expr> <Esc> <SID>NoHlSearch()

. 我不知道如何解决包含{lhs}但一开始没有的非递归可重映射的问题。


我在这方面运气很好

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

缺点是功能键不能在插入模式下使用。

1
:h ek