Por que esse mapeamento no modo normal <Esc> afeta a inicialização?

13

Estou tendo um problema estranho com um mapeamento de modo normal de Esc.

Se você criar o arquivo escmapvimrccom o conteúdo:

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

E então inicie o vim usando este vimrc:

vim --noplugin -u escmapvimrc

Em seguida, o vim iniciará no modo pendente do operador com um ccomando aguardando mais entradas, exibindo um arquivo vazio e exibindo a linha de comandos :noh.

Se você remover a nnoremaplinha, o problema desaparecerá.

Se você depurar e passar por tudo, obterá a seguinte saída:

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

Depois de pressionar enter, a tela de inicialização do Vim é exibida e abaixo:

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

A tela de inicialização do Vim desaparece e você está no modo pendente de operador, conforme descrito acima.

O que está acontecendo?

EDIT: O comportamento é como descrito no Vim 7.3. No Vim 7.4.52, as nmapcausas do Vim são iniciadas no modo Substituir ao iniciar o Vim sem um arquivo. (Se o Vim 7.4.52 for iniciado com um arquivo, no entanto, ele também será iniciado com um comando c em andamento.) De qualquer maneira, o problema desaparecerá quando o nmap for removido.

Rico
fonte
Eu reproduzi isso com o vim, mas a linha de comando não apareceu :nohpara mim. Fazer o mesmo com o gvim não mostrou esse comportamento.
PhilippFrank
1
Um mapeamento comum para limpar o destaque de busca é:nnoremap <c-l> :noh<cr><c-l>
Peter Rincker
Como nota lateral, você pode usar /alksdjflaskjpara esclarecer o destaque da pesquisa, que também é bastante rápido.
Shahbaz

Respostas:

11

O Vim envia durante a inicialização alguns códigos de terminal especiais (que geralmente contêm a <esc>chave) para determinar várias coisas (cores, bs, ...) Se você mapeou, <esc>isso provavelmente irá confundir o analisador dos códigos de retorno e coisas estranhas podem acontecer.

Portanto, use o mapa acima somente depois que tudo estiver configurado corretamente (por exemplo, através de um comando automático do VimEnter).

Christian Brabandt
fonte
1
Bem, eles são enviados sempre que a 'term'opção é definida. Isso geralmente é apenas durante a inicialização, mas pode haver cenários em que é definido em tempo de execução.
jamessan
Nesse caso em particular, isso parece ser causado por may_req_ambiguous_char_width (), que é chamado apenas na inicialização
Christian Brabandt
Eu estava planejando tentar exatamente isso (e é por isso que não aceitei a outra resposta). É bom ter confirmação de que deve funcionar, no entanto.
19315 Rich
Isso fez o truque, embora VimEnterespecificamente não funcione.
20915 Rich
Ta brincando né? O escape usado para se comunicar deve ser separado do mapeamento da tecla Escape.
precisa saber é o seguinte
11

O terminal Linux usa seqüências de escape ANSI (ou seja, cadeias de caracteres começando com <Esc>) para enviar chaves especiais ao Vim e como parte do protocolo de comunicação com o qual o aplicativo consulta seus recursos. Seu mapeamento interfere nisso e, portanto, leva a esses comportamentos "estranhos".

Portanto, não mapeie<Esc> . Use outra tecla. O problema é menos pronunciado no GVIM, mas também não o recomendo.

Ingo Karkat
fonte
Infelizmente, eu tenho esse mapeamento quase desde que comecei a usar o Vim, então está muito bem queimado na minha memória muscular agora. Obrigado pela explicação, no entanto.
18715 Rich
Provavelmente, devo acrescentar, por uma questão de posteridade, o problema descrito é o único problema que eu sei que definitivamente é causado por esse mapeamento e o único problema não resolvido estranho que consigo me lembrar de ter com o Vim.
18315 Rich
1
@ Rich quão difícil seria se acostumar a usar algo como <Esc><Esc>?
Random832
@ Random832 Essa é uma ideia intrigante.
20915 Rich
1
Todos os programas xterm farão isso porque emulam os terminais VT-100. Não tem nada a ver com o Linux. O iOS, que é baseado no BSD e não no Linux, também terá xterms que emulam os VT-100s.
shawnhcorey
1

Tente o seguinte:

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

cf /programming//a/16027716/400545

Jerome Dalbert
fonte
Isso não funciona bem para mim. Depois, substituindo o mapeamento no meu escapemapvimrcarquivo por este, quando a inicialização do Vim é concluída, estou no modo de linha de comando, com a linha de comando contendo o seguinte conteúdo: :83/94/95^G(isso é literal CTRL-Gno final). Essa parte :helpparece sugerir que talvez esse não seja o melhor momento para configurar o mapeamento: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

Tentei configurar um comando automático para definir o mapeamento posteriormente na inicialização, mas o problema ainda ocorreu. *

Eventualmente, criei um comando automático para ocorrer na primeira vez que entro no modo Inserir. Obviamente, essa não é uma solução perfeita, mas para mim funcionará a maior parte do tempo e parece ser o melhor que posso fazer:

ATUALIZAÇÃO : Depois de usar a versão mais longa abaixo sem problemas por alguns anos, decidi que ela estava com um pouco de engenharia excessiva e, desde então, usei essa versão muito mais simples, que apenas redefine o mapeamento toda vez que você entra no modo de inserção:

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

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

O mapeamento não precisa ser redefinido toda vez que você entra no modo de inserção, mas também não faz mal ao Vim.

VERSÃO ORIGINAL :

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

* Eu tentei anexá-lo a vários eventos: VimEnter, BufReadPost, BufWinEnter, e até mesmo CursorMoved(!), Mas estes todos parecem fogo muito cedo.

Rico
fonte
Você já tentou o TermResponsecomando automático?
Christian Brabandt
@ChristianBrabandt eu tenho agora. Não funciona bem para mim :(.
Rich
Eu aprendi recentemente que o TermResponse não é acionado para todos os comandos de consulta relacionados ao terminal, que o vim apenas envia. ( t_RV, t_u7, t_RF, t_RB, E possivelmente outros.) Então isso pode também dependem de seu terminal
Christian Brabandt