Vim: trabajando con ventanas

Una de las ventajas que tiene Vim es el poder trabajar con ventanas y poder ver/editar más de un fichero a la vez, aunque también dispone para poder ir cambiando de buffer viendo un solo fichero a la vez, puede que en ocasiones nos interesa poder ver dos o más ficheros a la vez o incluso poder ver el mismo fichero pero en diferentes partes del mismo.

Iniciando Vim

Podemos iniciar Vim con varios fichero y por defecto veremos el primero, pero si queremos ver todos o parte de ellos podemos utilizar los siguientes parámetros:

  • -o[n] (minúscula)
  • -O[n] (mayúscula)

Abre n ventanas (-o horizontalmente y -O verticalmente), si se omite el valor n abre todos los ficheros que se indiquen. Si el valor de n es mayor que el numero de ficheros indicados abrirá ventanas vacías hasta abrir n ventanas. Si el valor de n es menor que el número de ficheros indicados solo mostrará los n primeros ficheros.

Abriendo ventanas

Si una vez que estemos dentro del Vim y queremos abrir una nueva ventamos podemos usar estas opciones:

  • CTRL-W s
  • CTRL-W CTRL-S
  • :[N]sp[lit] [++opt] [+cmd] [file]

Divide la ventana actual en 2 horizontales, con lo cual podemos ver el mismo fichero en 2 ventanas independientes. N indica el alto en filas de la nueva ventana, por defecto es la mitad, es decir, 2 ventanas de la misma altura. Si se indica un fichero en vez de dividir el fichero actual en 2 abre file en la nueva ventana. NOTA: cuidado con CTRL-S que en algunos S.O. puede bloquearlos, para desbloquear pulsar CTRL-Q.

  • CTRL-W v
  • CTRL-W CTRL-V
  • :[N]vs[plit] [++opt] [+cmd] [file]

Divide la ventana actual en 2 verticales, con lo cual podemos ver el mismo fichero en 2 ventanas independientes. N indica el ancho en columnas de la nueva ventana, por defecto es la mitad, es decir, 2 ventanas de la misma anchura. Si se indica un fichero en vez de dividir el fichero actual en 2 abre file en la nueva ventana.

  • CTRL-W n
  • CTRL-W CTRL_N
  • :[N]new [++opt] [+cmd] [file]

Crea una nueva ventana horizontal. N indica el alto en filas de la nueva ventana, por defecto es la mitad, es decir, 2 ventanas de la misma altura. Si se indica un fichero en vez de dividir el fichero actual en 2 abre file en la nueva ventana.

  • :[N]vne[w] [++opt] [+cmd] [file]

Lo mismo que la anterior pero verticalmente.

Cerrando ventanas

Si una vez que estemos dentro del Vim y queremos cerrar una ventamos podemos usar estas opciones:

  • CTRL-W q
  • CTRL-W CTRL-Q
  • :q[uit][!]

Cierra la ventana actual, para forzar la salida usar la exclamación (!)

  • CTRL-W c
  • :q[uit][!]

Cierra la ventana actual, para forzar la salida usar la exclamación (!). No deja cerrar la última ventana. NOTA: no se puede pulsar CTRL-C ya que cancela la acción.

  • :hid[e]

Oculta la ventana actual, pero sigue abierta y podemos ir más tarde a ella.

  • :on[ly][!]

Cierra todas las ventanas excepto la actual. Las ventanas que estén modificadas no se cierran a menos que se indique la admiración (!).

Moviéndonos entre ventanas

  • CTRL-W <abajo>
  • CTRL-W CTRL-J
  • CTRL-W j

Mueve el cursor a la ventana de abajo.

  • CTRL-W <arriba>
  • CTRL-W CTRL-K
  • CTRL-W k

Mueve el cursor a la ventana de arriba.

  • CTRL-W <izquierda>
  • CTRL-W CTRL-H
  • CTRL-W h

Mueve el cursor a la ventana de la izquierda.

  • CTRL-W <derecha>
  • CTRL-W CTRL-L
  • CTRL-W l

Mueve el cursor a la ventana de la derecha.

  • CTRL-W W
  • CTRL-W w

Mueve el cursor rotando por las ventanas hacia abajo / derecha (w minúscula) o arriba / izquierda (W mayúscula).

Hay mucha más información en la página de ayuda del Vim: Ventanas.

vimdiff: editando 2 ficheros diferentes

En alguna ocasión tenemos 2 ficheros que en principio son iguales pero tienen algunas diferencias, por ejemplo cuando programamos y un fichero lo modificamos  o cuando tenemos un texto y hemos modificado parte o en general cuando queremos comparar dos documentos pero no solo queremos ver las diferencias si no que además queremos ajustar esas diferencias o reducirlas.

Con el comando diff podemos ver las diferencias de 2 ficheros (incluso de más) pero no es mejor ver esas diferencias y poder modificar todo en tiempo real ?

Supongamos que tenemos 1 fichero (extraído de un fichero C):

//----------------------------------------------------------------------------
//      MagnifyEventLoopTimer
//
//      Our magnification timer. Ideally we should be event based, but we can't
//      detect every event that might cause a screen update (window move, etc.)
//      so we resort to this.
//----------------------------------------------------------------------------

pascal void
MagnifyEventLoopTimer(EventLoopTimerRef /*inTimer*/, void *inUserData)
{
        WindowRef       window = (WindowRef)inUserData;
        Point           mouse;
        GrafPtr         windowPort;
        GrafPtr         savePort;
        Rect            sourceRect;
        Rect            destRect;
        Rect            portBounds;
        SInt16          distance;
    static Point        sLastMouse = { -1, -1};

        GetPort( &savePort );
        windowPort = GetWindowPort(window);

        GetPortBounds( windowPort, &portBounds );

al cual vamos a hacer algunas modificaciones:

//----------------------------------------------------------------------------
//      MagnifyEventLoopTimer
//
//      Our magnification timer. Ideally we should be event based, but we can't
//      detect every event that might cause a screen update (window move)
//      so we resort to this.
//----------------------------------------------------------------------------

pascal void
MagnifyEventLoopTimer(EventLoopTimerRef /*inTimer*/, void *inUserData)
{
        WindowRef       window = (WindowRef)inUserData;
        Point           mouse;
        GrafPtr         windowPort;
         Rect            sourceRect;
        Rect            destRect;
        Rect            portBounds;
        SInt            distance;
    static Point        sLastMouse = { -1, -1};

        GetPort( &savePortLocal );
        windowPort =  GetWindowPort(window);

        GetPortBounds( windowPort, &portBounds );

así a simple vista es complicado ver las diferencias, para eso tenemos el comando diff:

5c5
< //      detect every event that might cause a screen update (window move, etc.)
---
> //      detect every event that might cause a screen update (window move)
15,17c15,16
<         GrafPtr         savePort;
<         Rect            sourceRect;
<         Rect            destRect;
---
>          Rect            sourceRect;
>         Rect            destRect;
19c18
<         SInt16          distance;
---
>         SInt            distance;
22,23c21,22
<         GetPort( &savePort );
<         windowPort = GetWindowPort(window);
---
>         GetPort( &savePortLocal );
>         windowPort =  GetWindowPort(window);

aunque al ser código C es mejor verlas así:

@@ -2,7 +2,7 @@
 //      MagnifyEventLoopTimer
 //
 //      Our magnification timer. Ideally we should be event based, but we can't
-//      detect every event that might cause a screen update (window move, etc.)
+//      detect every event that might cause a screen update (window move)
 //      so we resort to this.
 //----------------------------------------------------------------------------

@@ -12,15 +12,14 @@
         WindowRef       window = (WindowRef)inUserData;
         Point           mouse;
         GrafPtr         windowPort;
-        GrafPtr         savePort;
-        Rect            sourceRect;
-        Rect            destRect;
+         Rect            sourceRect;
+        Rect            destRect;
         Rect            portBounds;
-        SInt16          distance;
+        SInt            distance;
     static Point        sLastMouse = { -1, -1};

-        GetPort( &savePort );
-        windowPort = GetWindowPort(window);
+        GetPort( &savePortLocal );
+        windowPort =  GetWindowPort(window);

         GetPortBounds( windowPort, &portBounds );

con lo que vemos que se ha modificado y ahora deberíamos editar los ficheros y modificarlos por separado con nuestro editor favorito que si es vim podemos hacer algo mucho mejor y es ver las diferencias mientras los modificamos con el comando vimdiff:

vimdiff en acción

Lo que vemos con fondo rosa son líneas que tiene alguna diferencia, con fondo azul oscuro línaes que se han añadido, con fondo azul claro líneas que faltan, con fondo rojo los caracteres que cambian.
Como podemos ver en el cuadro de la izquierda tenemos una línea con fondo azul oscuro y en la parte derecha una con azul claro, indicando que hay una línea en la parte izquierda que no está en la derecha. Y con fondo rojo los cambios en un lado y otro.
Aquí estamos en el editor vim así que podemos usar todas las combinaciones de teclas y demás opciones del vim y según vayamos editando se irán comparando los dos ficheros y mostrando las diferencias.
Como recordatorio para pasar de una ventana a otra: control+w dos veces.

VIM: Formateando texto

Teclas Acción
:[linea1,linea2]center ancho Centra las líneas entre linea1 y linea2 (o el bloque marcado visualmente) en un ancho de ancho columnas.
:[linea1,linea2]left margen Alinea a la izquierda las líneas entre linea1 y linea2 (o el bloque marcado visualmente) dejando un margen de margen columnas.
:[linea1,linea2]right ancho Alinea a la derecha las líneas entre linea1 y linea2 (o el bloque marcado visualmente) usando el ancho columnas total.
:set autoindent
:set ai
Auto Tabula las líneas, especialmente útil para escribir script y código.
:set smartindent
:set si.
Auto Tabula de forma inteligente las líneas, especialmente útil para escribir scripts y código.
= Indenta la línea actual.
=i{ o =i} o =iB Tabula el bloque de código entre { y } pero no estos caracteres.
=a{ o =a} o =aB Tabula el bloque de código entre { y } incluyendo estos caracteres.
=i( o =i) o =ib Tabula el bloque de código entre ( y ) pero no estos caracteres.
=a( o =a) o =ab Tabula el bloque de código entre ( y ) incluyendo estos caracteres.
=i< o =i> Tabula el bloque de código entre < y > pero no estos caracteres.
=a< o =a> Tabula el bloque de código entre < y > incluyendo estos caracteres.
=i[ o =i] Tabula el bloque de código entre [ y ] pero no estos caracteres.
=a[ o =a] Tabula el bloque de código entre [ y ] incluyendo estos caracteres.
NOTA: después del = se puede poner un número indicando cuantos bloques anidamos hay y los tabula en concordancia.
:set paste Todo lo que se escriba o pegue no se tabula evitando así el efecto escalera al pegar bloques de texto.
:set nopaste Todo lo que se escriba o pegue se tabula (si está activado), se puede producir el efecto escalera al pegar bloques de texto.

Trucos:

Teclas Acción
yypVr= Crea una línea tipo título (subrayar) debajo de la actual con el carácter ‘=’ (se puede sustituir por # o * o cualquier carácter).
yy : copia la línea actual en el buffer
p : pega la línea copiada en el buffer
V : Selecciona la línea pegada
r : Reemplaza los caracteres seleccionados por el carácter seguido de la ‘r‘ (en este caso ‘=’)
gg=G Reformatea autotabulando todo el texto desde la primera hasta la última línea, perfecto para indentar código no tabulado.
gg : Va a la primera línea del fichero
= : reformatea líneas, es decir, tabula de acuerdo a la configuración de formateo
G : Va hasta la última linea (le dice al VIM cuando parar).

VIM: buscando y reemplazando

Teclas Acción
/quebuscar Busca hacia adelante “quebuscar”.
?quebuscar Busca hacia atrás “quebuscar”.
// Repite la busqueda hacia adelante.
?? Repite la busqueda hacia atrás.
NOTA: Si se activa set incsearch se busca mientras se teclea.
* Busca la palabra (completa) bajo el cursor hacia adelante.
# Busca la palabra (completa) bajo el cursor hacia atrás.
g* Busca la palabra (completa o no) bajo el cursor hacia adelante. Si la palabra es juan, encontrará juan, juanito, etc.
g# Busca la palabra (completa o no) bajo el cursor hacia atrás. Si la palabra es juan, encontrará juan, juanito, etc.
:%s/busca/reemplaza/gc Busca ‘busca‘ y lo reemplaza por ‘reemplaza‘. g significa todas las ocurrencias que haya y c significa preguntar antes de reemplazar.

VIM: moviendose por el fichero

Teclas Acción
h Cursor a la izquierda
l Cursor a la derecha
j Cursor arriba
k Cursor abajo
( Cursor al principio de la frase
) Cursor al final de la frase
{ Cursor al principio del párrafo
} Cursor al final del párrafo
g, Cursor donde se hizo el cambio anterior (hacia arriba).
) Cursor donde se hizo el cambio anterior (hacia abajo).
w Cursor al principio de la siguiente palabra.
b Cursor al principio de la palabra anterior.
e Cursor al final de la palabra.
% Cursor al siguiente bloque del grupo (por ejemplo #if-#else-#endif).
[{ Cursor al principio del bloque.
]} Cursor al final del bloque.
[/ Cursor al principio del bloque de comentario (/* */, //, #).
]/ Cursor al final del bloque de comentario (/* */, //, #).
gd Cursor donde está definida la variable dentro del mismo bloque (hay que estar encima de la variable).
gD Cursor donde está definida la variable desde el principio del fichero (hay que estar encima de la variable)
:bnext
:bn
ctrl+cursor derecha
Salta al siguiente buffer (para que funcione con control se ha de usar: map <C-right> <ESC>:bn<CR>).
:bprevious
:bp
ctrl+cursor izquierda
Salta al buffer anterior (para que funcione con control se ha de usar: map <C-leftt> <ESC>:bp<CR>)

Personalizar VIM y fichero .vimrc

El fichero de configuración del VIM es .vimrc que se puede colocar de forma global (ejecutar dentro de VIM :echo $VIM para saber donde está ubicado) y localmente en la home del usuario. En este fichero podemos personalizar el aspecto y funcionamiento del VIM. Las siguientes opciones se pueden poner en el fichero .vimrc una por línea o ejecutadas dentor del VIM en modo comando (pulsando antes ‘:‘).

Opciones útiles:

  • set nobackup
    no guardar ficheros de backup
  • syntax on
    Activa la sintaxis coloreada según el tipo de fichero de texto.
  • set showmatch
    muestra las coincidencias en los resultados de la búsqueda
  • set ignorecase
    búsqueda sin importar mayúsculas y minúsculas
  • set incsearch
    para ver los primeros resultados de la búsqueda mientras la estás escribiendo
  • set expandtab
    cambia los tabs por espacios
  • set ts=4
    un tab son 4 espacios
  • set autoindent
    Auto indenta, es decir, cuando se pulsa intro se pone el cursor debajo del principio de la línea de arriba.
  • set number
    muestra el número de línea, útil para edición de código.

Corrector ortográfico:

Desde la versión 7 el propio VIM incluye un corrector ortográfico (ya no es necesario usar el spell de Unix ni nada parecido). En caso de que necesitemos algún lenguaje extra (por defecto solo viene inglés) podemos mira en ftp://ftp.vim.org/pub/vim/runtime/spell y copiarlos en el directorio spell donde esté instalado el VIM.

  • set spell
    activa el corrector ortográfico, por defecto está el idioma inglés.
  • set spelllang=es,en
    escoge el idioma español e inglés para el corrector ortográfico, se pueden poner más idiomas separados por comas.
  • set spellsuggest=X
    muestra X sugerencias, por defecto son 5.

Cuando VIM encuentra una palabra mal la marca (por defecto) en texto blanco con fondo negro. Si nos colocamos encima y pulsamos z= (estando en modo normal) nos sacará un listado de sugerencias de palabras.

Cambiando los colores (scheme):

Los schemes no solo cambian los colores de fondo y texto si no que cambian los colores de los errores, avisos, regla, etc, etc.

  • :colorscheme
    para saber los nombres de los schemes que hay disponibles (evidentemente solo se puede ejecutar dentor del VIM).
  • colorscheme nombre
    activa los colores del scheme nombre.

Línea de estado personalizada:

Por defecto VIM tiene una línea de estado muy pobre pero se puede personalizar por completo y hacerla muy útil con diversa información. Para activar y personalizar la línea de estado ejecutamos:

  • set statusline formato

donde “formato” es lo que queremos que muestre. Para saber todas las posibles opciones (y hay muchas) podemos ejecutar desde el VIM :help ’statusline’. Un ejemplo podría ser:

set statusline=%F%m%r%h%w\ [%{&ff}]\ [%Y]\ [HEX=\%02.2B]\ [X=%04l\ Y=%03v]\ [LEN=%L]

Visual cursor:

Aunque es muy bonito y en alguna ocasión muy útil, por lo general es algo incordio y ralentiza el scroll por lo que no es aconsejable usarlo.

  • set cursorline
    pone una línea horizontal en la posición del cursor.
  • set cursorcolumn
    pone una columna en la posición del cursor.
  • highlight CursorLine guibg=lightblue ctermbg=lightgray
    cambia el color de la línea del cursor.