1

Programs like resize ask the terminal about its size. And ultimately they will send some (ANSI) escape sequences to stdout and expect the terminal to react on those by itself returning some bytes.

The effect of the mechanism is visible with this interactive Python snippet:

>>> print('\x1b[21;t')

Gnome-terminal will insert visibly something related to the window title on stdin.

Which script snippet will provoke the terminal to write it’s size (in characters)? If the size is returned invisible, some simple transformation should be done to see something. Shell, Python, Perl, whatever language is fine. As this will be terminal specific, any common terminal emulator is fine (e.g. xterm, gnome-terminal, terminator, ...).

Clarification: I don’t care about programs which tell me the size. I know about TIOCGWINSZ, which does not work over serial lines. I want to see code which uses escape sequences, which actually works over serial lines.

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
Robert Siemer
  • 32,405
  • 11
  • 84
  • 94
  • The `stty` program reports the number of columns and rows, you could look at the GNU source http://code.metager.de/source/xref/gnu/coreutils/src/stty.c#get_win_size. It uses `ioctl`. – cdarke Dec 02 '16 at 12:24
  • So you aren't interested in [os.get_terminal_size](https://docs.python.org/3/library/os.html#os.get_terminal_size)? – PM 2Ring Dec 02 '16 at 12:43
  • Possible duplicate of [How do I determine size of ANSI terminal?](http://stackoverflow.com/questions/35688348/how-do-i-determine-size-of-ansi-terminal) – Thomas Dickey Dec 03 '16 at 00:31

2 Answers2

5

The following program saves the current cursor position; moves the cursor to 999,999; queries the terminal for the current position; and restores the cursor position.

Assuming that your terminal is smaller than 999x999, this effectively queries the size of the terminal.

import sys
print('\033[s\033[999;999H\033[6n\033[u')
print(repr(next(sys.stdin)))

Resources:

Community
  • 1
  • 1
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • FWIW, the [actual escape string](https://sources.debian.org/src/xterm/366-1/resize.c/?hl=137#L139) used in xterm's resize is: `ESCAPE("7") ESCAPE("[r") ESCAPE("[9999;9999H") ESCAPE("[6n")` So what's the effect of `\033[u` and how is `\033[s` different to `\0337\033[r`? – maxschlepzig Jul 18 '21 at 12:10
  • Can this work without having the user press enter when `next(sys.stdin)` is called? – Hykilpikonna Oct 21 '22 at 14:47
0

I lifted this technique from the GNU source of stty(1) at http://code.metager.de/source/xref/gnu/coreutils/src/stty.c#1739. I tested it on OS X, and I could not guarantee it would work elsewhere, but its worth a try.

import fcntl
import termios
import struct

pad = "0" * 8
s = fcntl.ioctl(1, termios.TIOCGWINSZ, pad)
sz = struct.unpack('hhhh', s)
print("rows: {} columns: {}, xpixels: {}, ypixels: {}". format(*sz))

on my machine gives:

rows: 24 columns: 80, xpixels: 1200, ypixels: 600

Edit: The source code for os.get_terminal_size is in Modules/posixmodule.c with a function called get_terminal_size. One of the mechanisms is that shown above, but there are others depending on macros TERMSIZE_USE_IOCTL and TERMSIZE_USE_CONIO, the CONIO route is used for Windows.

cdarke
  • 42,728
  • 8
  • 80
  • 84
  • It correctly returns the rows & columns for me in both konsole and xterm in Linux, but it returns 0 for the dimensions in pixels in konsole. – PM 2Ring Dec 02 '16 at 12:48
  • 1
    What does this `ioctl()` do? – The terminal size (e.g. over serial lines) is not known to the kernel. – Robert Siemer Dec 02 '16 at 13:19
  • Do a `man ioctl` if you want to know what it does. The `1` is the standard output file descriptor. If you are using some sort of emulator then I would expect the emulator to inform the server end of any change in size. Does `stty -a` work? If so, then work back from the source code of that, as I did. – cdarke Dec 02 '16 at 14:59
  • Did you try `os.get_terminal_size` (or `shutil.get_terminal_size`) as @PM2Ring suggested? – cdarke Dec 02 '16 at 15:01
  • 1
    This as well as `stty -a` doesn't work for terminals connected to a serial line. This is the reason why xterm's resize obtains the terminal geometry by other means and invokes `TIOCSWINSZ` such that following `TIOCGWINSZ` queries return the correct value. – maxschlepzig Jul 18 '21 at 12:15