2

QEMU was leaving my terminal in a weird state and it took me a while to finally debug it to the precise capability in question: tput smam vs tput rmam.

Is there a way to inspect the current terminal state, hopefully showing the current value of all capabilities at once?

This would allow me to easily diff out a working vs a "broken" terminal to find out what was modified.

Finding out the current state of any specific capability would also be a good start though, e.g. smam vs rmam.

Tested in Ubuntu 19.10, Gnome terminal.

2 Answers 2

3

This might work (VTE implements part of this control):

CSI ? Ps $ p

Request DEC private mode (DECRQM). For VT300 and up, reply DECRPM is

CSI ? Ps ; Pm $ y

where Ps is the mode number as in DECSET/DECSET, Pm is the mode value as in the ANSI DECRQM.

specifically, Ps is 7:

       Ps = 7  ⇒  Auto-wrap Mode (DECAWM), VT100.

which corresponds to the settings used in the terminal description:

rmam=\E[?7l, smam=\E[?7h,

so... you'd do

printf '\033[?7$p'

and expect to get back

\033[?7;1$y

or

\033[?7;2$y

depending on whether the mode was set or reset, respectively.

This also assumes your script/program is reading from the terminal (not necessarily standard input). There are several test/demo scripts in xterm's sources which you might find useful reading (though most will not work with VTE). Generally I'd test this feature with vttest, which has been packaged for whatever system you're using.

5
  • Thanks for this suggestion Thomas, but I'm afraid it didn't seem to work on my system: printf '\033[?7$p' | hd produces 1b 5b 3f 37 24 70 |.[?7$p| both after tput smam and tput rmam. Dec 24, 2019 at 14:16
  • Perhaps you're not reading from the terminal - I added a clarification. But piping through hd doesn't sound as if you're writing to the terminal. Dec 24, 2019 at 14:19
  • Given the | hd the easier conclusion is that xe is not writing to the terminal. (-:
    – JdeBP
    Dec 24, 2019 at 14:33
  • 1
    @Ciro if you want hd, do it like this: (g=$(stty -g); stty -icanon -echo min 0 time 5; printf '\033[?7$p'; dd count=1 2>/dev/null | hexdump -C; stty "$g"). That escape doesn't work in screen or tmux.
    – mosvy
    Dec 25, 2019 at 2:37
  • @mosvy ah, actually yes, it works without | hd. I thought I had tried that yesterday, oh well. But good to know how to obtain it programatically as you showed, since the end goal would be to generate a human readable list of all properties in one go. Dec 25, 2019 at 8:04
1

To complement Thomas Dickey's helpful answer, which provides all crucial information with POSIX-compliant convenience function tmode, adapted from the helpful command in mosvy's comment:

Given a terminal mode number, it prints 'SET' or 'RESET' to reflect the mode's status; e.g.:

# Get status of the DECAWM (autowrap) mode
$ tmode 7
RESET

CAVEATS:

If anyone can shed more light on these, please comment.

  • The function works only in certain terminal emulators, notably not in Gnome Terminal:

    • macOS: iTerm2.app, but not the built-in Terminal.app
    • Ubuntu: XTerm and UXTerm, but not the standard Gnome Terminal
    • Windows (WSL): not supported; neither in a legacy console window nor in Windows Terminal.
  • Re supported mode numbers :

    • The console_codes(4) Linux man page in section "DEC Private Mode (DECSET/DECRST) sequences" mentions only 1, 3, 5..9, 25 and 1000

    • In practice, the terminal emulates mentioned above return meaningful values for the following:

      • iTerm2.app on macOS: 1..3, 5..8, 25, 40..41, 45, 47, 69, 1000
      • [U]XTerm on Ubuntu: 1..7, 9, 12, 18..19, 25, 30, 35, 38, 40..42, 44..45, 47, 66..67, 69, 80, 95, 1000
    • There are other, non-numeric modes mentioned in the linked man page, such as = (DECPAM) and > (DECPNM) - I don't know how to query those.

    • While Thomas Dickey's link to the explanation of the DEC private-mode escape sequences mentions return value 0 as indicating an unknown mode and 3 / 4 as "permanently set/reset"; in practice it seems to be 4 that indicates a unknown mode, with known modes only ever reporting 1 ("set", i.e. on) or 2 ("reset", i.e. off).

Shell function tmode:

#!/bin/sh

function tmode {

  [ $# -eq 1 ] || { echo "Usage: tmode <mode-number>" >&2; return 2; }
  local modeNum="$1"

  # Make a copy of stdout and temporarily redirect it to the terminal.
  # This is necessary so that invocation such as `result=$(tmode 1)` work.
  exec 3<&1 1>/dev/tty
  
  # Query the terminal.
  stty -icanon -echo 2>/dev/null
  printf '\e[?%s$p' $modeNum; result=$(dd count=1 2>/dev/null)
  stty icanon echo 2>/dev/null
  
  # Restore stdout and close the copy.
  exec 1>&3 3>&-

  # Activate this to visiualize the raw result.
  # printf %s "$result" | od -c > /dev/tty

  # Print a friendly result.
  case $result in
    *';1$'*)
     echo SET;;
    *';2$'*)
     echo RESET;; 
    # NOTE: It seems that 4 is only ever used to signal a nonexistent mode.
    # *';3$'*)
    #  echo PERMANENTLY SET;; 
    # *';4$'*)
    #  echo PERMANENTLY RESET;; 
    *)
      echo "Unknown mode: $modeNum" >&2;;
  esac

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.