;; 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"):(+ 22);; Esta expressão simbólica significa "Some 2 e 2".;; "Sexps" são envoltas em parêntese, possivelmente aninhados:(+ 2(+ 11));; 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(+ 12));; ^ 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:(setqmy-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:(defunhello()(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"):(defunhello(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-window1));; Você pode armazenar um valor em uma variável local utilizando `let':(let ((local-name"you"))(switch-to-buffer-other-window"*test*")(erase-buffer)(hellolocal-name)(other-window1));; 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':(defunhello(name)(insert(format"Hello %s!\n"name)))(hello"you");; Vamos criar outra função que utilize `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"))));; 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:(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");; Vamos finalizá-la fazendo-a exibir os resultados em outra janela:(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)));; Agora teste-a:(greeting"Bastien");; Respire um pouco.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Vamos armazenar uma lista de nomes:(setqlist-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'hellolist-of-names);; Refine `greeting' para saudar todos os nomes em `list-of-names':(defungreeting()(switch-to-buffer-other-window"*test*")(erase-buffer)(mapcar'hellolist-of-names)(other-window1))(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:(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)) 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:(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);; Vamos colorir os nomes:(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 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