- Para ver corretamente temas como Solarized no Emacs de terminal, mais importante do que as cores de 24 bits em si é se terminal, terminfo, tmux e mosh entendem a mesma capacidade de cor até o fim
- Cores RGB são amplamente usadas na forma
ESC[38;2;<r>;<g>;<b>m, mas a sintaxe com dois-pontos, mais próxima do padrão, e a sintaxe com ponto e vírgula, difundida nas implementações reais, continuam coexistindo, complicando a compatibilidade xterm-256colorexterm-directanunciam respectivamente uma paleta de 256 cores e 16.777.216 cores, mas o modelo de terminfo centrado em paleta não consegue expressar bem cores RGB diretas- Em ambientes reais, podem ser necessários valores alternativos de TERM como as entradas
-directdoncurses-term,tmux-direct, a linha 1.4 do mosh evscode-direct, e algumas camadas ainda aceitam apenas a sintaxe com ponto e vírgula - Para usar com estabilidade recursos modernos de terminal, TERM e terminfo sozinhos não bastam; é preciso uma forma separada de representar capacidades que seja atualizada mais rápido por nome e versão do terminal
Por que cores de 24 bits são necessárias no Emacs de terminal
- O Emacs em ambiente gráfico oferece suporte automático a cores de 24 bits, exibindo corretamente temas como Solarized e fontes
- Ao usar o mesmo tema no terminal, a representação de cores pode ficar limitada e a tela pode parecer menos agradável
- Terminais populares já suportam cores de 24 bits há muito tempo, mas para que um programa use isso, a detecção de capacidade e a configuração precisam estar corretas
- O objetivo é duplo
- descobrir como ativar o suporte a truecolor no ambiente de terminal atual
- verificar como o problema de cores do Emacs se conecta aos padrões de terminal das décadas de 1970 a 1990
Códigos de escape ANSI e a história da expansão de cores
- Os primeiros terminais de hardware usavam conjuntos diferentes de códigos de controle, e a padronização ANSI foi necessária para criar software portável
- ANSI escape codes vêm sendo usados desde os anos 1970, e nas cores o ponto central é o SGR (Select Graphics Rendition)
- negrito ou brilho
- itálico
- piscante
- cor de primeiro plano e de fundo
- outros atributos de exibição de caracteres
- No início, as cores eram cores de 3 bits correspondentes aos 8 vértices de um cubo RGB
- incluindo preto, branco, primárias aditivas e primárias subtrativas
- Depois, com a adição de cores brilhantes ou do bit de negrito, isso foi expandido para 16 cores
- “bright black” corresponde a um cinza escuro
- Em 1999, Todd Larason adicionou ao xterm um patch de suporte a 256 cores
- amostragem de um cubo RGB 6x6x6
- uma rampa de escala de cinza com 24 níveis
- também existe uma variação de 88 cores, rara mas ainda suportada
Como surgiu a sintaxe de cores de 24 bits
- Em terminais compatíveis, cores de 8 bits e 24 bits são definidas assim
ESC[38;5;<n>m: define a cor númeronda paleta como cor de primeiro planoESC[38;2;<r>;<g>;<b>m: define os valores RGBr,g,bcomo cor de primeiro plano
- Os números
5e2estão ligados ao modo estendido de cores do ISO 8613-6, isto é, ITU T.4162: cor direta no espaço RGB5: cor indexada
- O fluxo de padronização foi o seguinte
- anos 1970: a ANSI padronizou sequências de escape de terminal, levando à ANSI X3.64 e à ECMA-48
- 1979: a 2ª edição da ECMA-48 atribuiu SGR 30~37 e 40~47 às cores de primeiro plano e fundo de 3 bits
- 1984: a 3ª edição da ECMA-48 introduziu o conceito de cor padrão de primeiro plano e fundo, atribuindo 39 e 49
- 1991: a 5ª edição da ECMA-48 deixou 38 e 48 para “padronização futura”, com referência ao ISO 8613-6
- 1993: o ISO 8613-6 definiu 38 e 48 como modos estendidos de cor de primeiro plano e de fundo
- Para separar subparâmetros, o uso de dois-pontos é o mais próximo do padrão, mas as implementações reais adotaram amplamente ponto e vírgula
ESC[38;5;3mpode ser interpretado por um terminal que não conheça SGR 38 como parâmetros separados38,5e3- o FAQ do xterm, de Thomas Dickey, explica que uma cópia da ITU T.416 era cara na época e que separar os valores RGB com ponto e vírgula, como se fossem outros parâmetros SGR, foi um erro
- A linha do tempo relacionada é esta
- 1999: Thomas Dickey integrou ao xterm o patch de 256 cores de Todd Larason, incluindo a sintaxe ambígua com ponto e vírgula
- 2006: o Konsole passou a suportar 256 cores e truecolor de 24 bits com a mesma sintaxe com ponto e vírgula do xterm
- 2012: o xterm foi alterado para aceitar também a sintaxe com dois-pontos, mais próxima do padrão
- 2016: o console embutido do Windows 10 passou a suportar códigos de escape ANSI e cores de 24 bits, mas usando a sintaxe com ponto e vírgula
- 2019: o Windows Terminal também passou a suportar códigos de escape ANSI, mas usa a sintaxe com ponto e vírgula
- 2022: a Microsoft anunciou a transição do ecossistema do subsistema de console estilo VGA legado para emulação de terminal ANSI
- 2022: o Konsole passou a suportar a sintaxe com dois-pontos compatível com o padrão
Como o terminfo representa capacidades de cor
- terminfo fornece um banco de dados de capacidades de terminal e meios de gerar as sequências de escape adequadas
- A variável de ambiente
TERMaponta para o registro terminfo que o programa deve usar, e também é transmitida automaticamente em conexõesssh toemostra a lista de registros terminfo instalados, einfocmpserve para verificar as capacidades de um registro específico- Para cores, há três capacidades importantes
colors: número de cores suportadas pelo terminalsetaf: define a cor de primeiro planosetab: define a cor de fundo
- O
setafdexterm-256coloremite sequências diferentes conforme o número da cor- 0~7: usa parâmetros ANSI SGR 30~37
- 8~15: usa as cores brilhantes não padronizadas 90~97
- acima disso: usa a paleta de 256 cores na forma
38;5;<n>
xterm-directé uma entrada terminfo para RGB de 24 bits que anunciacolorscomo 16.777.216- desativa
ccc, indicando que não é possível atribuir novos valores RGB a um índice de cor - também omite entradas relacionadas à alteração de cores em tempo de execução, como
initc,ocers1 setafesetabusam a forma baseada em dois-pontos38:2::...
- desativa
Limites do modelo de cor direta do terminfo
- O modelo de programação de terminfo e ncurses é, em essência, centrado em entradas de paleta
- existem N entradas de paleta
- cada entrada tem um valor RGB padrão
- pressupõe-se um modelo em que o terminal pode alterar esses valores
- Terminais
-directrepresentam cores de 24 bits como se houvesse 16.777.216 entradas de paleta- cada entrada corresponde a um cubo RGB 8:8:8
- os valores não podem ser alterados
- Por compatibilidade, o esquema
xterm-directusa os 7 azuis mais escuros para compatibilidade com as 8 cores ANSI padrão- excluindo o preto
- isso evita que programas antigos, ao assumir um significado para
setaf, acabem exibindo azuis muito escuros quase invisíveis
- Por isso, os modos
-directe-256colornão são compatíveis entre si- o programa precisa saber que 256 cores significam cor indexada e 16.777.216 significam cor direta
- também existe a exceção de evitar os 7 azuis mais escuros
- Em um problema relacionado ao termwiz, o programa esperava a paleta de
xterm-256color, mas na prática exibia tons de azul escuro difíceis de ler- a issue ainda estava aberta no momento da escrita, mas @quark-zju aplicou uma correção e hoje o termwiz se comporta de forma razoável
- O ponto central está mais nas restrições do terminfo do que no terminal em si
- um terminal que suporta cores de 24 bits também parece suportar a paleta de 256 cores do xterm e alteração dinâmica de valores RGB
- o terminfo é insuficiente para representar com precisão e rapidez o ecossistema moderno de emuladores de terminal
Configuração de TERM e compatibilidade com ponto e vírgula
- Como muitos programas usam terminfo, o valor de
TERMprecisa estar correto - Mesmo que se queira padronizar a sintaxe SGR com dois-pontos, muitos ambientes ainda suportam apenas a sintaxe com ponto e vírgula
- As entradas terminfo são compostas por blocos de construção
xterm+direct: sintaxe com dois-pontos, mais próxima do padrãoxterm+indirect: para terminais legados que suportam apenas ponto e vírgula
- Ao procurar por
xterm+indirect,vscode-directpareceu a melhor opção- como mira terminais da Microsoft, foi considerado próximo o bastante do Windows Terminal e do Windows Console
- nem todas as capacidades foram auditadas, mas funciona
- Muitos servidores podem não ter instaladas as entradas terminfo
-direct- na maioria dos sistemas, o banco de dados terminfo padrão vem no pacote
ncurses-base - entradas de terminal estendidas exigem o pacote
ncurses-term
- na maioria dos sistemas, o banco de dados terminfo padrão vem no pacote
- Durante a escrita, uma entrada terminfo
winconsolefoi adicionada ao ncurses, mas ela não suporta cores de 24 bits e ainda não foi lançada em nenhuma versão do ncurses
Como o Emacs detecta truecolor
- O Emacs documenta como detecta suporte a truecolor em TTY
- Em
M-x eval-expression, é possível executar(display-color-cells)para verificar se o Emacs reconhece 16.777.216 cores - A documentação do Emacs também trata das limitações do terminfo no modo
-direct- terminais com a capacidade
RGBpodem tratar#000001até#000007como cores indexadas, e não como RGB direto - isso serve para manter compatibilidade retroativa com aplicações que não entendem direct color
- se isso causar problema, pode-se usar uma definição de terminal personalizada com
setb24esetf24
- terminais com a capacidade
- O Emacs primeiro procura as strings
setf24esetb24; se não existirem, usaRGBcomo capacidade alternativa - As entradas terminfo verificadas no sistema não continham
setf24
Em terminais aninhados, todas as camadas precisam bater
- Um fluxo de trabalho comum aninha várias camadas de terminal
- abrir um emulador gráfico de terminal no desktop local
- conectar-se com mosh a uma máquina remota ou VM
- iniciar o tmux
- adicionar ainda terminal interno do Emacs, Asciinema, GNU Screen etc.
- Cada camada implementa sua própria máquina de estados de sequências de escape ANSI
- Para que cores de 24 bits funcionem, todas as camadas precisam entender as sequências de escape geradas pelo terminfo do
TERMinterno e repassá-las corretamente para corresponder ao terminfo externo - Portanto, o software envolvido precisa ser suficientemente recente
- o Ubuntu LTS atual oferece o mosh 1.3, então foi necessário ativar o PPA mosh-dev
- O
TERMdentro de cada camada também precisa estar correto- dentro do tmux, usa-se
tmux-direct - o mosh não tem um terminfo padrão, então é preciso escolher um valor suficientemente próximo
- dentro do tmux, usa-se
Configuração por ambiente
-
Emulador gráfico de terminal
- a maioria dos terminais define um
TERMpadrão apropriado ou permite que o usuário o substitua - o Konsole tem uma opção para escolher o valor de
TERM
- a maioria dos terminais define um
-
ssh
- o
sshtransmite o valor deTERMpara o novo shell - se o host remoto tiver o mesmo registro terminfo, a configuração fica relativamente simples
- o
-
tmux
- ao iniciar o tmux,
TERMpode ser definido comoscreen - isso é resolvido alterando o terminal padrão em
~/.tmux.conf
set -g default-terminal "tmux-direct"- também se pode considerar configurar
tmux-directcondicionalmente apenas quando oTERMexterno suportar cores de 24 bits; caso contrário, manterscreenoutmux-256color
- ao iniciar o tmux,
-
mosh
- versões recentes do mosh suportam cores de 24 bits, mas por conta própria anunciam apenas 8 cores ou 256 cores
- por isso, o usuário precisa configurar
TERMadequadamente - o mosh busca compatibilidade com xterm, mas em SGR 38 e 48 suporta apenas a sintaxe com ponto e vírgula
TERM=xterm-directnão funcionavscode-directfoi usado como a alternativa mais próxima dexterm-direct- como não há uma variável prática que indique que o mosh está em execução, foi escrito o script
detect-mosh.rse chamado em.bashrc - o método é verificar se o processo do shell é filho de
mosh-server - ainda não foi confirmado se compilar Rust no caminho de login é adequado para hosts de baixo desempenho
Resultado final e problemas restantes
- Depois da configuração, o tema no Emacs passou a ser exibido com cores de 24 bits mesmo dentro de tmux e mosh
- Os problemas restantes se resumem a três pontos
- os terminais ainda não concordam completamente em sintaxe e capacidades
- o terminfo é o caminho padrão para consultar capacidades
- o terminfo é limitado e às vezes impreciso, e novas versões também não são lançadas com tanta frequência
O caminho depois do terminfo
- Software que queira aproveitar plenamente recursos modernos de terminal precisa ir além do terminfo
- Algumas direções possíveis são
- continuar usando a variável
TERM, amplamente suportada - permitir que o programa conheça as capacidades do terminal de forma independente, sem depender apenas do terminfo desatualizado do sistema operacional ou da distribuição
- manter em bibliotecas atualizadas com frequência informações sobre emuladores de terminal da última década, com base em nome e versão
- não incluir suporte a terminais de hardware que já não são mais práticos de usar
- continuar suportando arquivos terminfo fornecidos pelo sistema operacional e o formato de arquivo terminfo, mas com um protocolo que permita decidir qual informação está mais atualizada
- usar
TERMVERSIONopcional para distinguir diferenças de capacidade por versão, como Konsole de 2022 e Konsole de 2023 - expressar sem ambiguidade recursos modernos como cores de 24 bits, animação de paleta de 256 cores, links de URL e o protocolo gráfico do Kitty
- continuar usando a variável
- Também é possível um caminho de retrocompatibilidade para programas legados
- um programa executado a partir de
.bashrcusaTERMeTERMVERSIONpara gerar arquivos binários terminfo em$HOME/.terminfo/ - gera capacidades claras de cor de 24 bits como
RGB,setf24esetb24 - para programas que não entendem RGB, assume-se uma paleta de 256 cores e mantém-se
colors#0x100,initceoc
- um programa executado a partir de
1 comentários
Comentários do Hacker News
Vasculhar o terminfo dá a sensação de iluminar hieróglifos com uma tocha tremeluzente em catacumbas profundas
É estranho quando se pensa em quanta complexidade existe em um único app de terminal, e isso me faz ser ainda mais grato aos desenvolvedores de terminais como iTerm e Kitty
Reuni algumas funções para definir a cor das abas no iTerm+zsh: https://gist.github.com/aclarknexient/84ebe33c1879f921685304...
Comparado ao jeito antigo de se conectar a HTTP ou SMTP via telnet, o texto em si é simples, mas o lado que exibe esse texto é um aplicativo complexo que dá suporte a todo tipo de recurso
Hoje isso é uma escolha possível porque, na prática, sou praticamente o único usuário desse terminal, mas terminais modernos dão suporte a um subconjunto comum razoável, o que é menos doloroso do que apps ficarem confusos por não reconhecerem um valor
TERMdesconhecidoClaro, se você não costuma entrar com SSH em sistemas novos, isso é um problema menos importante
Não é o emulador de terminal mais rápido, mas, em aparência, é disparado o melhor
Achei mais fácil ajustar a paleta de 16 cores em cada app de terminal do que acertar exatamente o código de terminal do lado dos aplicativos
Configurei as cores do rxvt-unicode em
~/.Xdefaultse, no tema.eldo Emacs, defini nomes de cores diferentes conforme a exibição fosse gráfica ou não, aplicando-os depois a várias facesDe quebra, a saída colorida do
lstambém ficou mais agradável. A paleta padrão de 16 cores muitas vezes tem saturação alta demais e contraste ruim(if (display-graphic-p)é o ponto centralO Emacs dá suporte a saída gráfica de verdade e, em X11/Cocoa/Win32, Esc funciona como Esc de verdade, além de permitir bindings com Ctrl+Shift ou Cmd, uso simultâneo de várias fontes, exibição de imagens, mudança do formato do cursor etc.
É como uma máquina do tempo que leva você para 1989, 20 anos no futuro
A linha vermelha só podia estar em vermelho forte ou desligada; quando se somava a linha de intensidade, virava vermelho a 100%
DIRCOLORS, olstambém dá suporte real a cores de 24 bitsAs cores padrão são escuras demais em relação a um fundo escuro, então aumentei a luminância de todas as cores
Acho que o autor teria sofrido muito menos se conhecesse
export COLORTERM=truecolorIsso aparece até na nota de rodapé sobre detecção de truecolor na documentação do Emacs vinculada e também na captura de tela do Konsole, mas é bem possível que tenha se perdido dentro de várias camadas de multiplexadores de terminal
Ao definir esse valor, o app entende imediatamente que você quer truecolor, então dá para pular a parte difícil, sem precisar do banco de dados terminfo
RGBMas nem todos os programas respeitam COLORTERM; por isso, em certo momento, eu deixava
COLORTERMunset no.bashrcquando eralinux | screen*e exportavaCOLORTERM=truecolornos demais casosHoje o Screen dá suporte a cores de 24 bits, então provavelmente era uma configuração da época do Ubuntu 18
trampousshfsPor outro lado, isso também acontece porque o mantenedor do ncurses é bastante conservador, enquanto novos desenvolvedores de terminais querem avançar rápido
Em versões mais antigas do Emacs, o banco de dados terminfo ainda é necessário
Na maioria dos casos não é preciso defini-lo, mas, se
COLORTERM=truecolorestiver definido em uma sessão do screen, de repente a tela fica muito esquisita; ao apagar a variável de ambiente, tudo volta ao normalAo interagir com o Emacs, não é obrigatório usar o terminal
É possível usar front-ends gráficos para MacOS, Windows, X.org e Wayland
Quando a barra de ferramentas fica desativada, o Emacs gráfico se parece tanto com o Emacs rodando no terminal que alguém que não conhece Emacs pode facilmente confundir a janela gráfica do Emacs no computador de um colega com uma janela de terminal
Em uma pesquisa com usuários do Emacs, 80% responderam que usam um front-end gráfico
xterm-mouse-modejá dá 80% dos benefíciosCom
mouse,xterm-mouse-mode,mouse-wheel-mode, configurações de rolagem etc., fica bem utilizável, eauto-save-defaultfica emnil, como Deus quisRodo todos os programas de terminal em buffers shell-mode do Emacs gráfico, e só uso term-mode para os raros programas que precisam de controle de tela inteira
Não é o mais cheio de recursos nem o mais rápido, mas dá para navegar como em qualquer outro buffer e lidar com ele de forma integrada ao conteúdo que estou editando
Se não consigo abrir o Emacs gráfico em um computador remoto, edito arquivos remotos via tramp ou inicio um servidor Emacs headless e me conecto com um emacsclient gráfico
Eu nunca tinha considerado que as pessoas poderiam achar que eu rodo o Emacs no terminal
O Emacs gráfico é muito melhor, mas ainda é excelente que, no terminal, uns 90% funcionem e apareçam da mesma maneira
A sensação é de ser tão leve quanto o terminal, não parece VNC
Há vantagens como fontes, uso simultâneo de outras fontes, menus, mouse, cores e vários frames/janelas
Rodando a parte gráfica localmente e acessando sistemas remotos via tramp, dá para editar até arquivos de configuração de um roteador remoto baseado em Linux que basicamente só tem busybox, com todo tipo de comodidade
Uso X11 de forma intermitente desde os anos 90, mas fontes ainda são algo que eu pesquiso até achar por acaso um comando que funciona e depois nunca mais mexo
O desempenho de exibição da maioria dos programas de terminal ainda é visivelmente mais rápido do que as configurações de X11 que acabo usando em ambientes corporativos
Hoje em dia, basta instalar um Emacs recente, abrir um terminal com suporte a xterm de 24 bits e executar
emacs -nwSe ficar bom depois de aplicar o tema, acabou; se não, adicione
export COLORTERM=truecolorao.bashrc,.zshrc,.fishrcetc., recarregue o shell ou execute só essa linha e reinicieemacs -nwEste texto faz parecer que é preciso fuçar no terminfo, mas em geral não é necessário. Talvez há 10 anos, mas hoje não
Reconfirmei rapidamente no iTerm no MacOS e no Alacritty, Kitty e Gnome Terminal no Linux, e hoje o suporte a xterm de 24 bits é comum
Hoje descobri que sequências de escape ANSI padrão também funcionam no Prompt de Comando do Windows 10
Cores de 24 bits também funcionam bem
Ao executar
echo ^[[48;2;255;0;0mHello^[[0m, Hello é exibido com fundo vermelhoRGB(255,0,0), e^[[0mrestaura a cor original^[deve ser digitado comCTRL-[; não se deve digitar^e[separadamente\x1bou o alias\ejunto com um comando que aceite códigos de escapePor exemplo, dá para fazer algo como
echo -e '\e[48;2;255;0;0mHello\e[0m'No entanto, em scripts,
echo -enão é padrão e oechocomum também difere em casos de borda, então é melhor sempre usarprintf '\e[48;2;255;0;0mHello\e[0m\n'DEVICE=C:\DOS\ANSI.SYSao arquivoC:\CONFIG.SYSComparado ao vim/neovim, o melhor do Emacs é que ele não é apenas um emulador de terminal dentro de uma janela: ele tem suporte a GUI de primeira classe
Sei que existe o gVim e inúmeros front-ends medianos para neovim, mas o modo padrão de executar o Emacs é uma GUI de verdade, e gosto disso
O terminal também é bom, mas tem resquícios históricos e limitações demais, e muita coisa já não faz sentido nos dias de hoje
Se executar Emacs em um servidor remoto for um problema, existem TRAMP e emacsclient
É frustrante quando um app GUI impede a cópia do texto exibido e obriga a redigitar manualmente
https://github.com/neovim/neovim/wiki/Related-projects#gui
Gosto muito de edição modal e do vim, mas era difícil tolerar a solução meio-termo oferecida por editores de terminal
Se existe uma plataforma gráfica rica, por que não usá-la?
Por exemplo, uso vim quase só para editar arquivos, e para ferramentas externas como
git, linters, formatadores, depuradores e manipulação da árvore de arquivos volto para o shellEntão minha aplicação principal já é o emulador de terminal, e nesse fluxo de trabalho a ausência de uma GUI dedicada importa muito pouco
Eu, por outro lado, queria que meu Emacs fosse assim: https://imgur.com/a/h0jA1ro
Não estou falando sério, é piada. Uso o Cool Retro Term só em apresentações
Pelo visto, no meu Emacs, cores de 24 bits funcionam por padrão: https://imgur.com/a/BM5OTxp
Só que o realce de sintaxe incomoda um pouco
O Cool Retro Term é excelente, e eu também gostaria de usá-lo em apresentações
Pessoalmente, os outros terminais retrô não ficam tão bonitos quanto ele
É realmente vergonhoso terem colocado o padrão atrás de um preço tão alto
As pessoas precisam contornar isso a esse ponto para não comprar, e esse tipo de resultado pode acontecer
Se é um padrão, deveria ser acessível. Na época em que só existia em forma de livro, talvez fizesse sentido cobrar pelos custos de impressão, mas é difícil acreditar que um PDF ruim custasse 200 dólares
Escrevi o patch de cores de 24 bits do xterm, mas só hoje descobri como fazer o ncurses funcionar com
xterm-directEu já usava minha própria biblioteca de terminal feita em Lisp, mas ainda é útil ter um caminho alternativo com ncurses
Agradeço ao Mr. Dickey pela resposta na pergunta do Stack Overflow e ao Chad por ter levantado esse assunto