在 vimrc 中映射 <esc> 会导致奇怪的箭头行为

Posted

技术标签:

【中文标题】在 vimrc 中映射 <esc> 会导致奇怪的箭头行为【英文标题】:Mapping <esc> in vimrc causes bizarre arrow behaviour 【发布时间】:2012-08-10 01:34:53 【问题描述】:

我是一个快乐的 VIM 用户,尽管我承认我离流利还很远。我发现了这个不错的帖子: Vim clear last search highlighting 我想如果我不必每次搜索时都敲出随机字符序列,我会成为一个更好的人。现在,我也在使用这里的 vimrc 配置:

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

我遇到的问题是,当我将行 nnoremap &lt;esc&gt; :noh&lt;return&gt;&lt;esc&gt; 添加到它时(它似乎在我放置的地方没有什么区别)当我在命令模式下使用箭头时,我会出现尴尬的行为,即来自的字母A 到 D 出现在换行符中,我切换到插入模式。

必须有一些映射冲突,但对于我的生活,我无法弄清楚它在哪里。

编辑:从答案中可以看出 Ultimate vimrc 部分不相关,即使它是唯一的 vimrc 条目,提到的 nnoremap 命令也会导致箭头行为改变。将标题更改为内容更丰富的标题。

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

【问题讨论】:

我已经看到了您在使用数字键盘时所描述的内容,但从未看到箭头光标键。 如果您真的想停止使用箭头键,只需重新映射它们以不执行任何操作 (example)。 我愿意,但这种方法对我来说仍然有点过于激进:) 【参考方案1】:

映射

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

会与所谓的“灰色键”冲突,我认为它应该只在 GVim 中使用,或者由不使用箭头等特殊键的人在终端 Vim 中使用。

据我所知(和猜测)Vim 是如何处理键的,我想说这是不可能的。要让 Vim 识别特殊键,它的所有组件都应该排成一行,所以当你按 左箭头 时,Vim 会得到以下代码序列:

[ D

但是在你的映射 Arrow Left 之后变成:

: n o h l

[ D

Vim 看到两个单独的序列并将 视为单次按下 Escape 键,因此接下来的两个代码是 Left Arrow 键失去了它们的特殊意义。

所以我建议您将:noh 映射到其他一些键序列(例如,映射到以&lt;leader&gt; 开头的一个,参见:help mapleader;我不建议您使用F 键,使用它们和使用它们一样糟糕使用箭头键)。

【讨论】:

很高兴知道它是如何工作的,即使我不得不接受另一种解决方案。 &lt;c-l&gt; 是一个常见的映射。 nnoremap &lt;c-l&gt; &lt;c-l&gt;:noh&lt;cr&gt; 我一直是map &lt;silent&gt; &lt;Leader&gt;&lt;Leader&gt; :nohlsearch&lt;cr&gt; 的粉丝,但当然这都是偏好。 mouse=a也有类似问题【参考方案2】:

此解决方案保留 ESC:nohlsearch 的映射。

this answer explaining why this is happening 上的评论告诉我们,根本原因是 vim 的 TermResponse 行为。这可以通过将映射包装在 TermResponse 事件的自动命令中来补偿。

这可确保在设置术语响应之后之后才发生绑定,从而防止 Esc 也将类似]&gt;1;3201;0c 的字符串发送到vim。

将 vimrc 中的行改为:

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

augroup 命令不是绝对必要的,但是当你重新加载你的 vimrc 而不退出 vim 时,它们可以防止多重映射。

编辑:如果您还使用 Gvim 或 Macvim 等图形 vim,则不会触发 TermResponse 事件。假设您使用单个 vimrc,您将需要一些额外的代码,例如

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

【讨论】:

就我而言,只需注释掉这一行: nnoremap :noh 对我有用。它是通过复制/粘贴其他人编写的代码添加的。学过的知识。 +1 让我走上正轨。 我喜欢这个想法,但它对我不起作用。这里的两个版本(仅用于终端 vim 的版本,以及具有 if/else 可用于 GUI 和终端的版本)在终端中运行时让我的箭头键损坏。我的终端 vim 是 Apple 提供的 VIM 7.3,作为 Mac OS X 10.11 "El Capitan" 的一部分;也许它取决于更高版本的 VIM 中的功能? The TermResponse method doesn't work well for me, either。当 Vim 启动时,它处于命令行模式,命令行包含以下内容: :83/94/95^G(最后是文字 CTRL-G)。【参考方案3】:

原因已经解释得很好,但没有提到解决方案。但是有一个直的。

如果你明确告诉 Vim 有从 &lt;esc&gt;[ 开始的键序列

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

当单个 &lt;esc&gt; 被按下时,Vim 将等待一秒钟(或不同的时间,参见 :h 'timeoutlen')或下一个键(例如第二个 &lt;esc&gt;),然后才用 :noh&lt;CR&gt; 替换它.

【讨论】:

:nnoremap &lt;esc&gt;^[ &lt;esc&gt;^[ 这两行是否可以包含在.vimrc 文件中,如果可以,按字面意思表示还是需要修改? 半年后...@fanuch 或任何其他想知道的人:是的,这两行当然可以放在你的 .vimrc 中。只需省略起始冒号,并确保您没有在映射的右侧添加任何注释(在上面或下面是一个好主意,以提醒您为什么拥有它们或它们是什么做)。半年后,哦,好吧 这是解决这个问题和其他相关问题的天才方法。 不幸的是,它在 Vim on Git Bash(MSYS2,Windows 10)上不起作用。【参考方案4】:

问题是,当您按下箭头时,终端会发出类似&lt;Esc&gt;OA 的信息。支持终端的 Vim 部分似乎使用与您使用的相同的映射机制来完成工作:nmap &lt;Esc&gt;OA 不会告诉您任何内容,call feedkeys("\eOA") 将向上移动一行,call feedkeys("\eOA", 'n') 将在当前行之外添加字母 A。由于您的映射不可映射,因此您禁止 vim 使用 &lt;Esc&gt; 作为密钥的一部分。问题是您在这里需要可重新映射的映射,但只有在以lhs 开头的情况下才可以在不递归的情况下进行可重新映射的映射,但&lt;Esc&gt;:noh&lt;CR&gt;OA 不起作用。我认为下面的代码会(它使用&lt;expr&gt; 并具有副作用使&lt;Esc&gt; 成为实际rhs 的第一个字符并仍然启动:noh),但实际上它没有:

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

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

【讨论】:

【参考方案5】:

我运气不错

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

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

:h ek

【讨论】:

不幸的是它对我做了同样的事情:( 尝试不使用 if 语句。所以只需set noeknnoremap &lt;silent&gt; &lt;esc&gt; &lt;esc&gt;:noh&lt;cr&gt; 对不起。这对我和我的终端都有效。我猜你有不同的键码被发送。你知道你的 $TERM 是什么吗? @PeterRincker:根据文档(和我的测试),此选项仅适用于插入模式。你确定它对你有什么改变吗? 抱歉,这对您不起作用。 @xaizek:适用于我使用它的机器。如果我每次在终端中打开 vim 时取出 set noek,它将以一些初始命令开始。我知道至少是2c b/c 我有set showcmd

以上是关于在 vimrc 中映射 <esc> 会导致奇怪的箭头行为的主要内容,如果未能解决你的问题,请参考以下文章

vimrc

_vimrc 的基本配置

在 Vim 中注释 c++ 代码

vim自定义设置-配置文件

vimrc中使用Alt的任何映射都不起作用

ubuntu vim配置文件怎么保存退出?