Skip to content

Instantly share code, notes, and snippets.

@dgl
Last active June 24, 2025 16:17
Show Gist options
  • Save dgl/cfa357ab9f77818e28465e3c9e2435f3 to your computer and use it in GitHub Desktop.
Save dgl/cfa357ab9f77818e28465e3c9e2435f3 to your computer and use it in GitHub Desktop.
Check for DECDHL support (DEC double-height lines)
#!/usr/bin/env bash
# © David Leadbeater, 2025 <http://©.st/dgl>
# SPDX-License-Identifier: 0BSD
#
# Detect whether terminals support DECDHL (DEC double-height lines). This is
# not perfect, as terminals are a mess, to put it mildly.
#
# If you want see the output in your terminal, try: curl -i ip.wtf
#
# Usage:
# Run directly to see the variables.
#
# Or, in bash, or a script:
# . check-decdhl
# check_decdhl
# echo $DECDHL
#
# Known issues:
# - Alacritty gets detected as supporting, when it doesn't (it seems to
# understand that DECDHL has an impact on cursor position, but doesn't
# render it).
# - Apple Terminal does not implement cursor position correctly, we guess
# based on the $TERM_PROGRAM environment variable and a heuristic, but this
# may not always work.
# - xterm before patch #380 will segfault if using TrueType fonts (e.g.
# xterm -fa Mono; which you need to correctly render the emoji).
# - On Windows there are multiple layers to getting Unicode working correctly,
# if you use "curl.exe -i ip.wtf" to test you may see Mojibake. Run "chcp
# 65001" first. This only works out of the box on WezTerm on Windows as
# Windows itself does not ship flag emojis. (Windows Terminal has other
# issues, but non-flag emojis in the BMP should work.)
#
# Terminals that do support DECDHL:
# - xterm (and so anything claiming TERM=xterm should)
# - VT100 (yes, but obviously not with emojis, etc.)
# - Windows Terminal
# - Apple Terminal
# - MinTTY (no emoji support)
# - WezTerm (with some strange behaviour where it renders \e#3, ignores #4)
#
# Terminals that don't support DECDHL:
# - Ghostty (https://github.com/ghostty-org/ghostty/discussions/3243)
# - iTerm2
# - Kitty (https://github.com/kovidgoyal/kitty/issues/6816, but see
# https://github.com/kovidgoyal/kitty/blob/master/docs/text-sizing-protocol.rst)
# - Alacritty (but see above)
# - VTE based terminals (strong no: :( https://bugzilla.gnome.org/show_bug.cgi?id=587049)
#
getpos() {
local r
printf '\e[6n' > /dev/tty
read -d R r
echo "${r/*;}"
}
check_decdhl() {
local pos
if [[ -z "$COLUMNS" ]]; then
printf '\e[10000G'
# Note if you run bash interactively, it sets COLUMNS for you.
# But set it ourselves if not set so this works in scripts too.
COLUMNS=$(getpos)
printf '\e[A'
fi
# Does this terminal render emoji as double width?
printf '\e[G\e[K✅'
pos=$(getpos)
if [[ $pos = 3 ]]; then
EMOJI=1
else
EMOJI=0
fi
# Does this terminal support double height fonts?
printf '\e[G\e[2K\e#3'
eval "printf ' %.0s' {1..$[1+$COLUMNS/2]}"
pos=$(getpos)
if [[ $pos = 2 ]]; then
# Yes, xterm style reporting (line wrapped)
DECDHL=1
# Delete extra line
printf '\e[M\e[F'
elif [[ $pos = $[2+$COLUMNS/2] ]]; then
# Correct cursor position for non-supporting, but still could be Apple
# Terminal.
if [[ $TERM_PROGRAM = Apple_Terminal ]]; then
DECDHL=1
DECDHL_EMOJI=1
# Reset state so there is no output left.
printf '\e[M\e[G\e[2K'
return
else
# It could still be Apple Terminal, but without the environment variable.
printf '\e[G\e[2Kx\e[2b🤗\e[2b'
# Expect "xxx🤗🤗🤗", but Apple Terminal renders. "xxx🤗[cursor]" => 6, if REP
# isn't supported at all the result is 4.
# Windows Terminal does not get here, but if it did it may trip:
# https://github.com/microsoft/terminal/issues/15390
pos=$(getpos)
if [[ $pos = 6 ]]; then
# Apple terminal heuristic
DECDHL=1
DECDHL_EMOJI=1
# Reset state so there is no output left.
printf '\e[M\e[G\e[2K'
return
fi
DECDHL=0
fi
else
# Strange answer
DECDHL=0
fi
printf '\e[G\e[2K\e#3'
eval "printf '☑️%.0s' {1..$[1+$COLUMNS/4]}"
pos=$(getpos)
if [[ $pos = 3 ]]; then
# Yes, xterm style reporting (line wrapped)
DECDHL_EMOJI=1
# Delete extra line
printf '\e[M\e[F'
elif [[ $pos = $[3+$COLUMNS/2] ]]; then
# Correct cursor position for non-supporting, Apple was checked above.
DECDHL_EMOJI=0
else
# Strange answer
DECDHL_EMOJI=0
fi
# Reset state so there is no output left.
printf '\e[M\e[G\e[2K'
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
check_decdhl
echo "EMOJI=$EMOJI, DECDHL=$DECDHL, DECDHL_EMOJI=$DECDHL_EMOJI"
fi
@Jan69
Copy link

Jan69 commented Jun 24, 2025

qterminal (based on QT tech) KINDA supports it, but it's particularly weird for me, it doesn't like emojis?
it picks the text from the top half, but if I did printf '\e#4Hello world 👽\n\e#3X€Ptu W0ifo 😑\n' then it resulted in
scrot
(if the screen scrolls, then the emoji gets half-cut-off and the prompt it overwrite appears normally)

putting it in the "correct order" of \e#3 before \e#4 doesn't change anything, I didn't notice it being backwards at first

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment