Emacs Lisp
Anotações dos meus estudos
Conteúdo
Sobre a série
O que pretendemos aprender
- Fundamentos da linguagem.
- Criação de funções.
- Manipulação de variáveis.
- Criar novas funcionalidades para o Emacs.
- Utilizar o Emacs como interpretador no sistema.
- Trabalhar com macros.
- Criar e compartilhar pacotes (git e MELPA).
Este site é gerado por um programa em Emacs Lisp interpretado pelo Emacs invocado em um shell script!
Para quem é a série
- Para mim: eu quero muito aprender elisp 😎!
- Para quem quer customizar os mínimos detalhes do seu Emacs.
- Para quem quer exercer plenamente sua liberdade de computação.
- Para quem quer contribuir com pacotes para a comunidade Emacs.
Ambiente de estudo
- GNU Emacs
- É fundamental ter ou desenvolver um conhecimento mínimo do Emacs. Nisso, o
tutorial pode ajudar muito:
C-h t
. - REPL (ielm)
- O Emacs conta com um REPL (Read Eval Print Loop) para avaliar interativamente
códigos em elisp:
M-x ielm
- Buffer scratch
O scratch buffer é um buffer temporário no modo Emacs Lisp, ou seja, um modo em que o Emacs aciona todas as funcionalidades para a escrita de código em elisp. Por ser temporário, o que escrevermos nele será perdido com o fim da sessão do Emacs, o que o torna ideal para os nossos experimentos.
O problema, é que o scratch buffer, embora disponível, não é o buffer visível no início, e isso requer, no mínimo, o conhecimento sobre como navegar entre os buffers (atalho
C-x b
). Além disso, os códigos precisarão ser avaliados pelo interpretador elisp para terem efeito:- Avaliar todo o buffer:
M-x eval-buffer
- Avaliar seleção (região):
M-x eval-region
- Avaliar última expressão antes do cursor:
M-x eval-last-sexp
- Avaliar todo o buffer:
- Sistema interno de descrições
C-h v
: Descrição de variáveisC-h f
: Descrição de funçõesC-h o
: Descrição de símbolosC-h m
: Descrição de modos
- Deixe o Emacs mais confortável
Ocultar/exibir barra de menu:
M-x menu-bar-mode RET
Ocultar/exibir barra de ferramentas:
M-x tool-bar-mode RET
Ocultar/exibir barras de rolagem:
M-x scroll-bar-mode RET
Alterar tema padrão:
M-x load-themne RET <nome do tema> RET
Essas alterações podem ser tornadas permanentes se escritas no arquivo
init.el
:(menu-bar-mode -1) (tool-bar-mode -1) (scroll-bar-mode -1) (load-theme 'modus-vivendi)
O arquivo
init.el
pode ser criado em~/.config/emacs/
ou em~/.emacs.d/
.Para o Emacs não exibir o buffer de boas-vindas e utilizar o scratch buffer como buffer inicial, nós podemos incluir a definição da variável
inhibit-startup-message
no arquivoinit.el
:(setq inhibit-startup-message t) (menu-bar-mode -1) (tool-bar-mode -1) (scroll-bar-mode -1) (load-theme 'modus-vivendi)
Sobre o Emacs
Esta é uma história de hackers…
- Em 1972, Carl Mikkelsen adiciona capacidade de edição visual ao editor TECO.
- Em 1974, Richard Stallman adicionou funcionalidades de macros ao TECO.
- As coleções de macros para o TECO foram se acumulando no laboratório de IA do MIT.
- Em 1976, Stallman organizou essas macros em comandos no TECO EMACS (Editor MACroS).
- Entre as novidades do EMACS, estava o recurso de auto-documentação das macros.
- O TECO EMACS tornou-se o editor padrão do sistema ITS (Incompatible Time Sharing).
- Nos anos seguintes, surgiram várias implementações do EMACS.
- Em 1984, Stallman começou a desenvolver o GNU Emacs: o primeiro programa do Projeto GNU.
Sobre o Emacs Lisp
- É um dialeto Lisp para expandir o Emacs.
- Fortemente inspirado no dialeto MACLISP (MIT, anos 1960).
- Tem influências do ANSI Common Lisp, mas é bem mais simples.
- Requer um conhecimento mínimo de uso do Emacs (tutorial:
C-h t
).
Conceitos básicos
Sintaxe
- Sintaxe simples (poucas regras) e uniforme, o que facilita muito o aprendizado.
- O código em elisp se resume a três elementos de sintaxe: listas, símbolos e valores.
- No Lisp, em geral, código também é dado.
- O próprio Emacs nos ajuda a lidar com os parêntesis.
- Múltiplos espaços e quebras de linha são ignorados: são os parêntesis que delimitam as expressões.
(defun salve (nome) "Exibe uma saudação para NOME." (message "Salve, %s!" nome))
Valores
- Todos os elementos (objetos) possuem um valor de um determinado tipo.
- São os valores avaliados que possuem um tipo, não as suas representações!
Alguns tipos do Lisp:
- Números
- Strings
- Símbolos
- Listas
Alguns tipos do Emacs Lisp:
- Buffers
- Windows
- Frames
- Keymaps
Os tipos do elisp são principalmente os componentes do Emacs e da sua interface!
Formas
São todos os objetos do Lisp que podem ser avaliados (termo geralmente aplicado a funções e macros).
Objetos autoavaliáveis
Tipos primitivos, como números e strings:
ELISP> 42 42 (#o52, #x2a, ?*) ELISP> "Salve, simpatia!" "Salve, simpatia!" ELISP> ?B 65 (#o102, #x42, ?B)
Funções e macros são avaliáveis
ELISP> (defun fala () (print "Falaê!")) fala ELISP> (fala) "Falaê!" "Falaê!" ELISP> (defun soma2 (a b) (+ a b)) soma2 ELISP> (soma2 17 25) 42 (#o52, #x2a, ?*)
Se o primeiro elemento da lista não for uma função ou uma macro, ela não poderá ser avaliada:
ELISP> (1 2 3 4) *** Eval error *** Invalid function: 1
Devido à notação prefixa (ou polonesa), o interpretador presume que o primeiro elemento da lista seja o nome de uma função.
Para ser avaliada como tal, a lista teria que ser citada (quoted):
ELISP> '(1 2 3 4) (1 2 3 4)
A aspa simples é a sintaxe reduzida da chamada da forma especial quote
:
ELISP> (quote (1 2 3 4)) (1 2 3 4)
A forma quote
também serve para avaliar símbolos:
ELISP> soma2 *** Eval error *** Symbol’s value as variable is void: soma2 ELISP> 'soma2 soma2
O erro aconteceu porque, quando tentamos avaliar um símbolo pelo seu nome, ele é presumido como o identificador de uma variável.
ELISP> (defvar bicho "zebra") bicho ELISP> bicho "zebra"
Objetos especiais t
e nil
No elisp, o símbolo nil
tem três significados:
- É um símbolo nomeado como
nil
; - É o valor lógico falso;
- E é uma lista vazia (com zero elementos).
Quanto à representação de um valor lógico verdadeiro, qualquer valor diferente
de nil
pode cumprir com este papel. Contudo, o símbolo especial t
é preferível
quando queremos ser explícitos ou quando não houver algo a ser avaliado para
determinar uma verdade lógica.
Predicados
Predicados são funções que avaliam apenas t
(verdadeiro) ou nil
(falso).
(null ()) ;; Avalia `t' se argumento for `nil'. (zerop 0) ;; Avalia `t' se argumento for zero.
Predicados de tipos
Predicados são funções que avaliam apenas verdadeiro (t
) ou falso (nil
). Os
predicados de tipos determinam se o argumento é do tipo especificado pela
função, por exemplo:
stringp
- Avalia
t
se o argumento for uma string. floatp
- Avalia
t
se o argumento for um número de ponto flutuante. integerp
- Avalia
t
se o argumento for um número inteiro. numberp
- Avalia
t
se o argumento for um número. listp
- Avalia
t
se o argumento for uma lista. symbolp
- Avalia
t
se o argumento for um símbolo. bufferp
- Avalia
t
se o argumento for um buffer. - windowp
- Avalia
t
se o argumento for uma janela.
Função type-of
Avalia um símbolo representando o nome do tipo do objeto primitivo passado como argumento.
ELISP> (type-of 42) integer ELISP> (type-of ?B) integer ELISP> (type-of (print "banana")) "banana" string ELISP> (type-of (get-buffer "*scratch*")) buffer
Predicados de igualdade
Determinam se dois objetos são idênticos em todos ou em algum dos seus atributos.
Determinando se dois objetos são o mesmo objeto
O predicado eq
avalia t
apenas se os dois objetos forem o mesmo objeto em termos
de referência na memória.
ELISP> (eq 15 15) t ELISP> (eq 'defun 'defun) t ELISP> (eq minha-var minha-var) t
Alguns objetos são referenciados em instâncias separadas na memória, mesmo que sejam escritos da mesma forma!
ELISP> (eq 3.0 3.0) nil ELISP> (eq "banana" "banana") nil ELISP> (eq '(a b c) '(a b c)) nil
Determinando se dois objetos são o mesmo objeto ou são números
Com eql
, a avaliação é t
se os objetos forem o mesmo objeto ou se forem números
iguais.
ELISP> (eql 1.5 1.5) t
Determinando se dois objetos são equivalentes
O predicado equal
avalia t
se os dois objetos possuírem os mesmos componentes.
ELISP> (equal 15 15) t ELISP> (equal 1.5 1.5) t ELISP> (equal "banana" "banana") t ELISP> (equal 'defun 'defun) t ELISP> (equal minha-var minha-var) t ELISP> (equal '(a b c) '(a b c)) t
Predicados de comparação numérica
(= 15 15) ;; Igualdade (< 15 52) ;; Menor que... (> 15 42) ;; Maior que... (<= 15 42) ;; Menor ou igual (>= 15 42) ;; Maior ou igual (char-equal ?😊 128522) ;; Comparação numérica usando caracateres
Operações aritméticas
Operações básicas
(+ 17 25) ;; Soma (- 126 84) ;; Subtração (* 10.5 4) ;; Multiplicação (/ 126 3) ;; Divisão (% 342 100) ;; Módulo (resto) int (mod 21.98 3) ;; Módulo (resto) float
Raiz quadrada
ELISP> (sqrt 1764) 42
Potenciação
ELISP> (expt 2 16) ;; Base 2, expoente 16... 65536
Incremento e decremento
ELISP> (1+ 41) 42 ELISP> (1- 43) 42
Número pseudoaleatório
(random 100) ;; Avalia um inteiro entre 0 e o `limite-1'.
Máximo e mínimo
(max 1 3 5 7) ;; Valor máximo entre os argumentos (min 1 3 5 7) ;; Valor mínimo entre os argumentos
Aproximações (converter float para int)
ELISP> (truncate 21.98) 21 ELISP> (floor 21.9999) 21 ELISP> (floor -21.9999) -22 ELISP> (ceiling 21.0001) 22 ELISP> (ceiling -21.0001) -21 ELISP> (round 21.5) 22 ELISP> (round 21.49999) 21
Expressões condicionais
Forma especial `if'
A forma if
avalia uma expressão, caso a CONDIÇÃO
avalie t
, ou várias expressões,
caso a CONDIÇÃO
avalie nil
.
(if CONDIÇÃO SE-VERDADEIRO SE-FALSO SE-FALSO ...)
Alternativamente, podemos avaliar mais de uma expressão se a CONDIÇÃO
avaliar
t
com a forma especial progn
:
(if CONDIÇÃO (progn SE-VERDADEIRO SE-VERDADEIRO ...) SE-FALSO SE-FALSO ...)
A forma prog
avalia todas as expressões passadas como argumentos.
Macro `unless'
Se a CONDIÇÃO
for avaliada nil
, as demais expressões serão avaliadas; caso
contrário, avalia nil
.
(unless CONDIÇÃO CÓDIGO)
Macro `when'
Se CONDIÇÃO
avaliar algo diferente de nil
, as demais expressões serão avaliadas;
caso contrário, avalia nil
.
(when CONDIÇÃO CÓDIGO)
Forma especial `cond'
Avalia cláusulas na forma (CONDIÇÃO CÓDIGO)
e avalia a primeira em que CONDIÇÃO
for diferente de nil
. Se nenhuma cláusula for avaliada, avalia nil
.
(cond (CONDIÇÃO CÓDIGO) (CONDIÇÃO CÓDIGO) ...)
A forma cond
pode ser utilizada como um if
"sem else" se houver apenas uma
cláusula. Nesse caso, se a única condição avaliar nil
, toda a expressão avaliará
nil
.
Repetições (loops)
Existem quatro formas de implementar repetições no elisp:
while
dotimes
dolist
- Funções recursivas
Forma especial `while'
Avalia o CÓDIGO
enquanto a CONDIÇÃO
continuar sendo avaliada como diferente de
nil
.
(while CONDIÇÃO CÓDIGO)
Macro `dotimes'
Avalia o CÓDIGO
enquanto associa VAR
a uma CONTAGEM
de inteiros sucessivos de
zero a CONTAGEM - 1
.
(dotimes (VAR CONTAGEM) CÓDIGO)
Macro `dolist'
Itera pelos ELEMENTOS
de uma lista na forma (VAR '(ÍTENS))
associando o ÍTEM
corrente a VAR
e avaliando o CÓDIGO
a cada iteração.
(dolist (VAR '(ÍTEM1 ÍTEM2 ...)) CÓDIGO)
Variáveis
Em Lisp, variáveis são símbolos associados a valores.
Definindo variáveis de escopo global
set
setq
defvar
Definindo variáveis de escopo global no buffer
setq-local
Definindo variáveis de escopo local
let
let*
Definindo variáveis customizáveis pela UI
defcustom