Resumen
Es un error y hay un parche (743). El error afecta a ambos ejemplos, pero no lo ve en un caso porque el carácter que se mueve hacia abajo es un (espacio en blanco). La solución es instalar el parche, pero también hay muchas soluciones alternativas o métodos alternativos, no afectados por el error.
NB : {, }y Btodos se refieren al mismo objeto de texto: Block ( :help aB
, :help iB
). Si esta u otras respuestas usan un signo diferente al que se usó en la pregunta, puede ser por eso.
El bicho
No lo entiendo completamente, pero aquí hay una explicación, si alguien está interesado.
El comportamiento que ve se debe a un error mencionado por Yukihiro Nakadaira en vim_dev y su parche se publica como 7.4.743: "p" en modo Visual provoca una división de línea inesperada .
:help v_p
Se supone que el modo visual put ( ) reemplaza el texto seleccionado visualmente con el texto de un registro. El fallo sucede cuando a) el registro es de tipo linewise ( :help linewise-register
), pero la selección visual es de tipo characterwise y b) los extremos de selección visuales en la última columna de una línea. En su caso, si tira del Bloque interno y luego selecciona visualmente un Bloque y lo pega, el registro arrancado será en línea y la selección visual será en forma de caracteres. Podemos tirar tanto del Bloque interno como de un Bloque a registros con nombre e inspeccionar:
En
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];
}
hacemos
"ayi{
"bya{
:registers ab
que muestra
--- 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}
y
:echo getregtype('a') " displays 'V' for linewise
:echo getregtype('b') " displays 'v' for characterwise
Para reemplazar una selección visual por caracteres con un registro lineal, las líneas que contienen el principio y el final de la selección visual deben dividirse en dos, de modo que el texto pueda insertarse en el medio. Esto generalmente funciona bien:
Ejecutando vim as vim -u NONE -U NONE
y escribiendo
( a )
iaaa
bbb
ccc
ddd<Esc>ggYjlvp
resultados en
aaa
b
aaa
b
ccc
y ( b )
iaaa
bbb
ccc
ddd<Esc>ggYjvjp
en
aaa
aaa
cc
ddd
Pero cuando la selección visual de caracteres termina en la última columna de una línea (y no incluye la nueva línea /n
/ ^J
) algo sale mal. Tiene que ver con la posición del cursor, que de repente se desactiva en -1 y debe incrementarse especialmente, que es lo que hace el parche. Compare ( a ) con el comando <Esc>ggYjllvp
, es decir, el mismo comando, excepto que mueva una columna más hacia la derecha para que el cursor esté en la última "b" de la línea. ¡El resultado es el mismo que antes!
Ahora tome el siguiente texto:
if (TIRED){
goto bed;
} else {
goto work;
}
Con el cursor en la segunda línea, yi{va{p
funciona bien y da
if (TIRED)
goto bed;
else {
goto work;
}
El registro de arrastre sigue en línea y la selección visual en forma de caracteres, pero la selección visual ya no termina en la última columna y todo está bien.
Ejemplos de textos de la pregunta
Para los dos textos de ejemplo, donde la única diferencia es un espacio en blanco entre el cierre del paréntesis y la apertura del corchete en la primera línea, puede parecer que su comando se comporta de manera diferente, pero realmente no lo hace. En el primer caso, el que parece exitoso, debe haber un espacio en blanco al final de la primera línea una vez que se eliminan los corchetes. Ese espacio en blanco al final está en la última línea. Conyi{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];
}
se convierte
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];
␣
al igual que
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];
}
se convierte
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];
)
Soluciones
La solución sería instalar el parche, pero hay muchas otras formas de eliminar los corchetes circundantes que no sufren el error. La mejor solución es la respuesta de @Gilles, pero la más fácil puede ser seleccionar visualmente antes de tirar, para mantener el registro con carácter.
El complemento de sonido envolvente de Tim Pope es excelente, pero (al menos para mí) hace más que quitar los corchetes: une la segunda línea a la primera, elimina la sangría y mueve el cursor al comienzo de la primera línea. Esto deja una limpieza no trivial que hacer. Ingo Karkat y Luc Hermitte tienen complementos que se ocupan de los registros y el pegado (estoy seguro de que hay muchos otros) y que deberían poder hacerlo. No estoy muy familiarizado con ellos, pero creo que con los corchetes lh que podrías hacer <M-b>x
para eliminar los corchetes circundantes y para una colocación más poderosa (especialmente en modo visual) podrías mirar Reemplazar con registro y UnconditionalPaste .
La mejor manera es la que da respuesta @Gilles, [{x]}x
. Es rápido, maneja bien los bloques anidados y no une líneas inapropiadamente ni ensucia con sangría. Si hay un espacio en blanco antes del corchete de apertura, puede agregar fácilmente un x
comando para eliminarlo:[{xx]}x
Otros comandos de vainilla
Una vez más, el comando más apropiado que se me ocurre es el de la respuesta de @Gilles, [{x]}x
o [{xx]}x
, pero aquí hay dos alternativas específicamente a la luz de este error.
Yank personaje
Dado que el error ocurre solo para el registro visual en línea sobre la selección de caracteres, y dado que es solo accidental en su bloqueo interno de Bloqueo que sea en línea, puede optar por tirarlo en su lugar. Una forma fácil es seleccionar visualmente el interior de manzana antes de tirar de ella, y para asegurarse de que la selección visual es characterwise (es decir, el uso v
no V
): vi{yva{p
. Esta puede ser la forma más fácil porque es muy similar a cómo realiza actualmente la operación.
No uses visual put
Otros comandos, como cambiar y eliminar, no se ven afectados por este error. Puede tirar como antes, pero luego eliminar un Bloque en el registro de agujeros negros ( :help quote_
) y colocar, o eliminar un Bloque y colocar desde el registro 0 ( :help quote0
): yi{"_da{p
oyi{da{"0p
Generalidad
Finalmente, hay formas similares a la respuesta de @Gilles: mover al comienzo de un bloque, eliminar el carácter, mover al final de un bloque, eliminar el carácter, pero que son más genéricos. La única razón para usarlos sería si el "bloque" que está eliminando es excéntrico y no tiene movimientos asociados que funcionen tan bien como [{
para un bloque delimitado por llaves. Existe la posibilidad de que el complemento vim-surround pueda manejar bien estos bloques excéntricos, pero dos formas vanas serían
- Seleccione visualmente el bloque excéntrico y salga del modo visual. El cursor está en el último carácter de la selección. Elimínelo, luego vaya al comienzo de la última selección (
:help `<
) y elimine el carácter.va{<Esc>x`<x
- Busque hacia atrás el comienzo del bloque excéntrico y elimine el carácter, luego busque hacia el final del bloque excéntrico y elimine el carácter.
?{<CR>x/}<CR>x
Esto puede no funcionar bien con bloques anidados.
Número de letras
+----+------------------------+----------------------------+------------+
| | 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;
viene el. ¿También podría precisar dónde coloca el cursor antes de ejecutar cada secuencia de teclas?