#!/bin/ksh93 integer DEFAULT_ROWS=${DEFAULT_ROWS:-24} integer DEFAULT_COLS=${DEFAULT_COLS:-80} # since the terminal does not take window decoration into account, we need to # adjust reported max height and width. So you probably need to adjust these # values wrt. window manager/theme. integer ADJUST_ROWS=${ADJUST_ROWS:-2} integer ADJUST_COLS=${ADJUST_COLS:-1} SAVEOUT="" usage() { printf ' Usage: %s [-h] [-v] [-a] [-V] [-H] [-F] Toggle the size of a resizable terminal window (e.g. xterm, gnome-terminal). Calling this script as "th" is equivalent with option "-H", calling it as "tv" is equivalent with option "-V" and calling it as "tf" is equivalent with option "-F". Options specified at the command line take precedence over the script name. NOTE: If ADJUST_* variables are not properly set or the window containing the terminal size has been already toggled via the window manager, one need to toggle the size again - otherwise the script may not work as expected! Options: -h .. Print this help and exit. -v .. Verbose output. -a .. Try to find out correct values to set for ADJUST_ROWS and ADJUST_COLS. -V .. Toggle vertical size. -H .. Toggle horizontal size. -F .. Toggle between normal and default size. Environment: ADJUST_COLS .. Number of columns to substract from the maximum reported by the terminal itself to get the usable max. column number. ADJUST_ROWS .. Number of rows to substract from the maximum reported by the terminal itself to get the usable max. row number. DEFAULT_COLS .. Number of columns to set when toggling horizontal/full size. DEFAULT_ROWS .. Number of rows to set when toggling vertical/full size. ' ${ basename $0;} } printChars() { STR="$1" for I in {0..$((${#STR}-1))}; do printf "%d = %c\n" "$I" "${STR:$I:$I}" done unset STR } readResponse() { # Read from tty. Since it will not send a NL|CR, we need explicitly specify, # when reading should stop (otherwise it will read forever - script will # not terminate). Shell reads the delimiter but doesn't append it to the # RESPONSE. Delimiter is usually the last character of the ANSI-Escape # sequence sent. Here 't'. OS=${ uname -s; } X="" if [[ $OS == "Darwin" ]]; then # this is buggy, the default Terminal doesn't even report a max size # so we need a timeout as well. However iTerm2 works. LAST="@" while [[ "$LAST" != "t" && -n "$LAST" ]]; do X+="$LAST" ; LAST="" read -N 1 -t 1 LAST done else read -d t X fi RESPONSE="$X" if [[ "$RESPONSE" == "@" || -z "$RESPONSE" ]]; then print -u2 "This terminal doesn't work correctly - exiting." exit 2 fi } # tty assigned to this terminal TTY=${ tty; } # read directly from the terminal input device instead of the shell's stdin exec < $TTY # terminal should not copy received input as well as the result to the output stty -echo getCurrentSize() { # Send CSI command 18t (CSI == '\033[', \033==0x1b==27==ESC). No trailing NL! # For more info see: http://rtfm.etla.org/xterm/ctlseq.html printf '\033[18t' readResponse # 1st two chars of RESPONSE contain the CSI + ResponseIndicator(here '9') # + ';' + height(rows) + ';' + width(columns) #printChars "$RESPONSE" ROWS=${RESPONSE#*;} COLS=${ROWS#*;} ROWS=${ROWS%;*} # as an alternative we could use: #COLS=${ tput cols; } #ROWS=${ tput lines; } [[ -n "$VERBOSE" ]] && SAVEOUT+="\nCurrent size: rows=$ROWS cols=$COLS" } getMaxSize() { # get max. size printf '\033[19t' readResponse MROWS=${RESPONSE#*;} MCOLS=${MROWS#*;} MROWS=${MROWS%;*} [[ -n "$VERB" ]] && SAVEOUT+="\nMax. reported size: rows=$MROWS cols=$MCOLS" } adjustMaxSize() { MROWS=$((MROWS-ADJUST_ROWS)) MCOLS=$((MCOLS-ADJUST_COLS)) [[ -n "$VERB" ]] && SAVEOUT+="\nMax. adjusted size: rows=$MROWS cols=$MCOLS" } BN=$0 BN=${BN##*/} VERB="" while getopts "hvaHVF" option ; do case "$option" in h) usage; exit 1;; a) BN="ta" ;; v) VERB="true" ;; V) BN="tv" ;; H) BN="th" ;; F) BN="tf" ;; esac done shift $((OPTIND-1)) getCurrentSize getMaxSize case $BN in tv) # toggle vertical size adjustMaxSize if (( $ROWS < $MROWS )); then printf '\033[8;%s;%st' $MROWS $COLS elif (( $ROWS > $DEFAULT_ROWS )); then printf '\033[8;%s;%st' $DEFAULT_ROWS $COLS fi ;; th) # toggle horizonal size adjustMaxSize if (( $COLS < $MCOLS )); then printf '\033[8;%s;%st' $ROWS $MCOLS elif (( $COLS > $DEFAULT_COLS )); then printf '\033[8;%s;%st' $ROWS $DEFAULT_COLS fi ;; tf) # toggle full size adjustMaxSize if (( $COLS < $MCOLS || $ROWS < $MROWS )); then printf '\033[8;%s;%st' $MROWS $MCOLS else printf '\033[8;%s;%st' $DEFAULT_ROWS $DEFAULT_COLS fi ;; ta) OROWS=$ROWS ; OCOLS=$COLS printf '\033[8;%s;%st' $MROWS $MCOLS resize >/dev/null getCurrentSize DIFF=$((MROWS-ROWS)) if (( $DIFF != $ADJUST_ROWS )); then SAVEOUT+="\nADJUST_ROWS=$DIFF should be set." fi DIFF=$((MCOLS-COLS)) if (( $DIFF != $ADJUST_COLS )); then SAVEOUT+="\nADJUST_COLS=$DIFF should be set." fi if (( $ROWS != $OROWS || $OCOLS != $COLS )); then printf '\033[8;%s;%st' $OROWS $OCOLS fi ;; esac # finally re-enable input echo stty echo resize >/dev/null [[ -n "$SAVEOUT" ]] && print "$SAVEOUT"