Explorando o "Fim da Linha" em seus projetos.
Parece coisa boba, mas o fim de linha de um arquivo é um detalhe técnico que tem sua devida importância, especialmente em projetos colaborativos. Entender alguns conceitos, assim como o funcionamento e seus impactos é essencial para garantir projetos mais robustos, colaborativos e compatíveis com diferentes plataformas.
EOL - End Of Line
📄 Quando a gente digita um texto e pressiona Enter
para iniciar uma nova linha, o que na verdade acontece nos bastidores é a inserção de um caractere especial que marca o término da linha. Sem esse caractere, um arquivo seria apenas uma sequência interminável de texto.
O Git, por exemplo, espera que os arquivos de texto do projeto estejam com o fim da linha definido. Inconsistências nesse aspecto podem gerar conflitos ao fazer commits, merges ou até mesmo na simples visualização das diferenças entre versões de arquivos.
Esses caracteres são padrões de End Of Line (EOL) e definem como o sistema deve tratar o comportamento da quebra de linha. O caractere invisível usado é chamado de Newline
, e é o que faz o sistema entender onde será o ponto de quebra naquele arquivo para começar uma nova linha, definindo que uma linha terminou.
Editores de codigo escondem, e tornam invisível o caractere de fim da linha, porém eles podem ser representados como Strings ou ASCII: 0x0D
0x0A
\r
\n
e etc.
⚙️ Essa convenção de Newline
em arquivos de texto surgiu no UNIX, e indica que o arquivo terminou por completo. Porém, há diferentes abordagens para esses padrões de caracteres de controle que marcam a quebra de linha em um arquivo de texto: CR
e LF
.
CR = Carriage Return
- Este caractere move o cursor para o início da linha atual, sem avançar para a próxima linha. Antigamente, o Mac OS utilizava apenas
CR
.
LF = Line Feed
- Este caractere move o cursor para baixo (linha seguinte). Ou seja, para a próxima linha, mas sem retornar ao início dessa linha. Este caractere é usado por padrão como caractere de nova linha em sistemas baseados em Unix/Linux.
É também utilizada a sequência
CR
+LF
(CRLF)
, que é uma combinação dos dois acima. Ou seja, são usados dois caracteres de forma combinada. Nesse caso ele move o cursor para baixo, para a próxima linha, e também move para o início dessa linha. Este padrão é utilizado por exemplo no Windows.
No editor VS Code, é possível visualizar e alterar o padrão de fim de linha dos arquivos. Basta clicar no canto inferior direito da janela, onde o padrão atual de EOL
é exibido.
Aplicação prática
🌱 Um exemplo de aplicação prática disso é que recetemente a ferramenta spring initializr
(API que gera um projeto Spring Boot rapidamente) adotou como padrão a geração automática do arquivo .gitattributes
, a fim de fazer correções de fim de linha, definindo o comportamento esperado do EOL
para diferentes tipos de arquivos, garantindo consistência nos projetos e repositórios.
/mvnw text eol=lf
*.cmd text eol=crlf
Por exemplo, arquivos de scripts do Windows como bat
e cmd
precisam de CRLF
, enquanto que comandos shell *.sh
seguem o padrão LF
.
O arquivo .gitattributes
pode definir vários elementos, e é muito útil para estabelecer um padrão que os colaboradores devem seguir no repositório, independente de como a IDE/editor eteja configurada. Com esse arquivo, configurações do Git podem ser substituídas nos arquivos que tiverem o atributo EOL
especificado no .gitattributes
. E por isso muitas vezes você recebe no Git por exemplo warnings como:
"LF will be replaced by CRLF in <filename>."
text=auto
: O Git manipula automaticamente os arquivos.
text eol=crlf
: O Git sempre converterá delimitadores de linha emCRLF
no check-out.
text eol=lf
: O Git sempre converterá delimitadores de linha emLF
no check-out.
A Origem do CR e LF
🧐 Por fim, uma curiosidade é que esses dois caracteres são expressões que tem origem nas antigas máquinas de escrever.
Carriage Return (CR): "Retorno do carro". Referência ao mecanismo que movia o cabeçote da máquina para o início da linha.
Line Feed (LF): Alimentava o papel para a próxima linha, movendo o papel para cima. Permitindo que o cabeçote da máquina ou o ponteiro continuasse imprimindo na linha seguinte.