Emacs es tan grande, y tan complejo, que de hecho tiene ¡su propio lenguaje de programación!. No bromeo: para personalizar Emacs ajustándolo a sus necesidades, tiene que escribir programas en este lenguaje. Se llama Emacs Lisp, y es un dialecto de Lisp, así que si tiene experiencia previa en Lisp, le parecerá bastante amistoso. Si no, no se preocupe: no voy a profundizar mucho, porque definitivamente se aprende mejor practicando. Para aprender realmente a programar Emacs, deberá consultar las páginas de información de Emacs Lisp, y leer mucho código fuente de Emacs Lisp.
La mayor parte de la funcionalidad de Emacs está definida en archivos de código de Emacs Lisp9. La mayoría de estos archivos se distribuyen con Emacs y colectivamente son conocidos como la "Biblioteca de Emacs Lisp". La ubicación de esta biblioteca depende de cómo se instaló Emacs en su sistema, son ubicaciones comunes /usr/lib/emacs/lisp, /usr/lib/emacs/19.19/lisp/, etc.
El 19.19 es el número de versión de Emacs, y podría ser diferente en su sistema.
No necesita hurgar por su sistema de archivos buscando la biblioteca de lisp, porque Emacs tiene la información almacenada internamente, en una variable llamada load-path (trayectoria de carga). Para averiguar el valor de esta variable, es necesario evaluarla; esto es, hacer que el intérprete de lisp de Emacs consiga su valor. Hay un modo especial para evaluar las expresiones de Lisp en Emacs, llamado modo lisp interactivo (lisp-interaction-mode). Comúnmente, hay un buffer llamado "*scratch*" que está ya en este modo. Si no lo puede encontrar, cree un nuevo buffer con cualquier nombre, y escriba M-x lisp-interaction-mode dentro de él.
Ahora tiene un espacio de trabajo para interactuar con el intérprete Lisp de Emacs. Teclee esto:
load-path
y entonces presione ||_C-j_|| al finalizar. En el modo Lisp interactivo, ||_C-j_|| está ligado a eval-print-last-sexp (evaluar-imprimir-última-sexp). Una "sexp" es una "s-expresion", lo que significa un grupo balanceado de paréntesis, incluido el caso de que no haya ninguno. Bueno, esto es simplificarlo un poco, pero irá entendiendo que son según programe con Emacs Lisp. De cualquier manera, al evaluar load-path debería conseguir algo como esto:
load-path ||_C-j_||
("/usr/lib/emacs/site-lisp/vm-5.35" "/home/kfogel/elithp"
"/usr/lib/emacs/site-lisp" "/usr/lib/emacs/19.19/lisp")
Por supuesto, no tendrá el mismo aspecto en cada sistema, puesto que es dependiente de cómo se instaló Emacs. El ejemplo de arriba viene de mi PC 386 que funciona con Linux. Como indica lo anterior, load-path es una lista de cadenas. Cada cadena nombra un directorio que podría contener archivos de Emacs Lisp. Cuando Emacs necesita cargar un archivo de código Lisp, va buscándolo en cada uno de estos directorios, en orden. Si un directorio se nombra pero no existe en el sistema de archivos, Emacs simplemente lo ignora.
_
9 A veces llamados no oficialmente "Elisp".
Cuando Emacs arranca, automáticamente trata de cargar el archivo .emacs desde su directorio de usuario. Por lo tanto, si quiere hacer personalizaciones en Emacs, deberá ponerlas en .emacs. La personalización más común son las teclas ligadas, así que aquí está cómo hacerlo:
(global-set-key C-cl" 'goto-line)
global-set-key (fijar teclas globalmente) es una función de dos argumentos: la tecla a la que ha de ser ligada, y la función a la que ligarla. La palabra "global" significa que esta tecla ligada tendrá efecto en todos los modos mayores (hay otra función, local-set-key, (fijar teclas localmente), que liga una tecla en un único buffer). Arriba, he ligado |_C-c_l_| a la función goto-line (ir a tal línea).
La tecla se describe usando una cadena. La sintaxis especial C-<carácter>" significa mantener pulsada la tecla |_Control_| mientras se presiona <carácter>. Así mismo, ""M-<carácter>" indica la tecla |_Meta_|.
Todo eso está muy bien, ¿pero cómo supe que el nombre de la función era "goto-line"?. Puedo saber que quiero ligar |_C-c_l_| a alguna función que pregunta por un número de línea y mueve el cursor a esa línea, pero ¿cómo hice para averiguar el nombre de esa función?
Aquí es donde intervienen las facilidades de ayuda de Emacs. Una vez que ha decidido qué tipo de función busca, puede usar Emacs para rastrear su nombre exacto. He aquí una manera rápida y sucia para hacerlo: puesto que Emacs completa los nombres de función, simplemente escriba |_C-h_f_| (que es describe-function (describir función), recuérdelo), y entonces presione |_Tab_| sin escribir nada más. Esto pide a Emacs que complete la cadena vacía _en otras palabras, ¡la terminación automática se corresponderá con cada una de las funciones!. Puede tardar un momento en construir la lista de funciones, ya que Emacs tiene muchas funciones internas, pero mostrará todo lo que entre en la pantalla cuando esté listo.
En este momento presione ||_C-g_|| para abandonar la función describir función. Habrá un buffer llamado "*Completions*", que contiene la lista de terminaciones automáticas que acaba de generar.
Cambie a este buffer. Ahora puede usar |_C-s_|, isearch, para buscar las funciones probables. Por ejemplo, es una suposición segura que una función que pregunta por un número de línea y entonces va a esa línea contendrá la cadena "line (línea)" en su nombre. Por lo tanto, simplemente comience buscando la cadena "line" , y acabará encontrando lo que busca.
Si quiere otro método, puede usar |_C-h_a_|, command-apropos, para mostrar todas las funciones cuyos nombres se ajustan a la cadena dada. La salida de command-apropos es un poco más difícil de clasificar, que simplemente buscar una lista de terminación automática, en mi opinión, pero puede encontrar que tiene distintas sensaciones. Pruebe ambos métodos y a ver que opina.
Siempre existe la posibilidad de que Emacs no tenga ninguna función predefinida para hacer lo que está buscando. En esta situación, tiene que escribir la función Ud. mismo. No voy a hablar de cómo hacer eso, debería buscar en la biblioteca de Emacs Lisp ejemplos de definiciones de función, y leer las paginas Info sobre Emacs Lisp. Si resulta que conoce a un gurú local de Emacs, pregúntele cómo hacerlo. Definir sus propias funciones de Emacs no es un gran asunto, para darle una idea, yo he escrito 131 de ellas durante más o menos el último año. Requiere un poco de práctica, pero la curva de aprendizaje no es empinada.
Otra cosa que la gente hace a menudo en su .emacs es asignar a ciertas variables los valores preferidos. Por ejemplo, ponga esto en su .emacs y entonces inicie un nuevo Emacs:
(setq inhibit-startup-message t)
Emacs verifica el valor de la variable inhibit-startup-message (bloquear mensaje de arranque) para decidir si muestra la información sobre la versión y la falta de garantía cuando arranca. La expresión de Lisp de arriba usa el comando setq para asignar a esa variable el valor `t', que es un valor especial de Lisp que significa true (verdadero). Lo contrario de `t' es `nil' (nada o nulo), que es el valor false (falso) designado en Emacs Lisp. He aquí dos cosas que están en mi |_.emacs_| que podría encontrar útiles:
(setq case-fold-search nil); causa la insensibilidad a mayúsculas y minúsculas para la búsqueda
; ;; Hacer indentar los programas C de la manera que me gusta:
(setq c-indent-level 2)
La primera expresión hace que las búsquedas (incluyendo isearch) sean insensibles a mayúsculas y minúsculas; esto es, la búsqueda encontrará versiones de un mismo carácter sea mayúscula o minúscula aunque la cadena de búsqueda contenga únicamente la versión en minúscula. La segunda expresión establece que la indentación por defecto para las sentencias en lenguaje C sea un poco menor de lo normal, esto es solamente una preferencia personal; encuentro que esto hace el código C más legible.
El carácter de comentario en Lisp es ";". Emacs ignora cualquier cosa que siga a uno de éstos, a menos que aparezca dentro de una cadena literal, como esta:
;;estas dos líneas son ignoradas por el intérprete de Lisp, pero la
; ;; s-expression que le sigue se evaluará totalmente:
(setq alguna-cadena-literal "Una pausa torpe; sin ningún propósito.")
Es una buena idea comentar sus cambios en los archivos Lisp, porque seis meses después no se acordará en qué estaba pensando cuando los modificó. Si el comentario aparece sólo en una línea, precédalo con dos punto y coma. Esto ayuda a Emacs a indentar los archivos Lisp correctamente.
Puede encontrar información sobre las variables internas de Emacs de las mismas formas que con las funciones. Use |_C-h_v_|, describe-variable para hacer una lista de terminación automática, o use |_C-h_C-a_|, apropos. Apropos difiere de |_C-h_a_|, command-apropos, en que muestra variables y funciones en vez de solamente funciones.
La extensión por defecto para los archivos de Emacs Lisp es .el, como en c-mode.el. Sin embargo, para hacer que el código Lisp se ejecute más rápido, Emacs permite que sea byte-compiled (compilado a un formato interno), y estos archivos de código Lisp compilado terminan en .elc en vez de .el. La excepción a esto es su archivo .emacs, que no necesita la extensión .el porque Emacs sabe buscarlo para arrancar.
Para cargar un archivo de código Lisp interactivamente, use el comando M-x load-file (cargar archivo). Le preguntará por el nombre del archivo. Para cargar archivos Lisp desde dentro de otros archivos Lisp, haga esto:
(load "c-mode");fuerza a Emacs a cargar el contenido de c-mode.el o .elc
Emacs añadirá la extensión .elc al nombre del archivo e intentará encontrarlo en algún lugar del load-path. Si falla, lo intenta con la extensión .el; si falla esto, usa la cadena literal tal y como es pasada a load. Puede compilar (byte-compile) un archivo con el comando M-x byte-compile-file, pero si modifica el archivo a menudo, probablemente no merezca la pena. Sin embargo no debería compilar de esa manera su .emacs, ni siquiera darle la extensión .el.
Después de que .emacs se ha cargado, Emacs busca un archivo llamado default.el para cargarlo.
Comúnmente se ubica en un directorio en la trayectoria de carga (load-path) llamado site-lisp o local-elisp o algo parecido (ver el ejemplo load-path que di hace un rato). La gente que mantiene Emacs en un sistema multiusuario usa default.el para hacer cambios que afectarán los Emacs de todos, puesto que todos los Emacs lo cargan después de los .emacs personales. default.el no debería ser compilado, ya que tiende a ser modificado frecuentemente.
Si el .emacs de una persona contiene algún error, Emacs no intentará cargar default.el, sino que simplemente se detendrá, destellando un mensaje diciendo "Error in init file." (Error en el archivo de inicio) o algo similar. Si ve este mensaje, probablemente algo vaya mal con su .emacs.
Hay un tipo más de expresión que a menudo va en un .emacs. La libreria de Emacs Lisp a veces ofrece múltiples paquetes para hacer lo mismo de diferentes formas. Esto significa que tiene que especificar cuál quiere usar (o tendrá el paquete por defecto, que no es siempre el mejor para todos los propósitos). Un área donde esto sucede es en las características de interacción del Scheme de Emacs. Hay dos interfaces diferentes de Scheme distribuidos con Emacs (al menos en la versión 19): xscheme y cmuscheme.
prompt> ls /usr/lib/emacs/19.19/lisp/*scheme*
/usr/lib/emacs/19.19/lisp/cmuscheme.el
/usr/lib/emacs/19.19/lisp/cmuscheme.elc
/usr/lib/emacs/19.19/lisp/scheme.el
/usr/lib/emacs/19.19/lisp/scheme.elc
/usr/lib/emacs/19.19/lisp/xscheme.el
/usr/lib/emacs/19.19/lisp/xscheme.elc
Resulta que el interfaz ofrecido por cmuscheme me gusta mucho más que el que ofrece xscheme, pero el que Emacs usará por defecto es xscheme. ¿Cómo puedo hacer que Emacs actúe de acuerdo con mi preferencia?. Puse esto en mi .emacs:
;; note cómo la expresión puede quebrarse en dos líneas. Lisp
;; ignora los espacios en blanco, generalmente:
(autoload 'run-scheme "cmuscheme"
"Corre un Scheme inferior, de la forma que me gusta." t)
La función autoload (auto carga) toma el nombre de una función (citada con "'", por razones que tienen que ver con cómo funciona Lisp) y le dice a Emacs que esta función está definida en un determinado archivo. El archivo es el segundo argumento, una cadena (sin la extensión .el o .elc) indicando el nombre del archivo a buscar en la trayectoria de carga load-path.
Los argumentos restantes son opcionales, pero necesarios en este caso: el tercer argumento es una cadena de documentación para la función, de modo que si llama a describe-function (describir-función), consigue alguna información útil. El cuarto argumento le dice a Emacs que esta función autocargable puede ser llamada interactivamente (esto es, usando |_M-x_|). Esto es muy importante en este caso, porque uno debería poder teclear M-x run-scheme para comenzar un proceso de scheme que se ejecuta bajo Emacs.
Ahora que run-scheme ha sido definido como una función autocargable, ¿qué sucede cuando tecleo M-x run-scheme?. Emacs mira la función run-scheme, ve que está establecida para ser autocargable, y carga el archivo nombrado por la autocarga (en este caso, cmuscheme). El archivo compilado cmuscheme.elc existe, así que Emacs lo cargará. Ese archivo debe definir la función run-scheme, o habrá un error de autocarga. Por suerte, define run-scheme, así que todo va sin tropiezos, y consigo mi interfaz preferida de Scheme10.
Una autocarga es como una promesa a Emacs, de que cuando llegue el momento, puede encontrar la función especificada en el archivo en el que le dice que mire. A cambio, consigue algún control sobre lo que se carga. También, la autocarga ayuda a reducir el tamaño de Emacs en la memoria, al no cargar ciertas características hasta que se pidan. Muchos comandos no están definidos realmente como funciones cuando Emacs se inicia. Más bien, están simplemente preparados para autocargarse desde cierto archivo. Si nunca invoca el comando, nunca se carga. Este ahorro de espacio es vital para el funcionamiento de Emacs: si cargara todos los archivos disponibles en la biblioteca Lisp, Emacs tomaría veinte minutos simplemente para arrancar, y una vez hecho, podría ocupar la mayor parte de la memoria disponible en su máquina. No se preocupe, no tiene que establecer todas estas autocargas en su .emacs; ya se tomaron en cuenta cuando Emacs se desarrolló.