Tecnologia
lf e Yazi no lugar do Nautilus: onde o preview gráfico quebra
O terminal mostra imagem, mas o preview gráfico do lf tem limites reais. A tentativa com Ghostty, chafa e Hyprland, o que ela ensinou e por que o Yazi entrou no meu uso.
≈ 10 min74a3a6a
neste texto
Abrir o Nautilus para mover três arquivos sempre me pareceu um exagero de cerimônia: tirar a mão do teclado, mirar o mouse, clicar, arrastar. Eu queria um gerenciador de arquivos que vivesse onde eu já vivo: no terminal. O obstáculo de sempre, aquele que todo mundo repete: “mas no terminal você não vê as imagens”.
Acontece que essa frase está errada desde, pelo menos, 2017: o terminal mostra imagem. Mas a descoberta não transforma automaticamente o lf, um binário único de 6 MB, sem dependências de runtime, num substituto integral do Nautilus. O preview gráfico expõe uma fronteira real entre uma TUI de texto e um gerenciador de arquivos que controla uma interface gráfica inteira.
O lf não sabe fazer nada (e isso é a força dele)
lf (“list files”) é um gerenciador de arquivos de terminal escrito em Go, herdeiro do ranger.O ranger é escrito em Python e arrasta o interpretador inteiro a cada abertura. O lf é um executável estático único: abre instantâneo, e o lfrc de configuração é, literalmente, um shell script.
O que mais me chamou atenção não foi a velocidade, mas a filosofia: o lf não sabe abrir um PDF, tocar um vídeo nem mostrar uma imagem. Ele delega tudo a programas externos.
Isso parece limitação. É o oposto. Significa que você não recebe um app fechado com as decisões de outra pessoa. Você costura o gerenciador dos seus sonhos a partir de ferramentas que já existem no sistema. O lf é só a cola e a navegação. O modelo mental correto: ele não compete com o Nautilus, ele compete com cd + ls + mv. O que o eleva ao nível do Nautilus é o ecossistema que você pendura ao redor.
A tentativa: imagem de verdade no terminal
Terminais foram feitos para texto. Para mostrar um JPEG num grid de caracteres, o terminal precisa implementar um protocolo gráfico. Existem três grandes:
| Protocolo | Quem usa | Como funciona |
|---|---|---|
| Sixel | xterm, foot, terminais DEC antigos | bitmap codificado em texto |
| kitty graphics | kitty, Ghostty, WezTerm | imagem enviada via escape sequences |
| iTerm2 inline | iTerm2 (macOS) | base64 embutido na linha |
Eu uso o Ghostty, que implementa o kitty graphics protocol nativamente. É por isso que dá para ver a miniatura real de uma foto, não uma aproximação em ASCII art, mas o pixel.
A ponte entre o arquivo e o protocolo é o chafa. Ele lê a imagem e emite os escape codes que o Ghostty entende:
| |
A saída desse comando começa com ESC _ G a=T,f=32,...: a sintaxe do protocolo. O Ghostty recebe esses bytes e pinta a foto. Sem intermediário, sem servidor gráfico.
O bug que me travou (e o que ele ensina)
Aqui entra a parte que vale o post inteiro, porque é o tipo de armadilha que nenhum tutorial conta.
A primeira coisa que tentei foi a receita mais copiada da internet: usar o kitten icat no previewer. O previewer é o script que o lf chama toda vez que você move o cursor para um arquivo. Resultado: nada aparecia. O motivo é simples e ninguém avisa: o kitten é o utilitário do terminal kitty, e eu não uso o kitty. No Ghostty esse binário não existe. A receita popular pressupõe um terminal que eu não tenho.
A solução foi trocar kitten icat por chafa -f kitty, que fala o mesmo protocolo sem depender do kitty. Instalei o chafa, reabri o lf, e… apareceu uma sopa de letrinhas no painel de preview:
_Ga=T,f=32,s=434,v=256,c=62,r=16,m=1,q=2\_Gm=1;EBAQ/xAQEP8...

Os códigos do protocolo, impressos como texto em vez de virarem imagem. Foi aqui que a ficha caiu sobre como o lf funciona por dentro:
lf captura o stdout do previewer e imprime aquilo como texto dentro do painel. Se o chafa manda os escape codes para o stdout, o lf os trata como texto comum, e você vê a sopa de letrinhas, não a foto.A tentativa de correção foi escrever a imagem direto no terminal (/dev/tty), driblando a captura do lf, e posicionar o cursor na coordenada que o próprio lf informa. O lf passa ao previewer cinco argumentos: caminho, largura, altura, coluna (x) e linha (y). Usei x e y para mirar o canto do painel:
| |
Reabri o lf, parei o cursor sobre um JPEG, e a imagem renderizou no painel, idêntica ao que eu via rodando o chafa solto. Dois detalhes finos pareciam fechar o conjunto: o previewer terminava com exit 1 (código ≠ 0 diz ao lf para nunca cachear preview de imagem, forçando o redesenho); e um cleaner mandava a sequência “apague todas as imagens” (ESC _ G a=d ESC \) quando você saía do arquivo.
Correção posterior: LF_LEVEL, Wayland e o limite do painel
Depois de usar a configuração por mais tempo, apareceu um defeito intermitente: ao descer pela lista, a miniatura podia parar de atualizar; redimensionar a janela do Hyprland fazia o preview reaparecer. O lf exporta LF_LEVEL para marcar instâncias aninhadas, e o chafa altera seu comportamento quando encontra essa variável; env -u LF_LEVEL corrige uma parte do problema, como confirmado pelo mantenedor do lf na issue #2574.
Mas havia outra falha, mais fundamental: imagens transmitidas diretamente ao terminal não participam do repaint da TUI do lf. Ao navegar, o lf redesenha células de texto enquanto o Ghostty mantém a imagem gráfica em outra camada; o resultado são resíduos e caracteres aparentes na tela. Redimensionar força um repaint e mascara o defeito, mas não o corrige. Portanto, essa receita não é confiável no lf 41 com Ghostty e Hyprland.
O caminho que costuma ser indicado para esse cenário é o ueberzugpp, sucessor Wayland do overlay que o Ranger usava: ele desenha a imagem numa janela sobreposta ao painel, fora da grade de texto do lf. Não cheguei a adotá-lo; registro como a direção a testar, não como resultado.
E mesmo um preview que funcione não resolve tudo. Uma página de PDF cheia de texto, reduzida ao espaço de um painel, continua ilegível: aumentar a resolução da rasterização não cria espaço físico para as letras. O preview serve para identificar o arquivo, a página e o tipo de conteúdo; não para ler o documento. Foi nesse ponto que o Yazi entrou no meu uso, como conto no fim. O lf permanece excelente para navegação, seleção e operações de arquivo, mas não recebe aqui a promessa de substituir um navegador gráfico em todos os casos.

A lição de método é a que mais me interessa: a receita mais popular pressupunha um terminal que eu não usava, e o sintoma, letrinhas em vez de imagem, só fazia sentido depois de entender que o lf captura o stdout. Copiar config dos outros funciona até o dia em que não funciona; aí você precisa saber o que cada linha faz.
O ecossistema que faz o “nível Nautilus”
Imagem à parte, o resto é pendurar ferramentas. Cada uma assume um pedaço do que o Nautilus faz num pacote só:
| Ferramenta | Papel |
|---|---|
chafa | imagem pelo protocolo kitty, com as ressalvas acima, ou em caracteres como fallback |
trash-cli | lixeira no padrão freedesktop, a mesma do GNOME |
bat | preview de código com cor e número de linha |
eza | listagem de pasta com ícones |
glow | preview de Markdown renderizado |
poppler | rasteriza a 1ª página do PDF / extrai texto |
ffmpegthumbnailer | frame de miniatura de vídeo |
fd + fzf | busca fuzzy recursiva de arquivos e pastas |
zoxide | “teletransporte” para as pastas mais visitadas |
A lixeira merece nota. Em vez de um mv para uma pasta qualquer, o trash-cli escreve os metadados .trashinfo corretos, então o que você apaga no lf aparece na lixeira do sistema e pode ser restaurado de lá. Integração de verdade, não um arremedo.
PDF e vídeo seguem a mesma lógica: para PDF, o poppler rasteriza a primeira página num PNG temporário; para vídeo, o ffmpegthumbnailer extrai um frame. O preview vira uma função, e cada tipo de arquivo só precisa produzir uma imagem para ela. Com isso, herdam também o mesmo limite de repaint da imagem.
Quanto pesa o lf: ~20 MB de RAM
Um gerenciador de arquivos completo deveria pesar, certo? Medi na minha máquina, com o Nautilus e o lf abertos e ociosos, uma instância de cada. A medição é só do processo do lf; cada previewer chamado soma a sua memória enquanto roda:
| RSS | PSS, o footprint realRSS conta toda a memória mapeada pelo processo, incluindo bibliotecas compartilhadas com o resto do desktop. PSS divide cada biblioteca compartilhada pelo número de processos que a usam: é a medida mais justa de quanto um programa de fato “custa” a mais. | |
|---|---|---|
| Nautilus | 419 MB | 296 MB |
| lf | 21 MB | 15 MB |
O lf usa cerca de 1/20 da memória do Nautilus: uns 5% do footprint, para navegar e operar arquivos. E a diferença não está no binário (são 6 MB de Go contra 1,5 MB do Nautilus); está em tudo que o Nautilus arrasta atrás de si: GTK, thumbnailers, indexadores, daemons. O lf carrega o que você mandou carregar, e nada além.

Dá para conferir no seu próprio sistema, com os dois abertos:
| |
Você não baixou um app: montou o seu
É essa a diferença que eu queria registrar. O Nautilus é uma decisão fechada que você aceita inteira. O lf é um esqueleto de 6 MB sobre o qual você empilha exatamente as peças que usa, cada uma fazendo bem uma coisa só: a velha filosofia Unix, aplicada ao gesto mais banal do dia: andar entre arquivos.
E a frase “no terminal você não vê imagens” era só uma frase que ninguém tinha conferido. O que existe é outro limite, mais interessante: o de uma TUI de texto tentando conviver com uma camada gráfica.
Onde o Yazi entra no meu uso
Depois dessa experiência passei a usar também o Yazi, outro gerenciador de arquivos de terminal, escrito em Rust. A diferença que me levou a ele é justamente a deste texto: o Yazi trata o preview de imagem como parte do programa, e não como um script externo tentando desenhar por cima da interface. Ele detecta o protocolo gráfico do terminal e redesenha a imagem junto com o resto da tela, que é exatamente o ponto em que a minha receita com o lf quebrava.
Não troquei um pelo outro. O lf continua sendo a ferramenta mínima, configurável por shell script, muito próxima do modelo cd + ls + mv descrito aqui. O Yazi entra quando quero navegar entre imagens, PDFs e vídeos vendo o que estou escolhendo. São duas respostas para o mesmo gesto: sair do gerenciador gráfico sem abrir mão de navegar, pré-visualizar e operar arquivos com o teclado. Uma comparação dos dois, com medições reproduzíveis, fica para uma nota própria.
Aparato
O que sustenta este texto: fontes citadas, textos que o mencionam, vizinhança temática e histórico de revisão.
Cronologia
A ordem em que os textos entraram no acervo.
Revisão
Uma nota muda com o tempo; o histórico fica visível.
- publicado
- última revisão
- commit
74a3a6a- arquivo
artigos/lf-substituto-nautilus/index.md
Assuntos
Cada assunto abre o próprio índice.