New lines and terminals: CR vs. LF
I’m building a terminal emulator in go: gritty. I noticed that /bin/sh
is sending me the ASCII CR character back as a part of the response. I tend to absolutely ignore the CR because in my mind it’s a “Windows thing”.
But seeing the CR made me realise that I don’t have a clear idea about how new lines work. In my mind, new line = \n
but it might be more complex than that.
name | ASCII hex code | abbreviation | escape sequence* | Caret notation |
---|---|---|---|---|
Line Feed | 0x0A |
LF | \n |
^J |
Carriage Return | 0x0D |
CR | \r |
^M |
- Line Feed - Move the cursor one line down
- Carriage Return - Move the cursor to the beginning of the line
Historically, these two actions had to happen together so you or the computer can start typing text on the next line.
So why did I see the CR character when working on my terminal emulator? Well it shows that we live in the past, at least when it comes to terminals.
When shell sends a line feed character to the PTY, the TTY driver translates that to \r\n
for the terminal (emulator). This is dependent on the TTY driver settings.
stty -a
icrnl
(-icrnl
) - Map (do not map) CR to NL on input.onlcr
(-onlcr
) Map (do not map) NL to CR-NL on output.
So in summary, the terminals and the terminal emulators are still using \r
even on unix systems (for example when you press enter, terminal sends \r
to the shell). That’s why I saw it in my
- How do you call the string
\n
(backslash followed by lower case n)? It is called “escape sequence for newline character”. The escape sequence comes originally from C and JavaScript and Go both adopt it.
Helpful links
linux - Wrong newline character over serial port (CR instead of LF) - Super User