为什么此<Esc>普通模式映射会影响启动?


13

我在使用的普通模式映射时遇到一个奇怪的问题Esc

如果escmapvimrc使用内容创建文件:

set nocompatible
set showcmd " Doesn't affect the problem: just makes it easier to see
nnoremap <Esc> :noh<CR><esc>

然后使用以下vimrc启动vim:

vim --noplugin -u escmapvimrc

然后,vim将以操作员待定模式启动,c命令等待进一步输入,显示一个空文件,并且命令行显示:noh

如果您删除该nnoremap行,那么问题就消失了。

如果您调试并逐步完成所有操作,则会得到以下输出:

Entering Debug mode.  Type "cont" to continue.
/[...]/escmapvimrc
line 1: set nocompatible
>s
/[...]/escmapvimrc
line 2: set showcmd " Doesn't affect the problem: just makes it easier to see
>s
/[...]/escmapvimrc
line 3: nnoremap <Esc> :noh<CR><esc>
>s
/[...]/escmapvimrc
line 4: End of sourced file
>s
Press ENTER or type command to continue

按回车后,将显示Vim启动屏幕,其下方:

Entering Debug mode.  Type "cont" to continue.
cmd: noh
>s

然后,Vim启动屏幕消失,并且您处于操作员待定模式,如上所述。

这是怎么回事?

编辑:行为如Vim 7.3中所述。在Vim 7.4.52中,nmap当启动不带文件的Vim时,Vim会以Replace模式启动。(但是,如果Vim 7.4.52是文件启动的,则它也将在执行c命令的情况下启动。)不管哪种方式,删除nmap时问题都会消失。


我确实用vim重现了此内容,但是命令行没有向:noh我显示。用gvim进行相同操作不会显示此行为。
PhilippFrank

1
清除搜索突出显示的常见映射是:nnoremap <c-l> :noh<cr><c-l>
Peter Rincker

附带说明,您也可以使用它/alksdjflaskj来清除搜索突出显示,这也非常快。
Shahbaz

Answers:


11

Vim在启动期间发送一些特殊的终端代码(通常包含<esc>密钥)来确定几件事(颜色,bs等)。如果映射了<esc>该代码,很可能会使返回代码的解析器感到困惑,并且可能会发生奇怪的事情。

因此,只有在一切都正确设置后(例如通过VimEnter自动命令),才可以使用上面的地图。


1
好吧,只要'term'设置了选项,它们就会发送出去。这通常仅在启动期间进行,但是在某些情况下可能会在运行时进行设置。
jamessan 2015年

在这种特定情况下,这似乎是由may_req_ambiguous_char_width()引起的,该方法仅在启动时调用
Christian Brabandt

我打算完全尝试这个(这就是为什么我不接受其他答案的原因)。好的,但是确认它应该可以工作。
Rich


你开玩笑的对吧?用于通信的转义符应与Escape键映射分开。
shawnhcorey

11

Linux终端使用ANSI转义序列(即,以开头的字符串<Esc>)将特殊键发送到Vim,并作为通信协议的一部分,应用程序通过该协议来查询其功能。您的映射会对此产生干扰,从而导致这些“奇怪”的行为。

因此,请勿映射<Esc>。使用另一个密钥。这个问题在GVIM中不太明显,但是我也不建议在那儿使用。


不幸的是,几乎从我开始使用Vim以来,我就已经有了这种映射,所以到现在为止,它已经很好地烧入了我的肌肉记忆中。不过,感谢您的解释。
丰富

为了后人的缘故,我应该补充一点,所描述的问题是我所知道的唯一问题,肯定是由该映射引起的,也是我可以回忆起的Vim唯一奇怪的未解决的问题。
丰富

1
@Rich习惯使用类似东西会有多困难<Esc><Esc>
Random832

@ Random832这是一个有趣的想法。
丰富

1
所有xterm程序都会这样做,因为它们模拟VT-100终端。它与Linux无关。基于BSD而非Linux的iOS也将具有模拟VT-100的xterm。
shawnhcorey

1

尝试这个:

augroup escape_mapping
  autocmd TermResponse * nnoremap <Esc> :noh<CR><esc>
augroup end

cf /programming//a/16027716/400545


这对我来说不是很好。之后,用此替换我的escapemapvimrc文件中的映射,当Vim启动完成时,我进入命令行模式,命令行包含以下内容:(末尾:83/94/95^G是一个文字CTRL-G)。这:help似乎表明这可能不是设置映射的最佳时间:Note that this event may be triggered halfway executing another event, especially if file I/O, a shell command or anything else that takes time is involved.
Rich

1

我尝试设置自动命令以在以后的启动中设置映射,但是问题仍然出现。*

我最终创建了一个自动命令,该命令在我第一次进入插入模式时发生。这显然不是一个完美的解决方案,但是对我来说,它在大多数情况下都会起作用,这似乎是我能做的最好的事情:

更新:使用下面较长的版本几年没有问题之后,我认为它可能经过了稍微的过度设计,从那时起,我使用了这个简单得多的版本,每次进入插入模式时,它都会重置映射:

augroup escape_mapping
  autocmd!
  autocmd InsertEnter * call s:setupEscapeMap()
augroup END

function! s:setupEscapeMap()
  nnoremap <Esc> :noh<CR><Esc>
endfunction

不必在每次进入插入模式时都重置映射,但是这对于Vim这样做也没有任何危害。

原始版本

if !exists('g:escape_mapped')  " Only need to set the mapping up once.
  augroup escape_mapping
    autocmd!
    " Create the autocommand, to fire when Insert mode is entered
    autocmd InsertEnter * call s:setupEscapeMap()
  augroup END
endif

function! s:setupEscapeMap()
  " Actually create the mapping
  nnoremap <Esc> :noh<CR><Esc> 

  " Now the map exists, so we won't ever need the autocommand again.
  let g:escape_mapped = 1

  " Tidy up the autocommand and group
  autocmd! escape_mapping InsertEnter *
  augroup! escape_mapping
endfunction

*我试图将其连接到各种事件:VimEnterBufReadPostBufWinEnter,甚至CursorMoved(!),但这些似乎都火得太早。


您是否尝试过TermResponse自动命令?
克里斯蒂安·布拉班德

@ChristianBrabandt我现在有。它不为我工作得很好 :(。
丰富的

我最近才了解到,并不是vim发出的所有与终端相关的查询命令都触发TermResponse。(t_RVt_u7t_RFt_RB,和其他可能的。)所以这可能也取决于你的终端上
基督教Brabandt
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.