Skip to main content

Queries a terminal emulator for its type, size and capabilities

Project description

Downloads codecov.io Code Coverage Windows supported Linux supported MacOS supported BSD supported

ttyscan

ttyscan queries a terminal emulator for its type, size and capabilities, creating a curses-compatible terminfo(5) file entry if necessary, and exports any corrected values of TERM, COLORTERM, LINES, COLUMNS, and optionally TERMCAP environment variables.

Problem

ncurses does not support XTGETTCAP, and so terminfo(5) files for some terminals must be deployed to remote systems by system operators in some circumstances.

Curses programs fail to start until those files are deployed or an alternate TERM is exported. All kinds of errors and warnings may be raised until this is done, some examples:

$ tmux attach
missing or unsuitable terminal: xterm-kitty

$ irssi
setupterm() failed for TERM=xterm-kitty: 0
Can't initialize screen handling.

$ htop
Error opening terminal: xterm-kitty.

$ python -c 'import curses;curses.setupterm()'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
_curses.error: setupterm: could not find terminal

$ git log -p
WARNING: terminal is not fully functional
Press RETURN to continue

Solution

ttyscan creates the missing terminfo(5) file using the XTGETTCAP (DCS +q) terminal query protocol when supported, and suggests a new TERMINFO environment value for export, allowing legacy calls to curses of setupterm(3) to succeed:

$ ttyscan -vft
ttyscan: probing terminal via XTGETTCAP ...
ttyscan: size via dual CPR: 28x100
ttyscan: XTGETTCAP supported, terminal: rio; received 198 caps (11 bool, 5 num, 178 str) in 4ms
ttyscan: writing /home/jq/.config/ttyscan/terminfo/r/rio
export COLORTERM=truecolor
export TERM=rio
export LINES=28
export COLUMNS=100
export TERMINFO=/home/jq/.config/ttyscan/terminfo
export TERMCAP='rio|XTGETTCAP-discovered terminal::am::ut::hs::km::5i::mi::ms::NP::xn::Co#256::co#80::it#8::li#24::pa#32767::ac=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~::bl=^G::mb=\E[5m::md=\E[1m::bt=\E[Z::vi=\E[?25l::cl=\E[H\E[2J::ve=\E[?12l\E[?25h::cr=\r::cs=\E[%i%p1%d;%p2%dr::le=\b::DO=\E[%p1%dB::do=\n::nd=\E[C::cm=\E[%i%p1%d;%p2%dH::up=\E[A::vs=\E[?12;25h::dC=\E[P::mh=\E[2m::dl=\E[M::ds=\E]2;^G::ec=\E[%p1%dX::cd=\E[J::ce=\E[K::cb=\E[1K::vb=\E[?5h$<100/>\E[?5l::fs=^G::ho=\E[H::ch=\E[%i%p1%dG::ta=\t::st=\EH::al=\E[L::sf=\n::mk=\E[8m::is=\E[!p\E[?3;4l\E[4l\E>::K2=\EOE::kb=^?::kB=\E[Z::kl=\EOD::kd=\EOB::kr=\EOC::ku=\EOA::kD=\E[3~::@7=\EOF::@8=\EOM::k1=\EOP::k0=\E[21~::F1=\E[23~::F2=\E[24~::k2=\EOQ::k3=\EOR::k4=\EOS::k5=\E[15~::k6=\E[17~::k7=\E[18~::k8=\E[19~::k9=\E[20~::kh=\EOH::kI=\E[2~::kH=\E[1;2B::kN=\E[6~::kP=\E[5~::ps=\E[i::pf=\E[4i::po=\E[5i::op=\E[39;49m::rp=%p1%c\E[%p2%{1}%-%db::mr=\E[7m::sr=\EM::ZR=\E[23m::ae=\E(B::te=\E[?1049l\E[23;0;0t::ei=\E[4l::ke=\E[?1l\E>::se=\E[27m::ue=\E[24m::r1=\Ec\E]104^G::r2=\E[!p\E[?3;4l\E[4l\E>::sa=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p5%t;2%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m::me=\E(B\E[m::ZH=\E[3m::as=\E(0::ti=\E[?1049h\E[22;0;0t::im=\E[4h::ks=\E[?1h\E=::so=\E[7m::us=\E[4m::ct=\E[3g::ts=\E]2;::cv=\E[%i%p1%dd:'

$ eval `ttyscan`

$ echo $TERM, $TERMINFO
rio, /home/jquast/.config/ttyscan/terminfo

$ file -b /home/jquast/.config/ttyscan/terminfo/r/rio
Compiled terminfo entry "rio"

$ python -c 'import curses;curses.setupterm()'; echo $?
0

CLI Arguments

usage: ttyscan [-h] [-v] [-f] [-t]

Export terminal capabilities discovered via XTGETTCAP

options:
  -h, --help     show this help message and exit
  -v, --verbose  Print diagnostic information to stderr
  -f, --force    Force export of all values even if unchanged
  -t, --termcap  Also export TERMCAP value

ttyscan saves a terminfo(5) file to $XDG_CONFIG_HOME/ttyscan/terminfo or ~/.config/ttyscan/terminfo, and does not re-query or re-create it when it already exists from previous executions, unless --force argument is used.

Typical total execution time is under 200ms. The default timeout query can be changed by environment value TTYSCAN_QUERY_TIMEOUT=1.0 (float), in seconds. If timeout is reached, terminal response may “bleed” into subsequent programs, (like a shell prompt).

Installation

pip install ttyscan

ttyscan requires Python3.8+.

ttyscan.py is a stand-alone python file, it does not require pip to install, you can copy this single file directly from source and execute it from source, eg. python ~/bin/ttyscan.py

Motive

Naturally, transferring your $HOME/.terminfo folder to a remote machine is the best solution.

However, enterprise systems, bastion hosts, cloud systems, web consoles, hypervisors, radio, and serial ports can be challenging places or protocol layers through which to deploy terminfo files.

Some workarounds include exporting a generally-compatible TERM=xterm-256color or xterm with sometimes minor corruption of screen output, missed interpretation of keyboard input such as backspace or delete, or a small reduction of features such as italic or underlined text or number of colors.

And so this tool is not often needed except for the very serious terminal connoisseur.

It serves as a demonstration: that a full terminal capability database can be transferred using XTGETTCAP for many modern terminals. My hope is that ncurses and setupterm(3) could negotiate with full XTGETTCAP support at some point in the future, and that this utility is not commonly used or required!

Scope

At time of this writing (May 2026), the ucs-detect dataset of 42 terminals shows three categories of support for XTGETTCAP:

  • Full XTGETTCAP capability support: contour, foot, ghostty, kitty, rio, and wezterm transmit their complete terminfo boolean, numeric, and string capabilities via XTGETTCAP.

    ttyscan produces terminfo files for only these terminals. ttyscan may also discover a preferred TERM from TN, and COLORTERM=truecolor from RGB.

  • Partial XTGETTCAP capability support: XTerm, iterm2, mlterm, AbsoluteTelnet/SSH, GNOME Terminal, LXTerminal, terminator, termit, and xfce4-terminal report only TN, Co, and RGB.

    ttyscan may only discover preferred TERM from TN, and COLORTERM=truecolor from RGB.

    XTerm supports only keyboard sequences in addition to TN, Co, and RGB. It does not report all capabilities, and so a terminfo(5) entry cannot be built. However, TERM=xterm-256color and TERM=xterm are the most ubiquitous terminal name, you should be just fine.

  • None: alacritty (refuses: alacritty/vte#98), bobcat, cmd.exe, ConEmu, cool-retro-term, Extraterm, Hyper, Konsole (requested: KDE#507017), linux fbdev, mintty, PuTTY, QTerminal, rxvt-unicode, screen, securecrt, st, Tabby, Apple Terminal, Terminal.exe (planned: microsoft/terminal#17735), terminology, tmux (passthrough: tmux/tmux#3755), libvterm, VS Code (xterm.js, proposal: xtermjs/xterm.js#4107), weston-terminal, and zutty.

Architecture

ttyscan uses the following,

  • XTGETTCAP field TN is used to correct TERM when unmatched.

  • XTGETTCAP field RGB is used to correct COLORTERM when unmatched.

  • all capability strings, keyboard and screen, when provided by XTGETTCAP.

  • DEC Private Mode 2048 (In-Band Resize) to determine the window size

  • Or failing that, using Cursor Position Report sequence like done in XTerm’s resize.c

Details

The difference of Full and Partial XTGETTCAP support is best described by foot:

XTGETTCAP is an escape sequence initially introduced by XTerm, and also implemented (and extended, to some degree) by Kitty.

Applications using this feature do not need to use the classic, file-based, terminfo definition.

XTerm’s implementation (as of XTerm-370) only supports querying key (as in keyboard keys) capabilities, and three custom capabilities:

TN - terminal name Co - number of colors (alias for the colors capability) RGB - number of bits per color channel (different semantics from the RGB capability in file-based terminfo definitions!).

Kitty has extended this, and also supports querying all integer and string capabilities.

Foot supports this, and extends it even further, to also include boolean capabilities. This means foot’s entire terminfo can be queried via XTGETTCAP.

Further, all of TERM, COLORTERM, LINES, or COLUMNS may not be transmitted by all software or protocols, some examples:

  • ssh does not forward COLORTERM unless configured using SendEnv in ssh_config(5) and AcceptEnv in sshd_config(5).

  • serial does not forward any; TERM is defined by host agetty(8) configuration, for example.

  • rlogin can forward all but COLORTERM.

  • telnet can forward all, but IAC NAWS and NEW-ENVIRON capability varies by software.

  • websocket cannot forward any without customization, often used in-browser.

ttyscan detects when these variables are unset or do not match values and re-exports the corrected values when they differ.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ttyscan-0.0.3.tar.gz (21.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ttyscan-0.0.3-py3-none-any.whl (15.7 kB view details)

Uploaded Python 3

File details

Details for the file ttyscan-0.0.3.tar.gz.

File metadata

  • Download URL: ttyscan-0.0.3.tar.gz
  • Upload date:
  • Size: 21.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for ttyscan-0.0.3.tar.gz
Algorithm Hash digest
SHA256 465c093113cd090c4411acca84ff154b953831c268f3faf86081b34f98409daa
MD5 24b6ec2d2c50252ab01c30ce47dba7ae
BLAKE2b-256 1cd90b2ed2790e6d2dc863fedac899a383b5fc27c539d00cb3f2e89f9136e0be

See more details on using hashes here.

File details

Details for the file ttyscan-0.0.3-py3-none-any.whl.

File metadata

  • Download URL: ttyscan-0.0.3-py3-none-any.whl
  • Upload date:
  • Size: 15.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for ttyscan-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 178d6162c835c7edec464ea44b509d2250bd2c26725b69332a1005b2ac228a5c
MD5 1296ab693c346ebaba355e482366fd76
BLAKE2b-256 acdd44d6a2c4a753fff44bd8a2ff2d313a2bf6871a8d4cd0f116c08dd6b8d4db

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page