;; Introduccion a Emacs Lisp en 15 minutos (v0.2d);;;; Autor: Bastien / @bzg2 / http://bzg.fr;; Traducción: Guillermo Vayá / @Driadan / http://willyfrog.es;;;; Antes de nada, lee este texto de Peter Norvig:;; Traducido: http://loro.sourceforge.net/notes/21-dias.html;; Original: http://norvig.com/21-days.html;;;; Ahora instala GNU Emacs 24.3:;;;; Debian: apt-get install emacs ;; (o sigue las instrucciones de tu distribución preferida);; OSX: http://emacsformacosx.com/emacs-builds/Emacs-24.3-universal-10.6.8.dmg;; Windows: http://ftp.gnu.org/gnu/windows/emacs/emacs-24.3-bin-i386.zip;;;; Puedes encontrar información general sobre Emacs en:;; http://www.gnu.org/software/emacs/#Obtaining;; Aviso importante:;;;; Seguir este tutorial no provocará daños en tu ordenador a menos que;; te enfades tanto que que acabes tirándolo al suelo. En tal caso ;; declino cualquier responsabilidad. ¡A divertirse!;; "N. del. T.": Algunos términos comunes de la informática se han dejado ;; sin traducir ya que es mucho más probable que el lector los conozca en ;; su forma en inglés, siendo la versión en español de muy raro uso.;; Además "sexps" se ha decidido traducir por sexpresión.;; Por último, añadir que no se han traducido los ejemplos de código ya que no ;; es necesario entender qué dice el string para comprender el funcionamiento;; y podría llevar a error.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Inicia Emacs.;;;; Pulsa la tecla `q' para pasar el mensaje de bienvenida.;;;; Mira a la línea gris en la parte inferior de la ventana:;;;; "*scratch*" es el nombre del espacio editable donde estás.;; A este espacio editable se le llama "buffer".;;;; Scratch es el buffer por defecto cuando abres Emacs.;; En Emacs nunca editas ficheros, sino que editas buffers que ;; posteriormente pueden grabarse a un fichero.;; can save to a file.;; ;; "Lisp interaction" indica el conjunto de ordenes disponibles.;; ;; Emacs dispone de un set de comandos disponibles en cualquier buffer;; ("built-ins") y aparte varios conjuntos de ordenes disponibles ;; según el modo específico que esté activo. En nuestro caso ;; estamos usando `lisp-interaction-mode', el cual incluye las;; ordenes necesarias para evaluar y navegar código Elisp.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Un punto y coma comienza un comentario. Pueden ponerse en cualquier ;; posicion de la linea.;;;; Los programas en Elisp se componen de expresiones simbólicas;; tambien llamadas "sexps":(+ 22);; Esta expresión simbólica se lee tal que "Suma 2 y 2";; Las sexpresiones se rodean por paréntesis, y pueden anidarse:(+ 2(+ 11));; Una expresion simbólica está formada bien por átomos o bien por otras ;; expresiones simbólicas. En el ejemplo de arriba, 1 y 2 son átomos, ;; mientras que (+ 2 (+ 1 1)) y (+ 1 1) son expresiones simbólicas.;; Gracias a `lisp-interaction-mode' puedes evaluar las sexpresiones.;; Coloca el cursor justo despues del paréntesis de cierre y ;; mantén pulsada la tecla Control y la j (para abreviar usaremos "C-j").(+ 3(+ 12));; ^ pon aquí el cursor;; `C-j' => 6;; `C-j' añade el resultado de la evaluación al buffer.;; `C-xC-e' muestra el mismo resultado pero en la linea inferior;; la cual se llama "minibuffer". Este será el metodo que usaremos ;; normalmente para no llenar el buffer con texto inútil.;; `setq' guarda un valor en una variable:(setqmy-name"Bastien");; `C-xC-e' => "Bastien" (aparece en el mini-buffer);; `insert' añade "Hello!" en el punto donde esté tu cursor:(insert"Hello!");; `C-xC-e' => "Hello!";; Aunque hemos usado `insert' con solo un parámetro "Hello!", se;; pueden pasar más. Por ejemplo, en esta otra sexpresión usamos dos:(insert"Hello"" world!");; `C-xC-e' => "Hello world!";; Se pueden usar variables en lugar de strings:(insert"Hello, I am "my-name);; `C-xC-e' => "Hello, I am Bastien";; Puedes combinar sexpresiones en funciones:(defunhello()(insert"Hello, I am "my-name));; `C-xC-e' => hello;; Evaluemos la funcion:(hello);; `C-xC-e' => Hello, I am Bastien;; Los parentesis vacios en la definicion de una funcion indican;; que no acepta parámetros. En cualquier caso, usar `my-name' siempre;; es aburrido, asi que vamos a hacer que la función accepte un parámetro;; (en este caso el parametro se llama "name"):(defunhello(name)(insert"Hello "name));; `C-xC-e' => hello;; Ahora vamos a llamar a la funcion con el string "you" como valor para ;; el único parámetro que posee.(hello"you");; `C-xC-e' => "Hello you";; ¡Genial!;; Descansa un poco y respira.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Ahora cambiaremos al nuevo buffer, llamado "*test*", en una nueva ventana.(switch-to-buffer-other-window"*test*");; `C-xC-e';; => [La pantalla ahora tiene dos ventanas y el cursor está en el buffer *test*];; Mueve el ratón sobre la ventana superior y pulsa el boton izdo. para volver. ;; Otra forma es usando `C-xo' (pulsa simultaneamente control y x y luego la o);; para ir a la otra ventana.;; Se pueden combinar varias sexpresiones mediante `progn':(progn(switch-to-buffer-other-window"*test*")(hello"you"));; `C-xC-e';; => [De las dos ventanas de la pantalla, el cursor está en la marcada como *test*];; A partir de ahora, si no te importa, dejaremos de decir que pulses `C-xC-e': ;; tendrás que hacerlo para ejecutar cada sexpresión que siga.;; También tendrás que volver al buffer *scratch* bien con el ratón o con `C-xo'.;; En ocasiones será util limpiar el buffer:(progn(switch-to-buffer-other-window"*test*")(erase-buffer)(hello"there"));; O volver a la ventana anterior:(progn(switch-to-buffer-other-window"*test*")(erase-buffer)(hello"you")(other-window1));; Puedes enlazar un valor a una variable local con `let':(let ((local-name"you"))(switch-to-buffer-other-window"*test*")(erase-buffer)(hellolocal-name)(other-window1));; En este caso, no hace falta añadir `progn' ya que `let' permite combinar ;; varias sexpresiones.;; Vamos a darle formato a un string:(format"Hello %s!\n""visitor");; Cada %s indica la posicion donde irá un string, el cual será reemplazado ;; por "visitor". "\n" es el caracter de nueva línea.;; Mejoremos nuestra funcion usando `format':(defunhello(name)(insert(format"Hello %s!\n"name)))(hello"you");; Creemos una nueva funcion que utililce `let':(defungreeting(name)(let ((your-name"Bastien"))(insert(format"Hello %s!\n\nI am %s."name; the argument of the functionyour-name; the let-bound variable "Bastien"))));; Y ahora la evaluamos:(greeting"you");; Algunas funciones son interactivas:(read-from-minibuffer"Enter your name: ");; Al evaluar esta función, ésta devuelve lo que hayas introducido.;; Ahora hagamos nuestra función `greeting' preguntar por tu nombre:(defungreeting(from-name)(let ((your-name(read-from-minibuffer"Enter your name: ")))(insert(format"Hello!\n\nI am %s and you are %s."from-name; the argument of the functionyour-name; the let-bound var, entered at prompt))))(greeting"Bastien");; Y ahora la completamos mostrando el resultado en la otra ventana:(defungreeting(from-name)(let ((your-name(read-from-minibuffer"Enter your name: ")))(switch-to-buffer-other-window"*test*")(erase-buffer)(insert(format"Hello %s!\n\nI am %s."your-namefrom-name))(other-window1)));; Probémosla:(greeting"Bastien");; Descansa un poco y respira.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Creemos una lista de nombres:(setqlist-of-names'("Sarah""Chloe""Mathilde"));; Para coger el primer elemento de la lista usaremos `car':(car list-of-names);; Para coger todos menos el primer elemento de la lista ;; usaremos `cdr':(cdr list-of-names);; Para añadir un elemento al comienzo de la lista utilizamos `push':(push"Stephanie"list-of-names);; OJO: `car' y `cdr' no modifican la lista, mientras que `push' sí.;; ¡Es una diferencia importante! Algunas funciones no tienen efectos ;; colaterales (como `car') mientras que otras sí (como `push').;; "N. del T.": estos efectos colaterales se les llama `side-effects' en ;; las distintas variantes de lisp.;; Llamemos a `hello' con cada elemento de `list-of-names':(mapcar'hellolist-of-names);; Retocamos `greeting' para que salude a todos los que estén en `list-of-names':(defungreeting()(switch-to-buffer-other-window"*test*")(erase-buffer)(mapcar'hellolist-of-names)(other-window1))(greeting);; ¿Te acuerdas de la función `hello' definida un poco más arriba?;; Recibía un parámetro: `name'. Así que `mapcar' llama a `hello' con cada ;; elemento de `list-of-names' como parámetro de `hello'.;; Ahora ordenaremos un poco lo que tenemos en el buffer:(defunreplace-hello-by-bonjour()(switch-to-buffer-other-window"*test*")(goto-char(point-min))(while(search-forward"Hello")(replace-match"Bonjour"))(other-window1));; (goto-char (point-min)) mueve el cursor al principio del buffer.;; (search-forward "Hello") busca un string "Hello".;; (while x y) evalua la/s sexpresion/es y mientras que x devuelva;; alguna cosa.;; En el momento que x devuelva `nil' (es decir nada), sale del ;; bucle `while'.(replace-hello-by-bonjour);; Observamos que todas las veces que teníamos la palabra "Hello" en el buffer *test*;; han sido reemplazadas por "Bonjour".;; Y además, hemos obtenido un error: "Search failed: Hello".;;;; Para evitar este error, hay que decirle a `search-forward' si debería dejar de ;; buscar en el buffer en algún momento y si debería fallar sin quejarse cuando ;; no encuentra nada.;; (search-forward "Hello" nil t) justo hace eso:;; El argumento `nil' significa que la busqueda no está ligada a ninguna posición.;; Y el argumento `t' le pide que no diga nada si no encuentra el string.;; Usaremos esta sexpresión en la función siguiente, la cual ya ;; no muestra ningún error:(defunhello-to-bonjour()(switch-to-buffer-other-window"*test*")(erase-buffer);; Say hello to names in `list-of-names'(mapcar'hellolist-of-names)(goto-char(point-min));; Replace "Hello" by "Bonjour"(while(search-forward"Hello"nilt)(replace-match"Bonjour"))(other-window1))(hello-to-bonjour);; Añadamos algo de color a los nombres:(defunboldify-names()(switch-to-buffer-other-window"*test*")(goto-char(point-min))(while(re-search-forward"Bonjour \\(.+\\)!"nilt)(add-text-properties(match-beginning1)(match-end1)(list 'face'bold)))(other-window1));; Esta función nos presenta `re-search-forward': en vez de ;; buscar el string "Bonjour" exacto, se busca por un patrón;; usando una "expresión regular" (lo cual se muestra abreviado ;; en el prefijo "re-" del inglés "Regular Expression").;; La expresión regular a utilizar es "Bonjour \\(.+\\)!" y se traduce como:;; el string "Bonjour ", seguido de ;; un grupo de | representado por \\( ... \\);; cualquier caracter | representado por .;; al menos una vez | representado por +;; y el string "!".;; ¿Preparado? ¡Probemoslo!(boldify-names);; `add-text-properties' añade propiedades al texto, como una fuente.;; ¡Hale! ¡Ya lo tenemos! ¡Feliz hacking!;; Si quieres saber más sobre una función o una variable:;;;; C-h v la-variable RET;; C-h f la-funcion RET;;;; Si quieres leer el manual de Emacs Lisp desde dentro de Emacs:;;;; C-h i m elisp RET;;;; Para leer una introducción en linea de Emacs Lisp:;; https://www.gnu.org/software/emacs/manual/html_node/eintr/index.html;; Me gustaría agradecer a las siguientes personas su feedback y sugerencias:;; - Wes Hardaker;; - notbob;; - Kevin Montuori;; - Arne Babenhauserheide;; - Alan Schmitt;; - LinXitoW;; - Aaron Meurer