ANSI 转ä¹ē ēę å
Source: Julia Evans
Hello! Today I want to talk about ANSI escape codes.
For a long time I was vaguely aware of ANSI escape codes (āthatās how you make text red in the terminal and stuffā) but I had no real understanding of where they were supposed to be defined or whether or not there were standards for them. I just had a kind of vague āthere be dragonsā feeling around them. While learning about the terminal this year, Iāve learned that:
- ANSI escape codes are responsible for a lot of usability improvements in the terminal (did you know thereās a way to copy to your system clipboard when SSHed into a remote machine?? Itās an escape code called OSC 52!)
- They arenāt completely standardized, and because of that they donāt always work reliably. And because theyāre also invisible, itās extremely frustrating to troubleshoot escape code issues.
So I wanted to put together a list for myself of some standards that exist around escape codes, because I want to know if they have to feel unreliable and frustrating, or if thereās a future where we could all rely on them with more confidence.
- whatās an escape code?
- ECMA-48
- xterm control sequences
- terminfo
- should programs use terminfo?
- is there a āsingle common setā of escape codes?
- some reasons to use terminfo
- some more documents/standards
- why I think this is interesting
whatās an escape code?
Have you ever pressed the left arrow key in your terminal and seen ^[[D?
Thatās an escape code! Itās called an āescape codeā because the first character
is the āescapeā character, which is usually written as ESC, \x1b, \E,
\033, or ^[.
Escape codes are how your terminal emulator communicates various kinds of information (colours, mouse movement, etc) with programs running in the terminal. There are two kind of escape codes:
- input codes which your terminal emulator sends for keypresses or mouse
movements that donāt fit into Unicode. For example āleft arrow keyā is
ESC[D, āCtrl+left arrowā might beESC[1;5D, and clicking the mouse might be something likeESC[M :3. - output codes which programs can print out to colour text, move the cursor around, clear the screen, hide the cursor, copy text to the clipboard, enable mouse reporting, set the window title, etc.
Now letās talk about standards!
ECMA-48
The first standard I found relating to escape codes was ECMA-48, which was originally published in 1976.
ECMA-48 does two things:
- Define some general formats for escape codes (like āCSIā codes, which are
ESC[+ something and āOSCā codes, which areESC]+ something) - Define some specific escape codes, like how āmove the cursor to the leftā is
ESC[D, or āturn text redā isESC[31m. In the spec, the ācursor leftā one is calledCURSOR LEFTand the one for changing colours is calledSELECT GRAPHIC RENDITION.
The formats are extensible, so thereās room for others to define more escape codes in the future. Lots of escape codes that are popular today arenāt defined in ECMA-48: for example itās pretty common for terminal applications (like vim, htop, or tmux) to support using the mouse, but ECMA-48 doesnāt define escape codes for the mouse.
xterm control sequences
There are a bunch of escape codes that arenāt defined in ECMA-48, for example:
- enabling mouse reporting (where did you click in your terminal?)
- bracketed paste (did you paste that text or type it in?)
- OSC 52 (which terminal applications can use to copy text to your system clipboard)
I believe (correct me if Iām wrong!) that these and some others came from xterm, are documented in XTerm Control Sequences, and have been widely implemented by other terminal emulators.
This list of āwhat xterm supportsā is not a standard exactly, but xterm is extremely influential and so it seems like an important document.
terminfo
In the 80s (and to some extent today, but my understanding is that it was MUCH more dramatic in the 80s) there was a huge amount of variation in what escape codes terminals actually supported.
To deal with this, thereās a database of escape codes for various terminals called āterminfoā.
It looks like the standard for terminfo is called X/Open Curses, though you need to create an account to view that standard for some reason. It defines the database format as well as a C library interface (ācursesā) for accessing the database.
For example you can run this bash snippet to see every possible escape code for āclear screenā for all of the different terminals your system knows about:
for term in $(toe -a | awk '{print $1}')
do
echo $term
infocmp -1 -T "$term" 2>/dev/null | grep 'clear=' | sed 's/clear=//g;s/,//g'
done
On my system (and probably every system Iāve ever used?), the terminfo database is managed by ncurses.
should programs use terminfo?
I think itās interesting that there are two main approaches that applications take to handling ANSI escape codes:
- Use the terminfo database to figure out which escape codes to use, depending
on whatās in the
TERMenvironment variable. Fish does this, for example. - Identify a āsingle common setā of escape codes which works in āenoughā terminal emulators and just hardcode those.
Some examples of programs/libraries that take approach #2 (ādonāt use terminfoā) include:
I got curious about why folks might be moving away from terminfo and I found this very interesting and extremely detailed rant about terminfo from one of the fish maintainers, which argues that:
[the terminfo authors] have done a lot of work that, at the time, was extremely important and helpful. My point is that it no longer is.
Iām not going to do it justice so Iām not going to summarize it, I think itās worth reading.
is there a āsingle common setā of escape codes?
I was just talking about the idea that you can use a ācommon setā of escape codes that will work for most people. But what is that set? Is there any agreement?
I really do not know the answer to this at all, but from doing some reading it seems like itās some combination of:
- The codes that the VT100 supported (though some arenāt relevant on modern terminals)
- whatās in ECMA-48 (which I think also has some things that are no longer relevant)
- What xterm supports (though Iād guess that not everything in there is actually widely supported enough)
and maybe ultimately āidentify the terminal emulators you think your users are going to use most frequently and test in thoseā, the same way web developers do when deciding which CSS features are okay to use
I donāt think there are any resources like Can I useā¦? or Baseline for the terminal though. (in theory terminfo is supposed to be the ācaniuseā for the terminal but it seems like it often takes 10+ years to add new terminal features when people invent them which makes it very limited)
some reasons to use terminfo
I also asked on Mastodon why people found terminfo valuable in 2025 and got a few reasons that made sense to me:
- some people expect to be able to use the
TERMenvironment variable to control how programs behave (for example withTERM=dumb), and thereās no standard for how that should work in a post-terminfo world - even though thereās less variation between terminal emulators than there was in the 80s, thereās far from zero variation: there are graphical terminals, the Linux framebuffer console, the situation youāre in when connecting to a server via its serial console, Emacs shell mode, and probably more that Iām missing
- there is no one standard for what the āsingle common setā of escape codes is, and sometimes programs use escape codes which arenāt actually widely supported enough
terminfo & user agent detection
The way that ncurses uses the TERM environment variable to decide which
escape codes to use reminds me of how webservers used to sometimes use the
browser user agent to decide which version of a website to serve.
It also seems like itās had some of the same results ā the way iTerm2 reports itself as being āxterm-256colorā feels similar to how Safariās user agent is āMozilla/5.0 (Macintosh; Intel Mac OS X 14_7_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Safari/605.1.15ā. In both cases the terminal emulator / browser ends up changing its user agent to get around user agent detection that isnāt working well.
On the web we ended up deciding that user agent detection was not a good practice and to instead focus on standardization so we can serve the same HTML/CSS to all browsers. I donāt know if the same approach is the future in the terminal though ā I think the terminal landscape today is much more fragmented than the web ever was as well as being much less well funded.
some more documents/standards
A few more documents and standards related to escape codes, in no particular order:
- the Linux console_codes man page documents escape codes that Linux supports
- how the VT 100 handles escape codes & control sequences
- the kitty keyboard protocol
- OSC 8 for links in the terminal (and notes on adoption)
- A summary of ANSI standards from tmux
- this terminal features reporting specification from iTerm
- sixel graphics
why I think this is interesting
I sometimes see people saying that the unix terminal is āoutdatedā, and since I love the terminal so much Iām always curious about what incremental changes might make it feel less āoutdatedā.
Maybe if we had a clearer standards landscape (like we do on the web!) it would be easier for terminal emulator developers to build new features and for authors of terminal applications to more confidently adopt those features so that we can all benefit from them and have a richer experience in the terminal.
Obviously standardizing ANSI escape codes is not easy (ECMA-48 was first published almost 50 years ago and weāre still not there!). I donāt even know what all of the challenges are. But the situation with HTML/CSS/JS used to be extremely bad too and now itās MUCH better, so maybe thereās hope.