← back

ʕ•ᴥ•ʔ Construindo um Editor de Texto em C - Parte 1

#c #terminal #programming #text-editor

Estou seguindo o tutorial Build Your Own Text Editor para construir um editor de texto simples em C, chamado Kilo. O objetivo é entender conceitos fundamentais de programação de baixo nível e manipulação de terminal.

Manipulação de Terminal em Modo Raw

Uma das primeiras coisas que aprendi foi como manipular o terminal no chamado modo raw (ou "modo cru"). Diferente do comportamento padrão do terminal, onde a entrada é processada linha a linha, o modo raw nos dá controle direto sobre cada tecla pressionada.

No Unix/Linux, o terminal normalmente opera em modo canônico (cooked mode), onde a entrada só é enviada ao programa quando o usuário pressiona Enter. O modo raw permite capturar cada tecla imediatamente.

A Estrutura termios

Para manipular o terminal, utilizamos a estrutura termios, que contém todas as configurações do terminal:

struct termios {
    tcflag_t c_iflag;    // flags de entrada 
    tcflag_t c_oflag;    // flags de saída
    tcflag_t c_cflag;    // flags de controle
    tcflag_t c_lflag;    // flags locais
    cc_t c_cc[NCCS];     // caracteres de controle
};

Configurando o Modo Raw

Para implementar o modo raw, precisamos desativar várias flags do terminal:

Flags desativadas

  • ECHO: não mostra caracteres digitados
  • ICANON: desativa modo canônico
  • ISIG: desativa sinais como Ctrl+C
  • IXON: desativa controle XON/XOFF
  • IEXTEN: desativa sequências estendidas
  • OPOST: desativa processamento de saída

Bandeiras ativadas

  • CS8: configura caracteres de 8 bits
  • VMIN = 0: retorna imediatamente da leitura
  • VTIME = 1: timeout de 0.1 segundos

Aqui está o código que implementa o modo raw:

void enableRawMode() {
    if (tcgetattr(STDIN_FILENO, &orig_termios) == -1) die("tcgetattr");
    atexit(disableRawMode);

    struct termios raw = orig_termios;
    raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    raw.c_oflag &= ~(OPOST);
    raw.c_cflag |= (CS8);
    raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
    raw.c_cc[VMIN] = 0;
    raw.c_cc[VTIME] = 1;

    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) die("tcsetattr");
}

Usamos o operador bitwise &= ~ para desativar flags e |= para ativá-las, sem afetar as outras flags.

Gerenciamento de Recursos

Uma parte importante da programação em C é o gerenciamento adequado de recursos. Nesse editor, registramos uma função disableRawMode() com atexit() para garantir que o terminal seja restaurado ao seu estado original quando o programa terminar:

void disableRawMode() {
    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios) == -1)
        die("tcsetattr");
}

Sempre restaure o estado original dos recursos que você modificar, mesmo em caso de erro ou término abrupto do programa.

Tratamento de Erros

O código também implementa uma função die() para tratamento de erros:

void die(const char *s) {
    perror(s);
    exit(1);
}

Esta função usa perror() para exibir uma mensagem de erro descritiva baseada no valor atual de errno, e então termina o programa com código de erro.

Conceitos Fundamentais Aprendidos

Conceito Descrição
Modo Terminal Diferença entre modo canônico e modo raw
Estrutura termios Como configurar o comportamento do terminal
Tratamento de Erros Uso de errno e perror() para diagnosticar problemas
Manipulação de Bits Uso de operadores bitwise para modificar flags
Gerenciamento de Recursos Importância de restaurar estados originais

Próximos Passos

Nos próximos capítulos do tutorial:

  1. Entrada e exibição de texto
  2. Manipulação do cursor
  3. Operações de edição (inserir, excluir texto)
  4. Operações de arquivo (abrir, salvar)
  5. Busca e destaque de sintaxe

Recursos

Se você quiser acompanhar meu progresso ou ver o código-fonte completo, confira: