Baixar o código: learn-emacs-lisp.el
;; Introdução ao Emacs Lisp em 15 minutos (v0.2d)
;;
;; Autor: Bastien / @bzg2 / http://bzg.fr
;;
;; Antes de começar, leia este texto escrito Peter Norvig:
;; http://norvig.com/21-days.html
;;
;; Agora instale GNU Emacs 24.3:
;;
;; Debian: apt-get install emacs (ou veja as instruções da sua distribuição)
;; 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
;;
;; Informações mais gerais podem ser encontradas em:
;; http://www.gnu.org/software/emacs/#Obtaining
;; Aviso importante:
;;
;; Realizar este tutorial não danificará seu computador, a menos
;; que você fique tão irritado a ponto de jogá-lo no chão. Neste caso,
;; me abstenho de qualquer responsabilidade. Divirta-se!
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Abra o Emacs.
;;
;; Aperte a tecla `q' para ocultar a mensagem de boas vindas.
;;
;; Agora olhe para a linha cinza na parte inferior da janela:
;;
;; "*scratch*" é o nome do espaço de edição em que você se encontra.
;; Este espaço de edição é chamado "buffer".
;;
;; O buffer de rascunho (i.e., "scratch") é o buffer padrão quando
;; o Emacs é aberto. Você nunca está editando arquivos: você está
;; editando buffers que você pode salvar em um arquivo.
;;
;; "Lisp interaction" refere-se a um conjunto de comandos disponíveis aqui.
;;
;; O Emacs possui um conjunto de comandos embutidos (disponíveis em
;; qualquer buffer) e vários subconjuntos de comandos disponíveis
;; quando você ativa um modo específico. Aqui nós utilizamos
;; `lisp-interaction-mode', que possui comandos para interpretar e navegar
;; em código Elisp.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Pontos e vírgulas iniciam comentários em qualquer parte de uma linha.
;;
;; Programas codificados em Elisp são compostos por expressões simbólicas
;; (conhecidas também por "sexps"):
(+ 2 2)
;; Esta expressão simbólica significa "Some 2 e 2".
;; "Sexps" são envoltas em parêntese, possivelmente aninhados:
(+ 2 (+ 1 1))
;; Uma expressão simbólica contém átomos ou outras expressões
;; simbólicas. Nos exemplos acima, 1 e 2 são átomos;
;; (+ 2 (+ 1 1)) e (+ 1 1) são expressões simbólicas.
;; No modo `lisp-interaction-mode' você pode interpretar "sexps".
;; Posicione o cursor logo após o parêntese de fechamento e,
;; então, segure apertado Ctrl e aperte a tecla j ("C-j", em resumo).
(+ 3 (+ 1 2))
;; ^ posicione o cursor aqui
;; `C-j' => 6
;; `C-j' insere o resultado da interpretação da expressão no buffer.
;; `C-xC-e' exibe o mesmo resultado na linha inferior do Emacs,
;; chamada de "echo area". Nós geralmente utilizaremos `C-xC-e',
;; já que não queremos poluir o buffer com texto desnecessário.
;; `setq' armazena um valor em uma variável:
(setq my-name "Bastien")
;; `C-xC-e' => "Bastien" (texto exibido no echo area)
;; `insert' insere "Hello!" na posição em que se encontra seu cursor:
(insert "Hello!")
;; `C-xC-e' => "Hello!"
;; Nós executamos `insert' com apenas um argumento ("Hello!"), mas
;; mais argumentos podem ser passados -- aqui utilizamos dois:
(insert "Hello" " world!")
;; `C-xC-e' => "Hello world!"
;; Você pode utilizar variávies no lugar de strings:
(insert "Hello, I am " my-name)
;; `C-xC-e' => "Hello, I am Bastien"
;; Você pode combinar "sexps" em funções:
(defun hello () (insert "Hello, I am " my-name))
;; `C-xC-e' => hello
;; Você pode interpretar chamadas de funções:
(hello)
;; `C-xC-e' => Hello, I am Bastien
;; Os parênteses vazios na definição da função significam que ela
;; não aceita argumentos. Mas sempre utilizar `my-name' é um tédio!
;; Vamos dizer à função para aceitar um argumento (o argumento é
;; chamado "name"):
(defun hello (name) (insert "Hello " name))
;; `C-xC-e' => hello
;; Agora vamos executar a função com a string "you" como o valor
;; para seu único parâmetro:
(hello "you")
;; `C-xC-e' => "Hello you"
;; Aí sim!
;; Respire um pouco.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Agora mude para um novo buffer chamado "*test*":
(switch-to-buffer-other-window "*test*")
;; `C-xC-e'
;; => [a tela exibirá duas janelas e o cursor estará no buffer *test*]
;; Posicione o mouse sobre a janela superior e clique com o botão
;; esquerdo para voltar. Ou você pode utilizar `C-xo' (i.e. segure
;; ctrl-x e aperte o) para voltar para a outra janela, de forma interativa.
;; Você pode combinar várias "sexps" com `progn':
(progn
(switch-to-buffer-other-window "*test*")
(hello "you"))
;; `C-xC-e'
;; => [A tela exibirá duas janelas e o cursor estará no buffer *test*]
;; Agora, se você não se importar, pararei de pedir que você aperte
;; `C-xC-e': faça isso para cada "sexp" que escrevermos.
;; Sempre volte para o buffer *scratch* com o mouse ou `C-xo'.
;; Frequentemente, é útil apagar o conteúdo do buffer:
(progn
(switch-to-buffer-other-window "*test*")
(erase-buffer)
(hello "there"))
;; Ou voltar para a outra janela:
(progn
(switch-to-buffer-other-window "*test*")
(erase-buffer)
(hello "you")
(other-window 1))
;; Você pode armazenar um valor em uma variável local utilizando `let':
(let ((local-name "you"))
(switch-to-buffer-other-window "*test*")
(erase-buffer)
(hello local-name)
(other-window 1))
;; Neste caso, não é necessário utilizar `progn' já que `let' combina
;; várias "sexps".
;; Vamos formatar uma string:
(format "Hello %s!\n" "visitor")
;; %s é um espaço reservado para uma string, substituído por "visitor".
;; \n é um caractere de nova linha.
;; Vamos refinar nossa função utilizando `format':
(defun hello (name)
(insert (format "Hello %s!\n" name)))
(hello "you")
;; Vamos criar outra função que utilize `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"
))))
;; E executá-la:
(greeting "you")
;; Algumas funções são interativas:
(read-from-minibuffer "Enter your name: ")
;; Ao ser interpretada, esta função retorna o que você digitou no prompt.
;; Vamos fazer nossa função `greeting' pedir pelo seu nome:
(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")
;; Vamos finalizá-la fazendo-a exibir os resultados em outra janela:
(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)))
;; Agora teste-a:
(greeting "Bastien")
;; Respire um pouco.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Vamos armazenar uma lista de nomes:
(setq list-of-names '("Sarah" "Chloe" "Mathilde"))
;; Pegue o primeiro elemento desta lista utilizando `car':
(car list-of-names)
;; Pegue uma lista de todos os elementos, exceto o primeiro, utilizando
;; `cdr':
(cdr list-of-names)
;; Adicione um elemento ao início da lista com `push':
(push "Stephanie" list-of-names)
;; NOTA: `car' e `cdr' não modificam a lista, `push' sim.
;; Esta é uma diferença importante: algumas funções não têm qualquer
;; efeito colateral (como `car'), enquanto outras sim (como `push').
;; Vamos executar `hello' para cada elemento em `list-of-names':
(mapcar 'hello list-of-names)
;; Refine `greeting' para saudar todos os nomes em `list-of-names':
(defun greeting ()
(switch-to-buffer-other-window "*test*")
(erase-buffer)
(mapcar 'hello list-of-names)
(other-window 1))
(greeting)
;; Você se lembra da função `hello' que nós definimos lá em cima? Ela
;; recebe um argumento, um nome. `mapcar' executa `hello', sucessivamente,
;; utilizando cada elemento de `list-of-names' como argumento para `hello'.
;; Agora vamos arrumar, um pouco, o que nós temos escrito no 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)) vai para o início do buffer.
;; (search-forward "Hello") busca pela string "Hello".
;; (while x y) interpreta a(s) sexp(s) y enquanto x retornar algo.
;; Se x retornar `nil' (nada), nós saímos do laço.
(replace-hello-by-bonjour)
;; Você deveria ver todas as ocorrências de "Hello" no buffer *test*
;; substituídas por "Bonjour".
;; Você deveria, também, receber um erro: "Search failed: Hello".
;;
;; Para evitar este erro, você precisa dizer ao `search-forward' se ele
;; deveria parar de buscar em algum ponto no buffer, e se ele deveria
;; falhar de forma silenciosa quando nada fosse encontrado:
;; (search-forward "Hello" nil t) dá conta do recado:
;; O argumento `nil' diz: a busca não está limitada a uma posição.
;; O argumento `t' diz: falhe silenciosamente quando nada for encontrado.
;; Nós utilizamos esta "sexp" na função abaixo, que não gera um erro:
(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)
;; Vamos colorir os nomes:
(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 função introduz `re-search-forward': ao invés de buscar
;; pela string "Bonjour", você busca por um padrão utilizando uma
;; "expressão regular" (abreviada pelo prefixo "re-").
;; A expressão regular é "Bonjour \\(.+\\)!" e lê-se:
;; a string "Bonjour ", e
;; um grupo de | que é o \\( ... \\)
;; quaisquer caracteres | que é o .
;; possivelmente repetidos | que é o +
;; e a string "!".
;; Preparado? Teste!
(boldify-names)
;; `add-text-properties' adiciona... propriedades de texto, como uma fonte.
;; OK, terminamos por aqui. Feliz Hacking!
;; Se você quiser saber mais sobre uma variável ou função:
;;
;; C-h v uma-variável RET
;; C-h f uma-função RET
;;
;; Para ler o manual de Emacs Lisp que vem com o Emacs:
;;
;; C-h i m elisp RET
;;
;; Para ler uma introdução online ao Emacs Lisp:
;; https://www.gnu.org/software/emacs/manual/html_node/eintr/index.html
;; Agradecimentos a estas pessoas por seu feedback e sugestões:
;; - Wes Hardaker
;; - notbob
;; - Kevin Montuori
;; - Arne Babenhauserheide
;; - Alan Schmitt
;; - LinXitoW
;; - Aaron Meurer
Sugestões ou correções? Abra uma issue no repositório do GitHub, ou faça um pull request você mesmo!
Originalmente contribuído por Bastien Guerry e atualizado por 4 colaboradores.