dotfiles/files/sh/.local/bin/resize-terminal
Ben Grande 45a0acb222
feat: support truecolor
- Standardize capability usage with the terminfo database for
  portability. POSIX tput does declare only the basic options such as
  'init', 'reset' and 'clear', leaving the rest unspecified, that is not
  ideal but hard coding escape sequences is way worse.
- Set colorization options based on number of colors the terminal
  supports and not the TERM variable when possible. This is incomplete,
  terminal emulators may support or adapt more than it is advertised,
  but involves using DECRQSS queries and delays, as an example, 'resize'
  utility from XTerm uses 3 seconds as delay, this is worrisome.
- Term with only '-direct' variants without ending with 256 means it
  only supports direct-color indexing, therefore 'tmux-direct' cannot be
  used, but the non-multiplexer terminal 'xterm-direct256' can.
2025-03-27 11:42:50 +01:00

106 lines
2.8 KiB
Bash
Executable File

#!/bin/sh
## SPDX-FileCopyrightText: 2024 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
##
## SPDX-License-Identifier: GFDL-1.3-or-later
##
## Credits: https://wiki.archlinux.org/title/Working_with_the_serial_console#Resizing_a_terminal
##
## Resize terminal columns and lines to current window size.
## Useful for terminals over link (serial console, socat's pty etc).
if test -n "${TERM_RESIZE_DISABLE:-}"; then
exit 0
fi
test -t 0 || exit 0
case "${TERM-}" in
dumb) exit 0;;
*);;
esac
## If argument is provided, allow user to bypass tty check.
if test "${#}" -eq 0; then
## Shells on graphical sessions (terminal emulators) are skipped.
test "${XDG_SESSION_TYPE:-}" = "tty" || exit 0
## Serial ports and devices are desired.
term_file="$(tty)"
term_file_wanted="ttyUSB ttyS"
## Consoles are desired.
if test -r /sys/class/tty/console/active; then
active_console="$(cat -- /sys/class/tty/console/active)"
term_file_wanted="${term_file_wanted} ${active_console}"
unset active_console
fi
term_file_active=0
for tf in $(printf '%s' "${term_file_wanted}"); do
case "${term_file}" in
*"/${tf}"*) term_file_active=1;;
*) ;;
esac
done
unset tf term_file term_file_wanted
## Terminal can handle screen resizing by itself.
if test "${term_file_active}" = "0"; then
unset term_file_active
exit 0
fi
unset term_file_active
fi
get_caps(){
sc="$(tput sc || printf '%b' '\0337')"
rc="$(tput rc || printf '%b' '\0338')"
cup="$(tput cup 99999 99999 || printf '%b' '\033[99999;99999H')"
csr="$(tput csr || printf '%b' '\033[r')"
gc="$(tput u7 || printf '%b' '\033[6n')"
}
## POSIX compliant.
# shellcheck disable=SC3045
if ! (printf '%s\n' "R" | read -r -t 1 -sd R 2>/dev/null); then
## Fast but depends on XTerm.
if has resize; then
resize_cmd="$(resize)"
eval "${resize_cmd}" >/dev/null
exit 0
fi
## Slow due to heavy stty calls.
get_caps
termios="$(stty -g)"
stty raw -echo min 0 time 1
printf '%s' "${sc}${csr}${cup}${gc}${rc}" >/dev/tty
IFS='[;R' read -r _ rows cols _ </dev/tty
stty "${termios}" cols "${cols}" rows "${rows}"
unset termios
exit 0
fi
msg_unsupported="error: cannot resize screen: unsupported terminal emulator"
## Non-POSIX compliant and fast.
get_caps
stty -echo
printf '%s' "${sc}${csr}${cup}${gc}${rc}" >/dev/tty
# shellcheck disable=3045,SC2034
IFS='[;R' read -r -t 1 -s -d R _ rows cols _ </dev/tty || {
printf '%s\n' "${msg_unsupported}" >&2
stty echo
unset rows cols
exit 1
}
if test "${COLUMNS}" = "${cols}" && test "${LINES}" = "${rows}";then
stty echo
unset rows cols
exit 0
elif test "${rows}" -gt 0 && test "${cols}" -gt 0;then
stty echo cols "${cols}" rows "${rows}"
unset rows cols
exit 0
fi
printf '%s\n' "${msg_unsupported}" >&2
stty echo
unset rows cols
exit 1