Introduction

At this point, there are hundreds of graphical terminal emulators out there. Every single one that I have run into pretends like it is some varient of a hardware terminal made by Digital Equipment Corporation (DEC) from their Video Terminal (VT) line of products, from 1978’s VT100 through 1993’s VT525.

A reader might chime in here and say, no MY TERMINAL thinks it is an xterm, but alas xterm pretends to be a VT420 (xterm can actually pretend it is many different terminals, so even if you DO use THE xterm software I doubt your computer is actually set up to most efficiently talk to it, I’ll talk about that later ).

First, the language a computer uses to access a terminal’s capabilities like, clear the screen, move the cursor, start printing inverse color, etc., are called Control Codes. Second, is that there was a standard created for control codes: ANSI X3.64-1979 The first product to market to mostly follow these standards was the DEC VT100 (several months before they were published).

About X3.64-1979

This document, which I’ll refer to as The Standard, isn’t easy to read because it refers to characters not by the common GLYPHS and Abbreviations we are used to seeing in a common ASCII chart, but instead a 4/4 bit split, using decimal. That is ? is referenced as 5/15 which these days would be talked about in HEX x5F, and this notation is true throughout The Standard.

The Standard also makes it clear that NO single product is expected to implement every code but should be aware of the paramters for codes so that a product can know to ignore the codes it doesn’t implement. With the exception of iTerm2, every Terminal I’ve used mostly follows The Standard.

The Standard’s Non-Standard Carve-out

The Standard specifies that there are four entries to special controls; SS2, SS3, ESC and CSI. The SS (Single Shift) entries aren’t relevant here, but the ESC and Control Sequence Introducer are relevant.

ESC is character 1/11 or x1B. The standard only assigns four functions that exist past an ESC without the [ (5/11 / x58) which turns it into CSI.

  • 8-bit ASCII: CSI is a standalone character, CSI 8/11 or x8B.
  • 7-bit ASCII: CSI is two characters: ESC [ 1/11 5/11 or x1B x5B.

Unicode only preserved the 7-bit ASCII table, and CSI being in the 8 bit range, moved the CSI into a different place, so unless a terminal emulator still uses a retro-8bit ASCII code-page mode, it is easier to use the 7-bit control varient given that Unicode CSI doesn’t save any transmitted bits.

After the CSI, The Standard suggests that parameters can start. The first position of the first parameter, though, is restricted. ASCII 0 through ; / x30 - x3B indicates something that is either defined by The Standard or reserved for future standards. However, ASCII <, =, > and ? ( x3C - x3F ) are reserved for “Private Parameter”. This means that this indicates something that will never be defined by the standard, and is a safe place to indicate feature parameters that are not covered by The Standard.

DEC Video Terminals and the Device Capability Feature

Before the standard, The DEC VT50 had a control initiated by ESC Z which DEC named DECID. DECID is NOT one of the four “ESC Fn” codes in The Standard. The DEC VT100 would also respond to this, but it was not part of The Standard, and the manuals begged users to stop relying on its existence (VT400 and later terminals ignore it). Instead of DECID, DEC instead did something more weird. They created a control called Device Attributes (DA) which was accessed with CSI c (ESC [ c). This gets a bit complicated but c is inside the range of characters reserved for future standards, so it should not have been grabbed by DEC for this function.

That is I’m starting out to say that DEC itself doesn’t fully follow The Standard. I would guess they figured if they sold enough terminals, nobody would assign something else to that function, and, well, they were right in taking that gamble.

Later, with the VT220, they kept Device Attributes but also added what they called a Secondary DA. That DID follow The Standard: CSI < c, which uses the < character to designate that this is, at least, a “Private Parameter”. Though the final function still shouldn’t be c, by setting a Private Parameter, is at least makes other ANSI compliant terminal know to not try to figure out the meaning, even were c to be given a standardized function meaning later. Good job on the bare minimum. Secondary DA would return the sub-model within a range, a firmware version of the terminal, and an indicator of hardware feature (special keyboard or internal modem). Outside of xterm itself, all Terminal Emulators I have tested pick some numbers, and never change it no matter how much the software itself changes.

Most currently maintained Terminal Emulators respond to Device Attributes and Secondary DA, even if the Device Attributes response indicates a VT100 model that didn’t support the secondary feature. Note that the VT400 line also introduced Tertiary DA.

Broken Terminal Emulators

Claiming to Be, But Not Actually

Several terminal emulators take a safe route by claiming to be a VT100 or VT102. Since this is the first ANSI Escape sequence terminal, they have less features than subsequent Video Terminal models.

\033[?1;0c VT100 without Advanced Video Option (AVO) \033[?1;2c VT100 with AVO (underline, blink, bold, reverse video) \033[?6c VT102 zero option version of the VT100

Terminal emulators that claim to be a VT102 or VT100 without options are claiming that they cannot even do underline, bold, blink or reverse video. Yet, all of them can do these things (or, at least they’ll use brighter colors to emulate Bold, which a VT100 couldn’t do).

VT200 and higher terminals have controls to protect an area of the screen from overwrite or overrun. Few terminal emulators can do this correctly. That requires programs to be extra careful to wrap their own text to stay out of protected areas (that aren’t actually protected).

Mislabeled Device Attributes

DEC terminal products from VT200 included a DA response that listed out features numerically. Has printer, has alternate code-page, has graphics, etc. Again, xterm does a good job emulating these correctly, but many terminal emulators seem to just put something else’s answer in as the return.

\033[?62;4c VT200 ONLY 80 columns supporting sixel graphics.

Does it Really support Sixel? xterm does in the right emulation mode, iTerm2 does. If not, don’t do this.

\033[?65;1;9c VT540 supporting 132 character width and 7bit National Replacement Character sets.

For those that talk Unicode, option 9; 7bit National Replacement Character Sets, doesn’t really make sense anymore.

Color

The DEC VT340 and VT525 products did color. If your terminal emulator does support color, maybe try emulating one of those models? But no, “I’m a VT100” respose probably also means “I can do color”. Nothing indicates color depth either. xterm DA will include a 22 to indicate color support, but is that 8, 16, 88, 256 or even Direct Color? “Direct Color” can theoretically support 48 bit color. Nothing is available to tell the software which is available. Sigh.

Unicode

Unicode was first published before the last DEC terminal was designed, but it was hard-coded 16-bit (two byte) at the time, and had far more code points that most Terminal buyers would need anyway. That is, the VT500 series was still 7 or 8bit ASCII with swappable code-pages.

Since 1994 and the last DEC Video Terminal debut, UTF-8 has slowly become the defacto standard, and terminal emulators have been quietly adding support for UTF-8, led (as was the typicaly case) by xterm.

Since xterm didn’t add a response number to indicate UTF8, nobody else did either. That means there’s no way for a program to ask a terminal if it is expecting ASCII or UTF-8. After 2010, most programs just assume that UTF-8 will be accepted but that’s a weird expectation.

This ALSO means that even terminals that claim to be an 8bit capable DEC terminal just no longer support the CSI character (under Unicode, it is no longer a single byte, but was moved into a two byte range, yet that isn’t a valid reason to drop this support entirely).

Glyph support

This didn’t matter much in the days of 7bit ASCII, but in the Unicode era it would be super helpful for a program to be able to ask the terminal if a certain codepoint can actually be printed or not. If my program wants to drop a beer emoji (like homebrew), I have to do a lot of guess-work to figure out if that is possible. Worse, if my terminal program wants to print traditional Chinese characters as still used on the island of Taiwan, I no longer have a way of checking if such a thing is available.

iTerm2 abusing The Standard

iTerm2 does this weird thing of introducing new controls in reserved space, with several new controls that start with ESC ] 1 which doesn’t start with the CSI (that terminals were taught to ignore if they don’t understand them), and ends with The Standard’s 7bit ST (ESC \\). It makes the Zeroth Parameter into a Sub Function designator and the Oneth Parameter into a Sub Function selector.

Terminal capabilities and Terminfo

There’s this great bit of software and sets of libraries that are able to map a terminal’s capabilities into the Control Codes that that terminal ACTUALLY uses. There’s even a very extensive file that includes those definitions for a huge number of terminals and terminal emulators.

Do you use the new Windows Terminal on Win 10 or 11? That one’s entry is ms-terminal. Do you use the default Terminal.app on macOS? That is nsterm. What about Konsole (konsole) or Gnome Terminal (vte) on Linux. How about xterm … uh… Well… That’s a problem.

If you actually use xterm (it’s ugly and few people can tolerate it these days), then you actually DON’T want to use the xterm entry at all.

The xterm and xterm-256color entries are purosely hobbled because most modern terminal emulators ask for the xterm entry, claiming compatability, when they just aren’t fully there. That means, the xterm entry is a pared down entry of VT102 basic controls that everyone generally has, forcing software to do things with padding or extra cursor moves because actual features are reported as missing … for the lowest common denominator.

Being Awkwardly Good: KiTTY

I won’t use it because it forces bash into POSIX mode on purpose, but as far as a terminal emulator, the KiTTY terminal emulator is awkwardly good. It does NOT ask to be treated like an xterm like everything else. Instead it installs it’s own terminfo (it’s called xterm-kitty, awkward name, but unique), and with ssh integration it will even forward its own entry to any computer you log into. It’s a rare case where even if KiTTY does everything else wrong, it doesn’t matter because a program can trust that it has the best terminal definitions avaible already.

Writing a Terminal Program?

Stop Pretending to be Something Else

Please do support the Device Attributes, Secondary DA and Tertiary DA entries, but don’t reply with stock answers. Let it be the different thing that it is.

\033[?13;...c There was never a VT that answered between 13 and 61. \033[?66;...c There was never a six series VT, it’s there and open.

New Feature Flags

The highest feature number I’ve seen is 46.

Go ahead a reserve a feature number for explicit UTF-8 support. The first one to do it and document it is likely to become the standard maker.

Go ahead and make a scheme for color supports. 8, 16, 88, 256, and Direct are all out there, but don’t have option numbers.

Will this be the first one to add a feature for telling a program if a Glyph is printable? Will this be the first one to have a way to explicitly say how wide a glyph actually will print?

Learn from KiTTY, supply a terminfo entry.

Even if a terminal emulator is designed to be compatible with the stripped down xterm terminfo, if it has ANY features beyond that, it should start shipping a terminfo source file with all of its features.