Múltiples cursores en la ubicación deseada

13

Estoy usando el complemento vim-multiple-cursors .

Me gustaría poner los cursores exactamente donde quiero. Por ejemplo ( [x]son las posiciones del cursor):

Lorem ipsum dolor sit amet[1], consectetur adipiscing elit, 
sed do eiusmod tempor incididunt ut labore et dolore magna[2]
aliqua.

En Sublime Text , normalmente pondría el primer cursor, luego iría a la siguiente posición con las teclas de flechas y colocaría el segundo.

¿Hay algo similar en VIM? Con este complemento u otro.

EDITAR

Después de un comentario, mi interés en hacerlo apareció al intentar escribir
\section[My first section in this book]{My first section in this book}
en un .texarchivo. Mi primera reacción fue escribir \section[]{}y luego poner dos cursores para escribir lo mismo dentro de []y {}.

Otro ejemplo sería agregar _someStuffdespués de varios nombres de variables diferentes. Por ejemplo, convierta esto:

variable1 = 2
my_variable2 = 12
var3 = 14

dentro de esto:

variable1_someStuff = 2
my_variable2_someStuff = 12
var3_someStuff = 14

Con múltiples cursores puedo hacer seleccionando un cursor de columna y luego yendo al final de la palabra, luego insertando, etc. Pero supongo que sería fácil elegir exactamente dónde quiero que estén los cursores.

tomasyany
fuente
1
Creo que una pregunta importante es: ¿por qué quieres hacer eso? ¿Que estás tratando de hacer? El uso de múltiples cursores no es realmente "seguir el camino de Vim", es probable que haya una forma diferente de hacer lo que quiere, al menos tan eficiente, utilizando las funciones integradas.
statox
@statox. Ver editar. Di dos ejemplos que me vinieron a la mente. El segundo lo puedo lograr con el complemento vim-multiple-cursors, pero el primero no lo puedo hacer, al menos de manera fácil.
tomasyany
@ Nobe4. Gracias, el segundo guión lo hizo.
tomasyany

Respuestas:

29

Usar cursor múltiple no es una cosa de Vimmer

Como dije en los comentarios, usar múltiples cursores (incluso con un complemento) no es realmente "seguir el camino de Vim", entiendo totalmente que es atractivo para alguien que viene de Sublime-Text, pero a menudo puedes encontrar alternativas que son al menos tan eficiente con las funciones integradas de Vim.

Por supuesto, encontrar estas soluciones alternativas no siempre es fácil y, a veces, lleva tiempo, pero será más fácil con su experiencia Vim y verá que con el tiempo múltiples cursores le parecerán totalmente inútiles.

Eso es genial, pero ¿cómo puedo encontrar una forma alternativa?

No hay una respuesta universal, ya que depende mucho de lo que intentes hacer, solo intentaré darte algunas pistas sobre lo primero que debes intentar:


El comando punto .

El comando Dot es probablemente una de las herramientas más poderosas en Vim, simplemente nos permite repetir el último cambio. No podría explicarlo mejor que Drew Neil en su Vim Práctico . Creo que todos los Vimmer deberían considerar leer este libro.

La fortaleza de este comando es que el último cambio puede ser una acción que funcione en un personaje, una línea o un archivo completo. Por ejemplo, un cambio puede delimitarse en el momento en que ingresa al modo de inserción y el momento en que regresa al modo normal.

Con eso en mente, es fácil hacer lo que quería hacer con el multicursor:

  • Primero configuremos nuestro entorno: escribamos como sugirió

    \section[]{}

  • Luego haga un cambio repetible. El cursor está ahora encendido }, presione F[para volver al [personaje. Luego ingrese al modo de inserción con iy escriba My first section in this booky regrese al modo normal con ESC:

    \section[My first section in this book]{}

  • Y aquí viene la parte mágica: escriba f{para colocar el cursor sobre el {personaje y presione .para repetir el último cambio:

    \section[My first section in this book]{My first section in this book}

Todo el desafío del comando dot es aprender a hacer cambios repetibles: vendrá con grokking Vim, pero lo básico es entender cómo hacer su cambio de manera repetible.

Por ejemplo, para insertar un punto y coma al final de una línea, preferirá usar en A;lugar de $a;. ¿Por qué?

Debido a que A;crea una acción atómica, cuando la use .en otra línea, sin importar dónde se encuentre en la línea, insertará el punto y coma al final. Mientras que cuando lo usa $a;, divide su cambio en dos partes $ay la inserción de ;modo que si lo usa ., insertará el punto y coma en la posición actual del cursor.

NOTA La fórmula mágica en Vim es n.. Un flujo de trabajo realmente genial es:

  • busca el lugar con el que deseas editar /pattern
  • haz tu edición repetible
  • use npara ir al siguiente lugar para editar
  • usar .para repetir la edición
  • repite los dos últimos pasos: eres el rey del mundo (o al menos de las ediciones)

macros

Las macros son otra herramienta extremadamente importante en Vim, ya que le permite grabar una secuencia de pulsaciones de teclas y repetirla como si la hubiera vuelto a escribir.

Usaré, como ejemplo, su segundo caso de uso:

variable1 = 2
my_variable2 = 12
var3 = 14

Una vez más, lo importante es aprender cómo hacer que sus macros sean eficientes (daré un contraejemplo justo después):

  • Coloque el cursor sobre la palabra variable1y comience a grabar su macro con qq. Esto significa "comenzar a grabar todas mis pulsaciones de teclas futuras en el registro denominado q".

  • Comience a hacer su edición escribiendo:

    • 0 ir al principio de la línea
    • e ir al final de la primera palabra
    • a para agregar después de su cursor
    • .someStuff agregar el texto deseado
    • <Esc> para detener la inserción
    • j ir a la siguiente línea
    • q para dejar de grabar la macro
  • Obtendrás:

variable1.someStuff = 2
my_variable2 = 12
var3 = 14
  • Ahora puede usar la macro para repetir su edición. Como está en la línea correcta para editar, simplemente puede ejecutar la macro con @q. Como queremos ejecutarlo dos veces, puede usarlo 2@qy obtendrá el siguiente resultado:
variable1.someStuff = 2
my_variable2.someStuff = 12
var3.someStuff = 14

NOTA 1 Como habrás notado, usar 0eaal principio de la macro fue realmente importante. De hecho, si hubiera colocado el cursor al final de la primera palabra antes de grabar la macro y ejecutarla nuevamente, su resultado habría sido:

variable1.someStuff = 2
my_variable2 = 12.someStuff
var3 = 14.someStuff

Como su cursor, el texto se habría insertado en la posición del cursor después de cambiar de línea (es decir, el final de la línea en este caso)

NOTA 2 Las macros son extremadamente potentes e incluso puede crear macros recursivas cuando se sienta cómodo con ellas. Aquí su macro podría haber sido:

`0ea.someStuff<Esc>j@q`

La final @qhabría llamado a la macro por sí misma en lugar de usarla 2@q; simplemente lo habrías usado @qy todo el trabajo se habría hecho.


bloqueo visual

Aquí viene otro truco que no se aplica directamente a su caso de uso, pero puede ser realmente útil para editar una gran cantidad de líneas al mismo tiempo. Consigamos este extracto del código CSS:

li.one   a{ background-image: url('/images/sprite.png'); }
li.two   a{ background-image: url('/images/sprite.png'); }
li.three a{ background-image: url('/images/sprite.png'); }

¿Qué pasa si moviste los sprites de imagesa components?

Así se puede poner el cursor sobre el ide imagesy pulse <C-v>. Esto iniciará el modo de bloque visual que permite seleccionar bloques. Ahora puede escribir t/ para seleccionar la palabra que desea cambiar y 2jseleccionar todas las apariciones de la palabra.

Después de eso, simplemente tiene que escribir cpara cambiar la palabra y luego components. Cuando salga del modo de inserción verá:

li.one   a{ background-image: url('/components/sprite.png'); }
li.two   a{ background-image: url('/components/sprite.png'); }
li.three a{ background-image: url('/components/sprite.png'); }

El comando global

El comando global es una herramienta que permite aplicar un comando en modo ex en líneas que coinciden con un patrón, una vez más, esa es una buena manera de aplicar el mismo cambio en un lugar diferente sin necesidad de múltiples cursores.

La sintaxis es la siguiente:

:[range] g / pattern / command

Para más detalles sobre el [range]parámetro, consulte :h :range. No lo detallaré aquí, simplemente recordaré que %representa todo el archivo, '<,'> representa la última selección y 1,5representa las líneas 1 a 5 del archivo.

Este parámetro define las líneas que serán tratadas por el comando global. Si no se especifica ningún rango, el comando global se usará %de manera predeterminada.

El argumento [patrón] es un patrón de búsqueda, ya que está acostumbrado a usarlo con el motor de búsqueda. Como integra el historial de búsqueda, puede dejar este campo en blanco y el comando global utilizará el último patrón de búsqueda en el historial de búsqueda.

Finalmente, el parámetro [comando] es un comando ex como probablemente esté acostumbrado.

Ahora el comportamiento del comando global es bastante simple:

  • Iterar a través de todas las líneas definidas en el parámetro [rango]
  • Si la línea actual coincide con el patrón definido, aplique el comando

Como el parámetro [comando] es un comando ex, puede hacer muchas cosas. Tomemos el siguiente pseudocódigo que no es muy interesante y tiene muchos mensajes de depuración:

var myList  = null
var i       = 0

myList = new List()
echo "List instantiated"

for (i=0; i<10; i++)
    myList.Add(i)
    echo i . " added to the list"

echo "end of for loop"

Ahora supongamos que está seguro de que este código funciona y desea eliminar estas echodeclaraciones inútiles :

  • Puede aplicar su comando global en todo el archivo, por lo que tendrá que anteponer el comando con %(o sin nada, ya que %es el rango predeterminado).

  • Sabes que las líneas que deseas eliminar coinciden con el patrón echo

  • Desea eliminar estas líneas, por lo que deberá usar el comando :delete que también se puede abreviar comod

Entonces simplemente tendrá que usar la siguiente función:

:%global/echo/delete

Que también se puede abreviar como

:g/echo/d

Tenga en cuenta que %desapareció, globalse abrevia como gy deletecomo d. Como te puedes imaginar, el resultado es:

var myList  = null
var i       = 0

myList = new List()

for (i=0; i<10; i++)
    myList.Add(i)

NOTA 1 Un punto importante que me llevó un tiempo darme cuenta es que el normalcomando es un comando ex, lo que significa que puede usarlo con el comando global. Eso puede ser realmente poderoso: digamos que quiero duplicar todas las líneas que contienen eco, no necesito una macro o incluso la fórmula mágica n.. Simplemente puedo usar

:g/echo/normal YP

Y voilá:

var myList  = null
var i       = 0

myList = new List()
echo "List instantiated"
echo "List instantiated"

for (i=0; i<10; i++)
    myList.Add(i)
    echo i . " added to the list"
    echo i . " added to the list"

echo "end of for loop"
echo "end of for loop"

NOTA 2 "Oye, ¿qué pasa si quiero usar mi comando en líneas que no coinciden con un patrón específico?"

globaltiene un comando opuesto vglobalabreviado vque funciona exactamente igual, globalexcepto que el comando se aplicará en líneas que no coinciden con el parámetro [patrón]. De esta manera si aplicamos

:v/echo/d

En nuestro ejemplo anterior obtenemos:

echo "List instantiated"
    echo i . " added to the list"
echo "end of for loop"

El deletecomando se ha aplicado en líneas que no contenían echo.


Aquí espero que esas pocas sugerencias le den ideas sobre cómo deshacerse de su complemento de cursor múltiple y usar Vim de la manera Vim ;-)

Como puede imaginar, estos ejemplos son bastante simples y solo están hechos para demostrar que cuando sigue la forma de Vim realmente rara vez necesita varios cursores. Mi consejo sería cuando encuentre una situación en la que piense que sería útil, escríbala y tómese un tiempo más tarde para encontrar una mejor solución. El 99% de las veces eventualmente encontrarás una forma más rápida / eficiente de hacerlo.

También me repetiré una vez más, pero realmente te animo a que leas Practical Vim de Drew Neil porque este libro no trata sobre "Cómo hacer eso o esto en Vim" sino sobre "Cómo aprender a pensar a la manera de Vim" lo que le permitirá construir su propia solución a sus problemas futuros de una buena manera.


PD: Un agradecimiento especial a @Alex Stragies por su trabajo de edición y las correcciones que hizo a esta larga publicación.

statox
fuente
Muy completa respuesta. En realidad conocía todos esos comandos, pero nunca pensé en usarlos así ... Creo que necesito más práctica. Sin embargo, debo decir que a veces el 'vim-way' lleva más tiempo que solo usar algún complemento (por ejemplo, su ejemplo de CSS se puede hacer mucho más rápido con el complemento que mencioné), y a veces toma mucho más corto (en realidad, el vasto la mayoría de las veces vim es más rápido que cualquier editor de texto, si se usa correctamente).
tomasyany
Por cierto, creo que tu respuesta ya está bastante completa. Lo aceptaré, pero si desea agregar más detalles, hágalo y me complacerá leerlos.
tomasyany
1
@tomasyany: De hecho, a veces usar el "modo vim" puede parecer más largo (no puedo contar cuántas veces paso más tiempo creando una macro de trabajo que si hubiera hecho los cambios manualmente) pero con la práctica eventualmente se vuelve más rápido. He estado usando Vim durante solo un año y estoy (muy) lejos de ser un experto, pero puedo sentir que mi edición mejora continuamente mientras practico.
statox
1
Probablemente debería mencionar también el gnobjeto de texto. Aborda algunos casos de uso de múltiples cursores. Busque con /, luego dgno cgn, luego repita con ..
Justin M. Keyes
@Justin No estoy realmente familiarizado gn. Lo intentaré y lo agregaré después. ¡Gracias por estar al frente!
statox
5

Sus casos de uso dados me parecen querer saber el .comando de teclado (repita el último comando de Edición)

  • Vaya al primer lugar, presione i, inserte su texto,<ESC>
  • mover a la ubicación 2, presione .(Punto) ==> Se inserta el texto idéntico
  • Para moverse hacia abajo una línea aquí e insertar nuevamente (al insertar en líneas consecutivas), presione <ALT>-j.

Su ejemplo de texto para mí se resuelve con:

I\section[]{}<ESC>hhiMy first Sec...<ESC>lll.

Alex Stragies
fuente
Es una buena solución. Conocía perfectamente el .comando de teclado, pero nunca pensé en usarlo de esa manera. Estoy de acuerdo en que es una buena manera. Pero su respuesta en realidad no se refiere a la pregunta real, por lo que no sería apropiado aceptarla, supongo.
tomasyany
1
Bueno, su pregunta (después de agregar los casos de uso deseados) me recordó a "Realmente me gustan mis tijeras y quiero apretar un tornillo con ellas. Dime cómo". Y yo señalando un uso ingenioso para un destornillador;) (agregué como respuesta, porque no sé, cómo formatear en los comentarios)
Alex Stragies
4

Más formas de Vim.

Primera tarea:

\section[foobar baz]{foobar baz}

Flujo de trabajo:

\section[]{}
hh
ifoobar baz<Esc>
$.

Segunda tarea:

variable1 = 2
my_variable2 = 12
var3 = 14

Mando:

3:norm ea_somestuff

Resultado:

variable1_somestuff = 2
my_variable2_somestuff = 12
var3_somestuff = 14
romainl
fuente