SÃ, los cursores mÚltiples son mÃĄgicos. Son convenientes, fÃĄcil de usar y estÃĄn presente en muchos editores modernos. Para bien o para mal, vim no los tiene. Pero estÃĄ bien, podemos ser felices sin ellos. Bueno... yo puedo y voy decirles cÃģmo.
Vamos a repasar las situaciones donde podrÃamos usar cursores mÚltiples y veremos quÃĐ alternativas tenemos en vim.
Reemplazar palabra debajo del cursor
En vim debemos comenzar el proceso buscando la palabra debajo del cursor, para esto presionamos *. Luego presionamos cgn para reemplazar la prÃģxima ocurrencia. Si queremos repetir la acciÃģn presionamos ., sÃ, el punto. Si no queremos reemplazar la ocurrencia actual podemos ignorarla y pasar a la siguiente presionando n.
Podemos hacer este proceso mÃĄs rÃĄpido si creamos un atajo de teclado que agrupe los primeros dos pasos.
nnoremap <leader>j *``cgn
Con este atajo podremos utilizar la tecla lÃder + j para reemplazar la palabra actual, luego podremos navegar entre cada ocurrencia de la palabra y usar . para reemplazar el texto.
Ver en asciinema.
Cambiar una variable
Puede ser que la palabra que quieren reemplazar es una variable en su cÃģdigo, en este caso serÃa ideal que el editor sÃģlo reemplace las referencias que son vÃĄlidas. Aquà la soluciÃģn puede ser un poco mÃĄs complicada. Como saben vim no es un IDE, este tipo de funcionalidad no estÃĄ habilitada por defecto. Pero no es imposible, existen plugins que nos permiten usar servidores LSP. Resulta que renombrar variables es una de esas funcionalidades que podemos obtener con un servidor LSP.
Personalmente uso Neovim y no vim como tal. En mi caso sÃģlo necesito algo como esto.
lua require('lspconfig').ts_ls.setup({})
nnoremap <F2> <cmd>lua vim.lsp.buf.rename()<cr>
Aquà uso nvim-lspconfig para configurar tsserver. Y creo el atajo <F2> para renombrar variables.
Ver en asciinema.
Si ustedes usan vim pueden probar estos plugins:
Reemplazar selecciÃģn
Tal vez el texto que queremos reemplazar no es una palabra, tal vez es una oraciÃģn o un atributo de html. En este caso no tenemos una funcionalidad nativa que nos ayude pero podemos implementar nuestra propia soluciÃģn.
Lo primero que haremos serÃĄ colocar la selecciÃģn actual en el "registro de bÚsqueda" de vim.
let @/=escape(@", '/')
Aquà tomamos el registro " que contiene la selecciÃģn mÃĄs reciente, nos aseguramos de escapar el caracter / para que no ocurra un conflicto en nuestra bÚsqueda, finalmente asignamos el resultado al registro /.
Luego debemos borrar toda la selecciÃģn e ir al modo de inserciÃģn. Esto lo logramos con esta secuencia.
"_cgn
Con "_ le decimos a vim que queremos usar el registro _ para nuestra siguiente operaciÃģn. cgn es para reemplazar la primera ocurrencia de una bÚsqueda.
Si juntamos estas piezas en un atajo tendremos esto.
xnoremap <leader>j y<cmd>let @/=escape(@", '/')<cr>"_cgn
Pero esta soluciÃģn sÃģlo funciona con bÚsquedas de una lÃnea. Si por alguna razÃģn quieren reemplazar una selecciÃģn de mÚltiples lÃneas deben hacer esto.
xnoremap <leader>j y<cmd>substitute(escape(@", '/'), '\n', '\\n', 'g')<cr>"_cgn
Aquà usamos la funciÃģn substitute para reemplazar el salto de lÃnea con \n, asà tÃĐcnicamente nuestra bÚsqueda siempre serÃĄ de una lÃnea.
ÂŋCÃģmo usamos esto? De la misma forma que usamos el atajo <leader>j en la secciÃģn "reemplazar palabra debajo del cursor". La diferencia es que en este caso primero debemos ir a modo visual para seleccionar el texto. Luego podremos repetir la acciÃģn usando . o podemos movernos a la siguiente ocurrencia usando n.
AÃąadir texto al inicio de una lista
Digamos que tenemos una lista de palabras y queremos convertirla en una lista ordenada en markdown.
Queremos transformar esto.
volar
html
cssls
En esto.
1. volar
1. html
1. cssls
En vim tenemos un modo llamado "visual block", cuando estamos en este modo tenemos la posibilidad de agregar texto a cada lÃnea de la selecciÃģn si vamos a modo de inserciÃģn usando I o A. Luego de insertar el texto en la primera lÃnea vim procede a repetir esta acciÃģn en el resto de las lÃneas seleccionadas.
Vamos a revisar paso a paso lo que debemos hacer.
Ver en asciinema.
- Vamos al primer caracter de la primera lÃnea.
- Presionamos
Ctrl + vpara ir al modo "visual block". - Seleccionamos las lÃneas que queremos cambiar.
- Presionamos
Ipara colocar el cursor al inicio de la selecciÃģn. - Agregamos el texto que queremos.
- Presionamos
Esc.
AÃąadir texto al final de una lista
SÃ. TambiÃĐn podemos modificar el final de la lÃnea. El proceso es casi idÃĐntico, con la diferencia de aquà debemos expandir la selecciÃģn hacia el final de la lÃnea.
Digamos que tenemos nuestra lista ordenada pero ahora queremos agregar el texto (is supported) al final de cada lÃnea.
Ver en asciinema.
- Vamos al primer caracter de la primera lÃnea.
- Presionamos
Ctrl + vpara ir al modo "visual block". - Seleccionamos las lÃneas que queremos cambiar.
- Expandimos la selecciÃģn hacia el final de la lÃnea presionando
$. - Presionamos
Apara colocar el cursor al final de la primera lÃnea. - Agregamos el texto que queremos.
- Presionamos
Esc.
Repetir un movimientos
El modo visual block puede ser Útil en muchas situaciones pero es limitado. SÃģlo puede agregar texto en un lugar. ÂŋQuÃĐ hacemos cuando queremos hacer modificaciones complejas? La respuesta: macros. Un macro es una cadena de texto que describe una secuencia de teclas. Podemos "grabar" un macro y repetirlo tantas veces sea necesario.
ÂŋCÃģmo usamos un macro? Primero debemos elegir un registro. Algo asà como una etiqueta para nuestro macro. Presionamos q seguido de la letra de nuestro registro. Luego ejecutamos las modificaciones que queremos. Finalmente presionamos q para terminar de grabar el macro. Para repetir el macro debemos presionar @ seguido de la letra que elegimos en el primer paso.
Vamos con un ejemplo.
Tenemos esta lista.
volar
html
cssls
eslint
Y queremos convertirlo en una lista ordenada de enlaces.
1. [volar](http://localhost/how-to-configure-volar-lsp)
1. [html](http://localhost/how-to-configure-html-lsp)
1. [cssls](http://localhost/how-to-configure-cssls-lsp)
1. [eslint](http://localhost/how-to-configure-eslint-lsp)
Noten que aquà necesitamos aÃąadir texto al inicio y final de cada lÃnea. TambiÃĐn tenemos que copiar el nombre de cada item y colocarlo en el enlace.
Lo que haremos serÃĄ convertir el primer item y repetir el proceso usando un macro. Estos son los pasos.
- Grabamos el macro en el registro
i. Presionamosqi. - Modificamos el primer item.
- Finalizamos la grabaciÃģn del macro presionando
qnuevamente. - Repetimos el macro tres veces presionando
3@i.
Ver en asciinema.
Cuando aplicamos un macro de esta manera, con repeticiones automÃĄticas, debemos tener en cuenta la posiciÃģn del cursor. En este caso particular el primer atajo que utilicÃĐ al comenzar a grabar el macro fue 0 y terminÃĐ presionando j. Con esto me aseguro de que en cada repeticiÃģn el cursor estÃĐ en el primer caracter de la lÃnea, y justo antes de terminar el macro muevo el cursor a la lÃnea que estÃĄ debajo.
Aplicar un macro en lÃneas especÃficas
Otra forma interesante de aplicar un macro es con el comando g. Este comando ejecuta una bÚsqueda y nos da la oportunidad de ejecutar otro comando en las lÃneas donde hay una ocurrencia. En nuestro caso lo que queremos hacer despuÃĐs de la bÚsqueda es ejecutar un macro, para eso usamos el comando normal @i (donde i puede ser cualquier registro).
Digamos que queremos buscar todas las lÃneas con la palabra vim y ejecutar un macro. Podemos hacer algo asÃ.
:g/vim/normal @i
Si quieren asegurarse de que su bÚsqueda tiene los resultados esperados pueden omitir la secciÃģn que va despuÃĐs de la bÚsqueda.
:g/vim/
Si todo estÃĄ bien agregamos normal @i.
Aplicar un macro en una selecciÃģn
No estamos obligados a usar el comando g, podemos utilizar el comando normal @i sobre una selecciÃģn ejecutando este comando.
'<,'>normal @i
Nota: No se preocupen por recordar la sintaxis
'<,'>, vim lo agregarÃĄ automÃĄticamente cuando pasamos de modo visual a modo de comando.
Esto ejecutarÃĄ el macro en i sobre cada lÃnea de la selecciÃģn. Deben tener en cuenta que cada macro comenzarÃĄ con el cursor al principio de la lÃnea.
Buscar patrÃģn y ejecutar un macro
Esta es una alternativa al comando g. Porque tal vez no se sienten cÃģmodos usando expresiones regulares. Los entiendo. La mayorÃa de las veces lo que quiero hacer es seleccionar un pedazo de texto y aplicar un macro sobre algunas ocurrencias. Ya vimos cÃģmo buscar una selecciÃģn, podemos aplicar este conocimiento para manipular la posiciÃģn del cursor.
ÂŋRecuerdan esto?
y<cmd>let @/=substitute(escape(@", '/'), '\n', '\\n', 'g')<cr>
Esta es la secuencia que usamos para colocar la selecciÃģn actual en el registro de bÚsqueda. Todo lo que tenemos que hacer es iniciar la grabaciÃģn del macro despuÃĐs de esta funciÃģn. AsÃ.
gvqi
Con gv vim vuelve a resaltar la selecciÃģn anterior, porque recuerden que perdemos la selecciÃģn luego de presionar y. DespuÃĐs con qi comienza la grabaciÃģn del macro en el registro i.
Si juntamos todo esto en un atajo obtenemos:
xnoremap <leader>i y<cmd>let @/=substitute(escape(@", '/'), '\n', '\\n', 'g')<cr>gvqi
La historia no termina aquÃ, ahora tenemos que aplicar el macro en las ocurrencias de nuestra selecciÃģn. Usaremos gn para seleccionar la siguiente ocurrencia y ejecutar el macro.
nnoremap <F8> gn@i
Vamos con un ejemplo de la vida real.
Hace unos meses estaba probando packer.nvim, un manejador de plugins. En mi configuraciÃģn tenÃa este cÃģdigo.
require('packer').startup(function(use)
use({
'nvim-lualine/lualine.nvim',
config = function() require('plugins.lualine') end,
})
use({
'akinsho/bufferline.nvim',
config = function() require('plugins.bufferline') end,
})
use({
'lukas-reineke/indent-blankline.nvim',
config = function() require('plugins.indent-blankline') end,
})
end)
Me molestaba tener que repetir function() require... por cada plugin. BusquÃĐ por internet y encontrÃĐ la manera de reducir el cÃģdigo repetido. Escribà esta funciÃģn.
local function load(name)
return string.format([[pcall(require, 'plugins.%s')]], name)
end
Con esta funciÃģn puedo reducir el cÃģdigo necesario para utilizar config. Puedo hacer esto.
config = load('lualine')
Lo que queda es reemplazar la propiedad config de cada plugin.
Ver en asciinema.
- Seleccionamos el patrÃģn que vamos a buscar. En este caso
config =. - Comenzamos a grabar el macro usando el atajo
<leader>i. - Hacemos las operaciones necesarias.
- Terminamos de grabar el macro presionando
q. - Presionamos
npara ir al siguiente punto. - Repetimos el macro con el atajo
<F8>.
BÚsqueda y reemplazo
Porque muchas veces no necesitamos herramientas complicadas.
En vim podemos usar el comando substitute. Esta es la sintaxis.
%s/<patrÃģn>/<reemplazo>/g
Aquà % es el "rango" de la bÚsqueda, si usamos % quiere decir que queremos buscar en todo el archivo. s es el comando, no tenemos que escribir el nombre completo substitute. <patrÃģn> es la expresiÃģn regular que queremos buscar. <reemplazo> es el texto queremos usar. g es un "flag" que le indica a vim que debe buscar en toda la lÃnea. Noten que cada una de estas secciones estÃĄ separada por /, pero podemos usar otros caracteres.
Vamos con un ejemplo. Digamos que queremos cambiar la palabra config por setup. No necesitamos conocer nada de expresiones regulares, sÃģlo colocamos las palabras en el lugar correcto.
%s/config/setup/g
El Kirby tuerto
Okey. Si hay algo que les recomiendo aprender de expresiones regulares en vim son los "grupos". Incluso un pequeÃąo truco puede traer muchos beneficios.
ÂŋQuÃĐ es eso del kirby tuerto? Es la forma de recordar esta sintaxis.
\(.*\)
Este truco lo aprendà de ThePrimeagen.
Con este patrÃģn podemos capturar un pedazo de texto y crear un "grupo". Una vez que tenemos un grupo podremos utilizar el texto en nuestro texto de reemplazo.
Consideren este comando.
%s/`\(.*\)`/[\1](#how-to-configure-\1-lsp)
Aquà capturamos todo el texto que se encuentre entre comillas. Luego utilizamos el texto del grupo con el patrÃģn \1 en el texto de reemplazo. Aquà tienen un demo.
Ver en asciinema.
En este demo se puede observar en tiempo real el efecto del comando mientras escribo. Tengo entendido que esto es Único de neovim (puedo estar equivocado). Pero sÃ, con este efecto en tiempo real el comando substitute puede ser una buena alternativa (en algunos casos) a los cursores mÚltiples.
Si les preocupa no poder recordar la sintaxis del Kirby tuerto consideren crear un atajo.
cnoremap <F2> \(.*\)
De esta manera sÃģlo tienen que presionar <F2> para crear el grupo.
ConclusiÃģn
Ya estÃĄn listos. Pueden salir al mundo y ser productivos con vim. No puedo garantizar que serÃĄn felices pero sobrevivirÃĄn. EstÃĄ bien si todavÃa consideran que los cursores mÚltiples es la mejor herramienta. No importa, pueden vivir sin ellos mientras estÃĄn en vim.
Gracias por su tiempo. Si este artÃculo les pareciÃģ Útil y quieren apoyar mis esfuerzos para crear mÃĄs contenido pueden dejar una propina en ko-fi.com/vonheikemen.

Top comments (0)