Configuración de EMACS para programadores (I)

Copyright (c) 2003 Eduardo Ferro bajo GNU FDL

Emacs es uno de los editores más conocidos en el entorno UNIX y dejando de lado las guerras santas Emacs vs Vi, ha demostrado ser uno de los editores preferidos para la programación en esos entornos.
Para la edición cómoda de ficheros fuente se suelen requerir a los editores las siguientes funcionalidades:

Ni que decir tiene que emacs cuenta con estas y otras funcionalidades, por lo que en este artículo voy a intentar describir la forma de activar y usar todas y cada una de las funcionalidades indicadas. No vamos a tratar en este artículo el uso básico de emacs puesto que sobre ese tema existen muy buenas referencias en Internet y además daría para escribir no uno sino varios libros, así que supongo los conceptos básicos de emacs (buffers, modos, cortar, pegar, ayuda, etc) son conocidos.

Configuración básica de EMACS

Actualmente emacs cuenta con dos sistemas para la configuración de su funcionamiento. Por una parte se puede escribir la configuración en un fichero de configuración que lee en el arranque, por otra parte se puede usar (en las versiones más modernas) una funcionalidad conocida como "Customize". Esta funcionalidad permite cambiar la mayor parte de las variables de configuración de emacs desde la opción de menú Options->Customize, aunque la configuración generada termina escribiéndose en el fichero de configuración.
En cualquier caso, nosotros nos vamos a centrar en la configuración mediante edición directa del fichero de configuración, que es la forma más rápida de configurarlo.

Emacs usa como fichero de configuración por defecto el fichero ".emacs" en el directorio del usuario ($HOME/.emacs). Emacs utiliza para su configuración y extensión un dialecto del lisp conocido como EmacsLisp o más comúnmente elisp. El fichero .emacs es simplemente un fichero de código elisp que emacs carga en su arranque, por lo que un conocimiento somero de elisp será muy conveniente para el uso avanzado de emacs. Por ahora nos bastará con saber que las sentencias van encerradas entre paréntesis, y que todo lo que siga a un ";" hasta el final de la línea será considerado comentario.

En los siguientes apartados vamos a ir describiendo sentencias de elisp, que introducidas en nuestro fichero de configuración .emacs nos ayudarán a la hora de editar ficheros fuentes.

Configuraciones generales

En los siguientes párrafos voy a describir una serie de configuraciones generales, que en muchos casos no sólo afectan a los modos de programación, sino que sirven para todos los modos de edición.

Para activar el realzado de las coincidencias encontradas hasta el momento en las búsquedas, debemos poner las siguientes sentencias:

(setq search-highlight t)
(setq query-replace-highlight t)

Antes de poder realizar configuraciones sobre el comportamiento de los modos C y C++ debemos introducir en el fichero de configuración la siguiente sentencia:

(require 'cc-mode) ; modo para C/C++
Cuando escribimos un fichero fuente o cuando escribimos un fichero de texto suele ser interesante que el editor decida cuando no caben más palabras en en la línea actual y pase a la siguiente. Esta funcionalidad en emacs se conoce como "auto-fill". Con la siguiente sentencia indicamos que la columna donde deben terminar las líneas es la 77 y que debe activar el modo "auto-fill" para todos los modos derivados del modo de texto y en los modos para C y C++:
(setq default-fill-column 77)
(add-hook 'text-mode-hook 'turn-on-auto-fill)
(add-hook 'c++-mode-hook 'turn-on-auto-fill)
(add-hook 'c-mode-hook 'turn-on-auto-fill)
Por defecto en emacs, si vamos al final del fichero y pulsamos el cursor para ir hacia abajo emacs introduce un salto de linea, pero a veces este comportamiento no es el deseado. Con la siguiente sentencia podemos evitarlo:
; no añade lineas vacías al final
(setq next-line-add-newlines nil)
Suele ser interesante en los lenguajes de programación que cuando cerremos una llave o paréntesis, emacs nos señale a qué llave o paréntesis de apertura se corresponde. Para ello debemos introducir en el fichero de configuración la siguiente sentencia:
; Para que se marquen los paréntesis y 
; y las llaves
(require 'paren)  
En muchos lenguajes de programación el sangrar las líneas de forma correcta es fundamental para su correcta legibilidad y su facilidad de mantenimiento. Por ello, es muy importante realizar un sangrado del código correcto. El sangrado del código se puede realizar mediante la inserción de tabuladores o la inserción de espacios en blanco. Cualquiera de las dos soluciones es adecuada, pero desgraciadamente es muy posible, que sin querer, mezclemos las dos, en cuyo caso el fichero fuente sólo se vería bien si tenemos la tabulación configurada al mismo tamaño que el que editó el fichero. Para solucionar este problema lo que se suele hacer es utilizar espacios, pero dejar que sea emacs el que decida cuántos espacios se deben utilizar. Las siguientes líneas configuran emacs para que inserte siempre espacios y para que en los modos de C y C++ el tabulador sangre la línea actual (utilizando espacios), excepto en el caso de que estemos dentro de cadenas literales:
; No sangra si estamos en literales
(setq c-tab-always-indent "other") 
; Espacios en vez de tabuladores
(setq-default indent-tabs-mode nil)

Realzado de sintaxis mediante colores

Emacs permite el realzado de sintaxis mediante colores para gran cantidad de lenguajes de programación, para activarlo necesitamos introducir en el fichero de configuración las siguientes lineas:
;; Coloreado automático de sintaxis para todos los modos reconocidos
(global-font-lock-mode t)
(setq font-lock-support-mode 'lazy-lock-mode)
; No existe tamaño máximo de buffer para 
; colorear los buffers
(setq font-lock-maximum-size nil)       
(require 'font-lock)
(require 'lazy-lock)
Realmente, la única sentencia necesaria es (global-font-lock-mode t), que activa el modo de realzado automático mediante colores, el resto de líneas indican que por defecto se use el modo "vago" (lazy-lock-mode) es decir que no esté todo el rato verificando la sintaxis para realzarla porque consume demasiados recursos (y el modo "vago" es suficientemente bueno). También le indicamos que aunque el fichero sea muy grande realice el coloreado aunque tarde un poco más.

Emacs tiene una gran cantidad de configuraciones relacionadas con el realzado de sintaxis mediante colores. Se pueden configurar cada uno de los colores usados para cada tipo de entidad (palabras clave, comentarios, funciones, variables, etc) e incluso configurar nuevas entidades, pero no nos vamos a meter con ello, porque la configuración por defecto es bastante buena.

Auto sangrado (auto tabulación)

Como he comentado anteriormente, es bastante útil permitir que sea emacs quien decida el sangrado ("tabulado") de cada una de las líneas. Para ello, en el apartado de Configuraciones generales hemos indicado como configurar emacs para que se utilicen espacios en vez de tabuladores y que la tecla TAB realice el sangrado automático de la línea actual.

Además es muy útil indicar a emacs que cuando terminamos una sentencia mediante un retorno de carro, lo que queremos hacer es saltar a la siguiente línea y realizar el sangrado, de forma que el cursor quede preparado para insertar la siguiente sentencia en el sitio correcto. Este comportamiento lo conseguimos con las siguientes sentencias:

; Retorno de carro cambia de línea y realiza el sangrado
; en la siguiente linea
(define-key c-mode-map "\C-m" 'newline-and-indent)
(define-key c++-mode-map "\C-m" 'newline-and-indent)
Cuando veamos que emacs ha sangrado algo aparentemente mal deberemos repasar la sintaxis de las líneas anteriores, porque lo más probable es que tengamos un error de sintaxis en el fichero. Lo que podemos hacer, en caso de que nos cueste ver el error, es subir hasta la ultima línea que este correctamente sangrada y desde allí ir bajando poco a poco pulsando tabulador (para sangrar la línea) hasta que veamos qué línea es la que se sangra mal. Esa línea o la anterior será la que contenga el error de sintaxis. Como podéis ver, esta funcionalidad no sólo nos permite hacer nuestro código más legible (y por tanto de mejor calidad), sino que además nos ayuda a encontrar pequeños problemas sintácticos.

En algunos, casos es posible que necesitemos sangrar una región, por ejemplo porque hemos pegado código desde otro sitio y no ha quedado con el sangrado correcto. En estos casos, debemos utilizar el comando de sangrado de una región Alt-x indent-region, una vez tengamos seleccionada la región a sangrar.
Si estamos programando en C o C++ también podemos usar el comando Alt-x c-indent-defun, que se encargará del sagrado de la función o método en el que estemos. Esta función suele estar asignada a la combinación de teclas Ctrl-c Ctrl-q.

Auto expansión de texto.

Tanto para la programación como para la edición de cualquier tipo de texto, es muy habitual que existan multitud de palabras que repitamos de forma casi continua. Para ayudarnos a la escritura de estas palabras, los editores suelen tener sistemas de auto expansión de texto.
Emacs tiene varios sistemas para expansión automática de palabras, pero aquí vamos a describir someramente solo uno de ellos, el conocido como expansión de abreviaturas dinámicas. Este sistema es muy cómodo porque no nos obliga a que manualmente definamos las abreviaturas y las expansiones, sino que simplemente intenta completar la palabra actual con las palabras que hemos escrito anteriormente.
Para asignar esta funcionalidad a una combinación de teclas, debemos poner la siguiente sentencia en el fichero de configuración:
(define-key global-map [(control return)] 'dabbrev-expand)
Siendo "control return" la combinación de teclas elegida para la expansión. Para hacer uso de esta funcionalidad, simplemente debemos escribir al menos tres letras de la palabra que queremos escribir y pulsar Ctrl-Return repetidamente hasta que demos con la expansión que queremos.
Está funcionalidad es fundamental para programar, puesto que repetimos muchísimas veces los nombres de funciones, clases, variables, etc. Además, al completarlas automáticamente, hay menos posibilidad de que nos equivoquemos y nos dará menos pereza escribir nombres de variables y funciones largos y descriptivos.

Emacs también permite la definición manual de abreviaturas mediante el modo "abbrev-mode" (ver manual de emacs).

Selección sencilla de fuentes.

Cuando estamos programando, en muchos casos, sobre todo si usamos lenguajes orientados a objetos, solemos necesitar tener abiertos varios ficheros de forma simultánea y movernos de forma cómoda entre ellos.
Emacs permite editar varios buffers de forma simultánea y cambiar entre ellos, pero para la programación es conveniente tener una forma más sencilla de saber qué contenidos (qué clases, qué métodos) tiene cada uno de los ficheros y poder movernos entre ellos.

Una de las posibilidades es usar el navegador de objetos y ficheros llamado speedbar. Para ello debemos introducir la siguiente línea en el fichero de configuración:

(require 'speedbar)
Y luego una vez estemos ejecutando emacs podremos ejecutar el navegador introduciendo Alt-x speedbar. Una vez ejecutemos este comando, nos aparecerá una nueva ventana de emacs con todos los ficheros y directorios del directorio actual. El navegador Speedbar muestra la información en forma de árbol, cada nodo se puede expandir o contraer, en caso de que el nodo que expandamos sea de un fichero nos aparecerán cada una de las clases, métodos o funciones que hayamos definido en ese fichero.
Cuando seleccionamos un nodo en el navegador, emacs se posicionará en el buffer indicado por el navegador, es más si lo que seleccionamos es un método, en ese caso emacs nos posicionará en el comienzo de ese método.

Según editamos los ficheros fuente, el navegador ira analizándolos para poder ir actualizando la lista de ficheros y nodos, pero en algunos casos el speedbar tardará en actualizarse por lo que es posible que no siempre este completamente sincronizado.

Plantillas para estructuras repetitivas.

Cada lenguaje de programación tiene una serie de construcciones para hacer bucles, condicionales, o definir una clase, que se usan muy a menudo y de forma recurrente. Es una buena idea automatizar este tipo de estructuras de forma que tardemos menos en introducirlas y que disminuyamos la posibilidad de introducir errores al teclear.
Emacs tiene varios sistemas de crear plantillas, pero sólo voy a explicar la creación de plantillas mediante el módulo "tempo" que es bastante sencillo.
Las plantillas del módulo "tempo" son expresiones elisp definidas utilizando unas funciones proporcionadas por el módulo.
Las plantillas con tempo se crean usando la función tempo-define-template, esta función tiene como primer parámetro el nombre de la plantilla, como segundo la propia plantilla, como tercero la cadena que se debe expandir, como cuarto parámetro una cadena con la descripción de la plantilla y por ultimo el nombre de la tabla de plantillas donde queremos definirla (esto es necesario porque podríamos querer tener distintas plantillas con el mismo nombre en diferentes tablas).
Voy a explicar cada uno de los parámetros con una plantilla de ejemplo:
(tempo-define-template "c-if"
		       '(> "if (" p ")"  n> 
			 "{" > n
                         > p n 
			 "}" > n>
			 )
		       "if"
		       "Inserta un if de c/c++"
		       'c-tempo-tags)
Esta plantilla tiene como nombre "c-if", la cadena a expandir es "if" y se introduce en la tabla de plantillas "c-tempo-tags".
Pasemos ahora a explicar el segundo parámetro, que es el que realmente define la plantilla.
Como se puede ver, el segundo parámetro está compuesto por una serie de expresiones dentro de "'()". Dentro de esa cadena, las partes entrecomilladas se introducirán directamente cuando expandamos la plantilla y el resto son comandos, que tienen el siguiente significado: Como se puede ver, se pueden crear de esta forma plantillas para las estructuras de control típicas de cualquier lenguaje de programación (if, for, switch, etc). En este caso se ha puesto como cadena a expandir la cadena "if" pero se puede poner cualquier otra cadena de la que nos acordemos fácilmente.

Con las siguientes sentencias en el fichero de configuración preparamos todo lo necesario para poder crear plantillas para los modos C y C++:

(require 'tempo)
(setq tempo-interactive t)
(defvar c-tempo-tags nil
  "tabla de plantillas tempo para el modo C")
(defvar c++-tempo-tags nil
  "tabla de plantillas tempo para el modo C++")

; Asignamos la tabla de plantillas para C/C++  a los
; modos de C y C++
(add-hook 'c-mode-hook '(lambda ()
			  (tempo-use-tag-list 'c-tempo-tags)
			  ))
(add-hook 'c++-mode-hook '(lambda ()
			    (tempo-use-tag-list 'c-tempo-tags)
			    (tempo-use-tag-list 'c++-tempo-tags)
			    ))
Después de este código para la creación de las tablas y la carga de las mismas, podemos introducir en el fichero de configuración las plantillas que hayamos definido.

Para usar las plantillas, mientras estemos programando, deberemos introducir una de las cadenas que hemos definido para la expansión, por ejemplo "if" y sin mover el cursor introducir Alt-x tempo-expand-if-complete, con ello se expandirá la plantilla y podremos movernos entre las marcas de inserción definidas utilizando los comandos Alt-x tempo-forward-mark y Alt-x tempo-backward-mark.
Lo normal, es asignar combinaciones de teclas en el fichero de configuración para estas funciones. Por ejemplo, podemos realizar las siguientes asignaciones para los modos C y C++:

(define-key c++-mode-map
            [(control shift return)]
            'tempo-expand-if-complete)
(define-key c-mode-map
            [(control shift return)]
            'tempo-expand-if-complete)
(define-key c++-mode-map
            [(control shift left)]
            'tempo-backward-mark)
(define-key c-mode-map
            [(control shift left)]
            'tempo-backward-mark)
(define-key c++-mode-map
            [(control shift right)]
            'tempo-forward-mark)
(define-key c-mode-map
            [(control shift right)]
            'tempo-backward-mark)

Conclusiones

Emacs es un editor muy adecuado para el día a día de un programador, puesto que es muy flexible y permite automatizar un motón de tareas. El único problema que tiene, es que para realizar una configuración adecuada del mismo, es necesario tener unos conocimientos aunque sea básicos del lenguaje de programación elisp.
En cualquier caso, creo que merece la pena dedicar un poco de tiempo a crearnos un entorno de trabajo cómodo, que nos ayude ha hacer las tareas diarias más sencillas y con menos errores.
Un articulo se queda muy corto para explicar las funcionalidades de emacs que pueden venir bien a un programador. Se han quedado muchas cosas en el tintero (otros sistemas de plantillas, integración con compiladores y depuradores, etc).

Mantenga su cordura aún programando

Suelen decir que los informáticos en general y los programadores en particular estamos un poco locos, por lo que lo mejor es que después de una larga jornada de programación hablemos un poco con el psiquiatra para conseguir de esta forma mantenernos cuerdos. Incluso para esto emacs provee soluciones ya que integra su propio psiquiatra, para activarlo debemos introducir Alt-x doctor

Referencias

Página principal de emacs http://www.gnu.org/software/emacs/emacs.html
Introducción a Emacs lisp http://www.gnu.org/manual/emacs-lisp-intro/emacs-lisp-intro.html

Feichero de configuración

Ejemplo de
fichero de configuración donde se ponen en práctica las configuraciones comentadas.

Si quieres ponerte en contacto conmigo:

eferro@inicia.es