Descarga el código: learn-emacs-lisp.el
;; 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":
(+ 2 2)
;; Esta expresión simbólica se lee tal que "Suma 2 y 2"
;; Las sexpresiones se rodean por paréntesis, y pueden anidarse:
(+ 2 (+ 1 1))
;; 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 (+ 1 2))
;; ^ 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 "echo area". Este será el metodo que usaremos
;; normalmente para no llenar el buffer con texto inútil.
;; `setq' guarda un valor en una variable:
(setq my-name "Bastien")
;; `C-xC-e' => "Bastien" (aparece en el echo area)
;; `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:
(defun hello () (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"):
(defun hello (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-window 1))
;; Puedes enlazar un valor a una variable local con `let':
(let ((local-name "you"))
(switch-to-buffer-other-window "*test*")
(erase-buffer)
(hello local-name)
(other-window 1))
;; 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':
(defun hello (name)
(insert (format "Hello %s!\n" name)))
(hello "you")
;; Creemos una nueva funcion que utililce `let':
(defun greeting (name)
(let ((your-name "Bastien"))
(insert (format "Hello %s!\n\nI am %s."
name ; the argument of the function
your-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:
(defun greeting (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 function
your-name ; the let-bound var, entered at prompt
))))
(greeting "Bastien")
;; Y ahora la completamos mostrando el resultado en la otra ventana:
(defun greeting (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-name from-name))
(other-window 1)))
;; Probémosla:
(greeting "Bastien")
;; Descansa un poco y respira.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Creemos una lista de nombres:
(setq list-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 'hello list-of-names)
;; Retocamos `greeting' para que salude a todos los que estén en `list-of-names':
(defun greeting ()
(switch-to-buffer-other-window "*test*")
(erase-buffer)
(mapcar 'hello list-of-names)
(other-window 1))
(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:
(defun replace-hello-by-bonjour ()
(switch-to-buffer-other-window "*test*")
(goto-char (point-min))
(while (search-forward "Hello")
(replace-match "Bonjour"))
(other-window 1))
;; (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:
(defun hello-to-bonjour ()
(switch-to-buffer-other-window "*test*")
(erase-buffer)
;; Say hello to names in `list-of-names'
(mapcar 'hello list-of-names)
(goto-char (point-min))
;; Replace "Hello" by "Bonjour"
(while (search-forward "Hello" nil t)
(replace-match "Bonjour"))
(other-window 1))
(hello-to-bonjour)
;; Añadamos algo de color a los nombres:
(defun boldify-names ()
(switch-to-buffer-other-window "*test*")
(goto-char (point-min))
(while (re-search-forward "Bonjour \\(.+\\)!" nil t)
(add-text-properties (match-beginning 1)
(match-end 1)
(list 'face 'bold)))
(other-window 1))
;; 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
¿Tienes una sugerencia o rectificación? Abre un issue en el repositorio de GitHub, o haz un pull request tu mismo
Originalmente contribuido por Bastien Guerry, y actualizado por 3 colaboradores.