Montei minha config do GNU Emacs ao longo dos anos.

Tenho mantido esse repositório atualizado de tempos em tempos: https://github.com/alissonperez/emacs-conf

Dicas

Criar/abrir arquivo com nome parcial quando existe um nome parecido (Ivy)

Problema: ao usar C-x C-f (counsel-find-file) para criar um arquivo cujo nome é prefixo de outro já existente (ex.: digitar .env quando já existe .env.example), o Ivy destaca/seleciona o arquivo existente na lista, e apertar RET acaba abrindo esse arquivo em vez de criar o novo com o nome digitado.

Solução: C-M-j (ivy-immediate-done). Esse atalho já vem por padrão no ivy-minibuffer-map e ignora o candidato destacado, usando exatamente o texto digitado na minibuffer.

Fluxo:

  1. C-x C-f
  2. Digite .env
  3. Mesmo com .env.example destacado na lista, aperte C-M-j
  4. O Emacs cria/abre .env literal, ignorando a sugestão

Tecla Meta não funciona no terminal (Ghostty)

Problema: rodando o Emacs no terminal (emacs -nw) dentro do Ghostty, atalhos com Meta (ex.: M-x, M-p, M-n) não funcionam ao apertar Option. Isso acontece porque, por padrão no macOS, o Ghostty reserva a tecla Option para digitar caracteres especiais (á, é, ç, etc.) e não a envia como Alt/Meta para o Emacs.

Solução: adicionar ao config do Ghostty (~/.config/ghostty/config):

macos-option-as-alt = true

Reiniciar o Ghostty para aplicar. Alternativa: usar macos-option-as-alt = left ou right para manter apenas uma das teclas Option como Meta e preservar a outra para acentuação.

Ctrl+Shift+letra não funciona no terminal dentro do tmux

Problema: no terminal, C-S-d (duplicar linha) se comporta como C-d, e a seleção com C-S-f/C-S-b/C-S-p/C-S-n não funciona. A codificação clássica de terminal não tem bit de Shift para combinações com Control: C-S-d e C-d chegam como o mesmo byte.

Fora do tmux isso é resolvido pelo pacote kkp, que faz o Emacs falar o Kitty Keyboard Protocol do Ghostty. Dentro do tmux o kkp nunca ativa: ele só se habilita depois de perguntar ao terminal (CSI ? u) e receber uma resposta válida, e o tmux não responde a essa pergunta (extended-keys-format não aceita o valor kitty).

A solução exige três peças alinhadas — faltando qualquer uma, não funciona:

1. tmux precisa pedir as teclas estendidas ao Ghostty e repassá-las. Em ~/.tmux.conf:

# Pede eventos de teclado estendidos ao terminal externo. Sem a feature
# "extkeys" o tmux nem solicita esses eventos, então não tem o que repassar.
# O nome do terminal precisa bater com o que você usa (aqui, xterm-ghostty).
set -as terminal-features ',xterm-ghostty:extkeys'
 
# Reporta teclas modificadas aos programas rodando dentro do painel.
set -s extended-keys on
 
# csi-u, não xterm — ver detalhe sobre formato mais abaixo.
set -s extended-keys-format csi-u

Esse arquivo fica fora do repo do Emacs, então deixei uma cópia versionada em examples/tmux.conf lá, referenciada no README.

2. O Emacs precisa pedir o modo 2 do modifyOtherKeys. O term/tmux.el pede o modo 1, que por definição só re-codifica teclas “sem representação bem-conhecida” — e C-S-d tem uma (C-d), então continua ambígua. Isso é hardcoded no Emacs, não há variável para mudar; é preciso mandar \e[>4;2m manualmente.

3. Um decodificador genérico. O modo 2 re-codifica todas as teclas modificadas (M-x vira \e[120;3u, C-c vira \e[99;5u), e o xterm.el só decodifica uma lista curada — o resto vazaria como texto literal no buffer. O parser do kkp resolve isso e é stateless: só a detecção dele depende do handshake, não o parsing. Dá para registrá-lo direto.

O bloco correspondente está no init.el, sob a seção “Kitty Keyboard Protocol”.

Detalhe que custou caro ao depurar: o formato importa. O parser do kkp entende a codificação do Kitty, que corresponde ao formato csi-u do tmux (\e[100;6u) e não ao formato xterm (\e[27;6;100~, que ele leria como keycode 27).

Outro detalhe traiçoeiro: tmux send-keys C-S-d gera bytes diferentes de um toque real. O send-keys manda o código 100 (d minúsculo); o Ghostty manda 68 (D, a letra já com Shift). Testar com send-keys dá falso positivo — para medir de verdade, capture os bytes de um toque real:

printf '\033[>4;2m'; stty raw -echo; dd of=/tmp/k.bin bs=1 count=12 2>/dev/null; stty sane; od -c /tmp/k.bin

Para inspecionar o estado: tmux list-panes -a -F '#{pane_current_command} #{pane_key_mode}' mostra o modo negociado por painel (VT10x = legado, Ext 2 = modo 2 ativo).