Sumário
É um bug e existe um patch (743). O bug afeta os dois exemplos, mas você não o vê em um caso, porque o caractere que é movido para baixo é um (espaço em branco). A solução é instalar o patch, mas também existem muitas soluções alternativas ou métodos alternativos, não afetados pelo bug.
NB : {, }e Btodos se referem ao mesmo objeto texto: Block ( :help aB
, :help iB
). Se essa ou outras respostas usarem um sinal diferente do usado na pergunta, talvez seja por isso.
O inseto
Eu não entendo completamente, mas aqui está uma explicação, se alguém estiver interessado.
O comportamento que você vê é devido a um bug mencionado por Yukihiro Nakadaira no vim_dev e seu patch foi lançado como 7.4.743: "p" no modo Visual causa uma divisão inesperada de linhas .
O modo visual put ( :help v_p
) deve substituir o texto selecionado visualmente pelo texto de um registro. O erro acontece quando a) O registo é do tipo linewise ( :help linewise-register
), mas a seleção visual é do tipo characterwise e b) as extremidades seleção visual na última coluna de uma linha. No seu caso, se você puxar o bloco interno e selecionar visualmente um bloco e colar, o registro arrancado será no sentido da linha e a seleção visual será no caráter. Podemos puxar o bloco interno e um bloco para registros nomeados e inspecionar:
Em
for(int i = 0; i < s.length(); i++){
int index = s[i] - c;
if(root->next[index] == NULL)
root->next[index] = new TrieNode;
root = root->next[index];
}
nós fazemos
"ayi{
"bya{
:registers ab
que mostra
--- Registers ---
"a int index = s[i] - c;^J if(root->next[index] == NULL)^J root->next[index] = new TrieNode;^J root = root->next[index];^J
"b {^J int index = s[i] - c;^J if(root->next[index] == NULL)^J root->next[index] = new TrieNode;^J root = root->next[index];^J}
e
:echo getregtype('a') " displays 'V' for linewise
:echo getregtype('b') " displays 'v' for characterwise
Para substituir uma seleção visual caracterizada por um registro linear, as linhas que contêm o início e o final da seleção visual devem ser divididas em duas, para que o texto possa ser inserido no meio. Isso geralmente funciona muito bem:
Executando o vim as vim -u NONE -U NONE
e digitando
( a )
iaaa
bbb
ccc
ddd<Esc>ggYjlvp
resulta em
aaa
b
aaa
b
ccc
e ( b )
iaaa
bbb
ccc
ddd<Esc>ggYjvjp
no
aaa
aaa
cc
ddd
Mas quando a seleção visual caractere termina na última coluna de uma linha (e não inclui a nova linha /n
/ ^J
), algo dá errado. Tem a ver com a posição do cursor, que é subitamente desligada por -1 e deve ser especialmente incrementada, que é o que o patch faz. Compare ( a ) com o comando <Esc>ggYjllvp
, ou seja, o mesmo comando, exceto mova mais uma coluna para a direita para que o cursor fique no último "b" da linha. O resultado é o mesmo de antes!
Agora pegue o seguinte texto:
if (TIRED){
goto bed;
} else {
goto work;
}
Com o cursor na segunda linha, você yi{va{p
trabalha muito bem e dá
if (TIRED)
goto bed;
else {
goto work;
}
O registro do arranco ainda está no sentido da linha e a seleção visual no sentido dos caracteres, mas a seleção visual não termina mais na última coluna e está tudo bem.
Exemplos de textos da pergunta
Para os dois exemplos de texto, onde a única diferença é um espaço em branco entre o fechamento de parênteses e a abertura de colchetes na primeira linha, pode parecer que seu comando se comporta de maneira diferente, mas realmente não. No primeiro caso, aquele que parece bem-sucedido, deve haver um espaço em branco à direita na primeira linha depois que os colchetes forem removidos. Esse espaço em branco à direita fica na última linha. Comyi{va{p
for(int i = 0; i < s.length(); i++) {
int index = s[i] - c;
if(root->next[index] == NULL)
root->next[index] = new TrieNode;
root = root->next[index];
}
torna-se
for(int i = 0; i < s.length(); i++)
int index = s[i] - c;
if(root->next[index] == NULL)
root->next[index] = new TrieNode;
root = root->next[index];
␣
Assim como
for(int i = 0; i < s.length(); i++){
int index = s[i] - c;
if(root->next[index] == NULL)
root->next[index] = new TrieNode;
root = root->next[index];
}
torna-se
for(int i = 0; i < s.length(); i++
int index = s[i] - c;
if(root->next[index] == NULL)
root->next[index] = new TrieNode;
root = root->next[index];
)
Soluções
A solução seria instalar o patch, mas existem muitas outras maneiras de remover os colchetes ao redor que não sofrem com o bug. A melhor solução alternativa é a resposta do @Gilles, mas o mais fácil pode ser selecionar visualmente antes de puxar, para manter o registro caractere.
O plugin surround de Tim Pope é excelente, mas (pelo menos para mim) faz mais do que remover os colchetes: une a segunda linha à primeira, remove o recuo e move o cursor para o início da primeira linha. Isso deixa uma limpeza não trivial para fazer. Ingo Karkat e Luc Hermitte têm plugins que lidam com registros e colagens (tenho certeza que existem muitos outros) e que devem ser capazes de fazer isso. Eu não estou muito familiarizado com eles, mas acredito que, com lh-colchetes, você pode <M-b>x
excluir os colchetes circundantes e, para uma colocação mais poderosa (especialmente no modo visual), você pode ver ReplaceWithRegister e UnconditionalPaste .
A melhor maneira é a dada na resposta do @Gilles [{x]}x
,. É rápido, lida bem com blocos aninhados e não junta linhas de maneira inadequada ou mexe com o recuo. Se houver um espaço em branco antes do suporte de abertura, você poderá adicionar facilmente um x
ao comando para removê-lo:[{xx]}x
Outros comandos vanilla
Novamente, o comando mais apropriado que consigo pensar é o da resposta do @Gilles, [{x]}x
ou [{xx]}x
, mas aqui estão duas alternativas especificamente à luz desse bug.
Yank characterwise
Como o erro ocorre apenas para o registro visual colocado em linha a linha sobre a seleção entre caracteres, e como é acidental ao seu puxão interno do bloco ser lateral, você pode optar por puxá-lo no sentido contrário. Uma maneira fácil é selecionar visualmente o bloco interno antes de arrancá-lo, e para certificar-se de que a seleção visual é characterwise (ou seja, o uso v
não V
): vi{yva{p
. Essa pode ser a maneira mais fácil, pois é muito semelhante à maneira como você faz a operação no momento.
Não use visual put
Outros comandos, como alterar e excluir, não são afetados por esse bug. Você pode puxar como antes, mas excluir um bloco no registro do buraco negro ( :help quote_
) e colocar ou excluir um bloco e colocar no registro 0 ( :help quote0
): yi{"_da{p
ouyi{da{"0p
Generalidade
Finalmente, existem maneiras semelhantes à resposta do @Gilles - mover para o início de um bloco, excluir caractere, mover para o final de um bloco, excluir caractere - mas que são mais genéricas. A única razão para usá-las seria se o "bloco" que você está excluindo for excêntrico e não tiver movimentos associados que funcionem tão bem quanto [{
para um bloco delimitado por colchetes. Há uma chance de que o plug-in vim-surround possa lidar bem com esses blocos excêntricos, mas duas maneiras básicas seriam
- Selecione visualmente o bloco excêntrico e saia do modo visual. O cursor está no último caractere da seleção. Exclua-o e vá para o início da última seleção (
:help `<
) e exclua o caractere.va{<Esc>x`<x
- Pesquise para trás o início do bloco excêntrico e exclua o caractere; em seguida, pesquise o final do bloco excêntrico e exclua o caractere.
?{<CR>x/}<CR>x
Isso pode não funcionar bem com blocos aninhados.
Contador de caracteres
+----+------------------------+----------------------------+------------+
| | method | command | characters |
+----+------------------------+----------------------------+------------+
| 1. | vim-surround | ds{ | 3 |
| 2. | @Gilles answer | [{x]}x | 6 |
| 3. | Characterwise yank | vi{yva{p | 8 |
| 4. | Delete, not visual put | yi{"_da{p or yi{da{"0p | 9 |
| 5. | Visual mark | va{<Esc>x`<x | 8 |
| 6. | Search | ?{<CR>x/}<CR>x | 8 |
+----+------------------------+----------------------------+------------+
return -1;
vem. Além disso, você pode precisar onde coloca o cursor antes de executar cada sequência de teclas?