Usando Netrw, el navegador de archivos nativo de vim
2021-01-10 | 13 minutos | Read in english¿Sabían que vim tiene un navegador de archivos? Sí, es un plugin que ya viene instalado con vim. Se llama Netrw... y no es muy popular, al menos no en comparación con otros plugins como NERDtree. La razón para esto es: 1) no es muy intuitivo. 2) tiene algunas limitaciones. 3) se ve feo. Hoy vamos a aprender a usarlo, veremos cómo sobrepasar algunas de sus limitaciones y en el proceso vamos a convertirlo en un navegador de archivos más intuitivo.
Presentación
Para empezar a conocer Netrw podemos intentar abrir un directorio usando vim (algo así: vim .
). Asumiendo que su vimrc
no está fuertemente configurado Netrw debería verse así.
Lo primero que vemos es un banner que tiene información sobre el directorio. Esto es lo que nos muestra.
- Información de Netrw, nombre y versión (v156).
- La ruta del directorio.
- El criterio que usa para ordenar los archivos y directorios, en este caso es por nombre.
- Otro criterio de orden. Esta vez es una secuencia que usará para dar prioridad a los archivos de acuerdo al sufijo.
- "Ayuda rápida". Aquí se listan algunas pistas sobre funcionalidades que ofrece Netrw.
Lo curioso de este banner es que pueden interactuar con algunas de sus "opciones". Por ejemplo, si colocan el cursor sobre la línea donde dice "sorted" y presionan Enter
verán cómo cambia el orden de los archivos según otros criterios. Podemos cambiar el order según la última actualización, el tamaño o extensión del archivo. En la ayuda rápida, al presionar Enter
, te mostrará distintos atajos para tareas comunes.
Luego del banner tenemos nuestros archivos y directorios. ../
representa el directorio padre y ./
es el directorio actual. Finalmente, justo debajo tenemos nuestros archivos perfectamente ordenados.
Uso
Ahora que sabemos cómo luce Netrw vamos a cubrir las funcionalidades básicas.
Invocación
Nuestra primera parada será el comando :Explore
. Al invocar este comando sin argumentos, nos mostrará el directorio del archivo que estamos editando actualmente. Si no queremos eso, podemos proveerle la ruta a un directorio de nuestra elección. Ahora, el comportamiento de :Explore
varía de acuerdo a la configuración de vim, específicamente la opción hidden
. Si está deshabilitada (así es por defecto) y el archivo que estamos editando no tiene cambios sin guardar :Explore
abrirá Netrw en pantalla completa. Si resulta que tenemos cambios sin guardar Netrw creará una división horizontal y mostrará el directorio en la ventana superior.
Si queremos que la división sea vertical utilizamos el comando
:Explore!
.
Si tenemos la opción hidden
habilitada Netrw siempre ocupará toda pantalla, no importa si tenemos cambios sin guardar en un archivo.
Ahora hablemos de las variantes de :Explore
que tenemos disponibles.
Hexplore: Creará una división horizontal y mostrará el directorio en la pantalla inferior. La variante con
!
muestra el directorio en el lado opuesto.Vexplore: Creará una división vertical y mostrará el directorio a la izquierda. La variante con
!
muestra el directorio en el lado opuesto.Sexplore: Creará una división horizontal y mostrará el directorio en la pantalla superior. La variante con
!
crea una división vertical y muestra el directorio del lado izquierdo.Texplore: Creará un nuevo tabpage para mostrar el directorio.
Lexplore: Funciona de una manera similar a
Vexplore
con la diferencia de que cuando abren un archivo este aparecerá en la ventana de donde abrieron Netrw. También tiene la particularidad de poder abrir y cerrar una ventana de Netrw. Pueden verlo en acción en este demo.
Ver en asciinema.
Navegando
Si queremos movernos entre directorios y archivos estos son los atajos que necesitamos conocer:
Enter
: Entra en un directorio o abre un archivo.-
: Regresa al directorio padre.u
: Regresa al directorio anterior (en el historial).gb
: Salta al directorio más reciente en el registro de "Bookmarks". Para crear un bookmark se utilizamb
.
Vamos a repasar. Si quieren ir "hacia abajo" un directorio presionan Enter
. Si quieren ir "hacia arriba" presionan -
. Si quieren ir "hacia atrás", u
. Y si quieren "saltar" a un directorio cualquiera, primero deben marcar su destino con un bookmark (usando mb
) y luego pueden usar gb
para ir a ese directorio.
Operaciones sobre archivos
Ahora vamos a darle un vistazo a los atajos involucrados en las tareas más comunes cuando queremos gestionar nuestros archivos.
p
: Abre una vista previa del archivo.<C-w>z
:Ctrl + w
y luegoz
. Cierra la ventana de vista previa.gh
: Habilita y deshabilita la visualización de archivos ocultos.%
: Crea un archivo. Bueno... en realidad no crea nada, te da la oportunidad de crearlo. Esto es lo que pasa, cuando se presiona%
vim pregunta por el nombre del archivo. Luego de que ingresas el nombre del archivo, te deja editarlo (pero aún no existe). Después de que editas el contenido y lo guardas (usando el comando:write
) el archivo es creado.R
: Es para renombrar un archivo.mt
: Asigna el "directorio destino" para las acciones de copiar y mover.mf
: Marca un archivo o directorio. Esto es importante porque las otras operaciones dependen de estas marcas. Si quieren copiar, mover o eliminar un archivo, este debe estar marcado.mc
: Copia los archivos marcados en el directorio destino.mm
: Mueve los archivos marcados al directorio destino.mx
: Ejecuta un comando externo sobre los archivos marcados.D
: Elimina un archivo o un directorio vacío. vim no nos dejará eliminar directorios con archivos dentro. Más adelante les diré cómo sobrepasar esta restricción.d
: Crea un directorio.
Ejecutando una operación sobre varios archivos
Después de leer sobre los atajos anteriores tal vez se estén preguntando cuáles son los pasos a seguir cuando queremos copiar o mover un archivo. Vamos a hacer un ejemplo moviendo un par de archivos a un directorio.
Este es un proceso de tres pasos:
Asignar el directorio destino.
Marcar los archivos que queremos mover.
Ejecutar el comando correspondiente, en nuestro caso:
mm
.
Aquí les dejo un demo para ilustrar el proceso.
Ver en asciinema.
Esto es lo que pasa:
00:00-00:17 Se usa el comando
:Explore
para abrir Netrw. Y luego se verifica el contenido del directoriotest dir
.00:18 Se asigna
test dir
como directorio destino. Noten que ahora el banner se actualiza y nos indica el directorio destino. Se agrega esta línea.
" Copy/Move Tgt: /tmp/vim/test dir/ (local)
00:20-00:25 Se marcan los archivos
a-file.txt
yanother-file.txt
. Para indicar que están marcados los nombres ahora aparecen en negrita.00:25-00:27 Se presiona
mm
para mover los archivos, y estos desaparecen de la pantalla actual.00:29 Se puede observar que los archivos marcados ahora están dentro de
test dir
.
Y ese básicamente el proceso para las operaciones de copiar y mover. Para ejecutar comandos externos y eliminar es casi igual, con la diferencia de que no necesitamos un directorio destino (un paso menos).
Limitaciones de Netrw
- Al mover archivos.
Esto ocurre en linux y tal vez en macOS sea igual. En nuestro ejemplo anterior mover a-file.txt
al directorio test dir
funciona de maravilla, pero si quieren devolver a-file.txt
al directorio padre se van a encontrar con este error.
**error** (netrw) tried using g:netrw_localmovecmd<mv>; it doesn't work!
Esto no ocurre cuando van a copiar un archivo.
Hasta donde pude indagar esto tiene que ver con el directorio donde abrimos Netrw y el directorio que estamos visualizando, cuando no son iguales ocurre este error. Para arreglarlo pueden cambiar la variable global g:netrw_keepdir
a cero.
let g:netrw_keepdir = 0
- Al ejecutar operaciones en archivos marcados.
Cuando van a ejecutar un comando sobre archivos marcados este sólo afecta a los que están listados en la pantalla actual.
Digamos que tenemos esta estructura en nuestro directorio.
vim
├── mini-plugins
│ ├── better-netrw.vim
│ ├── guess-indentation.vim
│ └── project-buffers.vim
├── test dir
│ ├── a-file.txt *
│ ├── another-file.txt *
│ └── text.txt
├── custom-commands.vim
└── init.vim *
Los archivos que tienen un *
son los que tenemos marcados. Si nos encontramos en el directorio vim
y hacemos el proceso para mover los archivos nos daremos cuenta que sólo se ha movido init.vim
al directorio destino. En teoría esto es bueno porque siempre tendremos a la vista los archivos sobre los cuales estamos operando.
- Netrw no permite borrar directorios con archivos usando
D
.
La respuesta a esto es: usar un comando externo. Por suerte Netrw tiene algo que puede ayudarnos. Si prestaron atención en secciones pasadas sabrán que el atajo mx
nos deja hacer precisamente eso. Pueden verlo en acción.
Ver en asciinema.
Entonces, la solución: marcar los directorios con mf
, usar mx
y escribir el comando que necesitamos (en el demo rm -r
). Es todo. ¿Pero podemos hacer este proceso más conveniente? Sí, y vamos discutirlo en la siguiente sección.
Personalización
Si han decidido darle una oportunidad a Netrw tal vez quieran modificarlo un poco para hacer que sea más agradable.
Configuración recomendada
Sincronizar el directorio actual y el directorio que está mostrando Netrw. Esto ayuda con el error cuando se intenta mover archivos.
let g:netrw_keepdir = 0
Configurar el porcentaje que ocupa Netrw cuando crea una división. 30% esta bien.
let g:netrw_winsize = 30
Ocultar el banner (Si quieren). Para mostrarlo temporalmente sólo deben presionar I
en Netrw.
let g:netrw_banner = 0
Ocultar archivos que comiencen con un punto.
let g:netrw_list_hide = '\(^\|\s\s\)\zs\.\S\+'
Modificar el comando para copiar archivos. Para permitir copiar directorios de manera recursiva.
let g:netrw_localcopydircmd = 'cp -r'
Resaltar los archivos marcados de la misma manera en la que se resalta las coincidencias en una búsqueda.
hi! link netrwMarkFile Search
Esta es la manera más fácil que se me ocurrió para resaltar más las marcas. Esto puede crear confusión si buscan una cadena de texto y tienen archivos marcados. Si desean aplicar otros colores investiguen sobre el comando
highlight
.
Keymaps
Ahora que Netrw se ve mejor, hagamos que sea más fácil de usar.
Invocando Netrw
Podemos usar el comando :Lexplore
en un atajo para mostrarlo y ocultarlo cuando queramos.
nnoremap <leader>dd :Lexplore %:p:h<CR>
nnoremap <Leader>da :Lexplore<CR>
Leader dd
: Será para abrir Netrw en el directorio del archivo actual.Leader da
: Lo abrirá en el directorio de trabajo actual.
Navegación y visualización
Ahora bien, desafortunadamente no hay una manera directa de crear atajos exclusivos para Netrw. Es posible hacerlo pero necesitamos hacer algunas cosas primero.
Netrw es plugin que define su propio tipo de archivo, así que vamos a usar eso para crear una función que pueda asignar los atajos que nosotros queramos. Para ser específico, lo que haremos será crear un autocommand
que llame una función cada vez que vim abra un archivo de tipo netrw
.
function! NetrwMapping()
endfunction
augroup netrw_mapping
autocmd!
autocmd filetype netrw call NetrwMapping()
augroup END
Con esto en nuestra configuración lo que queda por hacer es colocar nuestros atajos en la función NetrwMapping
. Así.
function! NetrwMapping()
nmap <buffer> H u
nmap <buffer> h -^
nmap <buffer> l <CR>
nmap <buffer> . gh
nmap <buffer> P <C-w>z
nmap <buffer> L <CR>:Lexplore<CR>
nmap <buffer> <Leader>dd :Lexplore<CR>
endfunction
Ya que no tenemos acceso a los comandos que usa Netrw internamente (al menos no todos), usamos nmap
para hacer una especie de redirección. Por ejemplo, aquí H
será equivalente a presionar u
, que a su vez activará la función que queremos. Entonces tenemos que:
H
: Ahora será para "ir atrás" en el historial.h
: Será para "ir arriba" un directorio.l
: Será para abrir un directorio o archivo..
: Controlará si se muestran los archivos ocultos.P
: Para ocultar la ventana de la vista previa.L
: Abrirá un archivo y cerrará la ventana de Netrw.Leader dd
: Sólo cerrará la ventana de Netrw.
Con sólo agregar estos atajos (más la configuración recomendada) Netrw se convierte en un navegador decente. Pero esperen, aún podemos mejorar.
Marcas
Podemos encontrar una manera más cómoda de manejar las marcas de los archivos. Yo sugiero usar <Tab>
para esto.
nmap <buffer> <TAB> mf
nmap <buffer> <S-TAB> mF
nmap <buffer> <Leader><TAB> mu
Tab
: marcará (o quitará una marca) de un archivo o directorio.Shift Tab
: Quitará las marcas de todos los archivos listados en la pantalla actual.Leader Tab
: Quitará todas las marcas.
Gestión de archivos
Ya que hay un montón de comandos relacionados con los archivos vamos a usar la letra f
como prefijo para agruparlos.
nmap <buffer> ff %:w<CR>:buffer #<CR>
nmap <buffer> fe R
nmap <buffer> fc mc
nmap <buffer> fC mtmc
nmap <buffer> fx mm
nmap <buffer> fX mtmm
nmap <buffer> f; mx
ff
: Para crear un archivo. Crearlo de verdad. En esta ocasión, después de%
usamos:w<CR>
para guardar el archivo vacío y:buffer #<CR>
para volver a Netrw.fe
: Para renombrar un archivo.fc
: Para copiar los archivos marcados.fC
: Lo usaremos para ahorranos un paso. Con esto podremos situarnos sobre un directorio y copiar los archivos marcados directamente.fx
: Para mover los archivos marcados.fX
: Tiene la misma mecánica quefC
pero esta vez será para mover archivos.f;
: Lo usaremos para ejecutar comandos externos sobre los archivos marcados.
Aún podemos hacer un par de cosas, si no les importa usar algunas variables internas de Netrw.
Ver la lista de archivos marcados.
nmap <buffer> fl :echo join(netrw#Expose("netrwmarkfilelist"), "\n")<CR>
Mostrar el directorio destino, en caso de que queramos evitar mostrar el banner.
nmap <buffer> fq :echo 'Target:' . netrw#Expose("netrwmftgt")<CR>
Ahora podemos usar el atajo anterior en conjunto con mt
para asignar el directorio destino.
nmap <buffer> fd mtfq
De nuevo, esto sólo es útil si queremos evitar a toda costa mostrar el banner.
Bookmarks
En el mismo estilo en el que agrupamos la gestión de archivos podemos hacerlo con los "Bookmarks".
nmap <buffer> bb mb
nmap <buffer> bd mB
nmap <buffer> bl gb
bb
: Para crear un bookmark.bd
: Para eliminar el bookmark más reciente.bl
: Para saltar al directorio del bookmark más reciente.
Eliminando archivos de manera recursiva
Lo último que haremos será "automatizar" el proceso para eliminar un directorio no vacío. Para esto necesitaremos una función.
function! NetrwRemoveRecursive()
if &filetype ==# 'netrw'
cnoremap <buffer> <CR> rm -r<CR>
normal mu
normal mf
try
normal mx
catch
echo "Canceled"
endtry
cunmap <buffer> <CR>
endif
endfunction
En esta función lo primero que hacemos es asegurarnos de que estamos dentro de un archivo de tipo netrw
. Lo siguiente que hacemos es preparar el comando para eliminar. Nos aprovechamos del hecho de que vim nos obliga a entrar en modo de comando y creamos un atajo (<CR>
) que escribirá el comando para eliminar archivos por nosotros. Luego con normal mu
limpiamos la lista de archivos marcados (no queremos borrar nada por accidente). Marcamos el directorio que está debajo del cursor con normal mf
. Aquí viene lo gracioso, normal mx
nos preguntará qué comando queremos ejecutar, es en este punto donde podemos abortar el proceso usando ctrl + c
o presionar Enter
lo que causará que vim escriba rm -r
y ejecute el comando. Por último desechamos el atajo que creamos al principio de la función, porque sería muy inconveniente tenerlo de forma permanente.
¿Y cómo la usamos?
Dentro de NetrwMapping
creamos otro atajo.
nmap <buffer> FF :call NetrwRemoveRecursive()<CR>
Pueden visualizar todas las opciones y funciones presentadas en este artículo: aquí.
Conclusión
Netrw puede que no sea el mejor gestor de archivos en el ecosistema de vim pero con un poco de configuración podemos por lo menos convertirlo navegador de archivos intuitivo. Incluso si deciden no adoptar Netrw en su rutina diaria no viene mal aprender lo básico para poder navegar fácilmente entre directorios. Nunca saben cuando estarán varados en servidor remoto usando vim sin sus plugins favoritos a mano.
Fuente
¿Tienen alguna pregunta? Pueden dejar un comentario en cualquiera de estas plataformas:
Pueden contactarme por las redes sociales:
- Twitter @VonHeikemen_
- Bluesky @vonheikemen.bsky.social
- Mastodon @vonheikemen@hachyderm.io
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 buy me a coffee ☕.