Portál AbcLinuxu, 30. dubna 2025 15:26

Kterak zjistiti velikost terminálu - v Pythonu?

11.2.2010 20:43 | Přečteno: 878× | poslední úprava: 11.2.2010 20:44

Jednoduše, jasně. Ale co když nechci aby mi staroušek curses osahával můj mladý a nevinný terminál? V dnešní pedománii jeden nikdy neví.

Jednoduchy způsob - jen prstíček ohřejeme

Něco málo se dá z curses vytlačit i bez cirkusu spojeného s initscr()
import curses
curses.setupterm()
curses.tigetnum("lines"), curses.tigetnum("cols")

Složitějsí způsob - ani pohledem nezavadíme

Pokud opravdu nepotřebujeme barvičky, hýbaní kurzorem a podobné voloviny, dá se bez prokletí obejít úplně.
import sys, os, fcntl, termios, array
winsBuff = array.array("H", (0,0,0,0))
def getTermSize():
    """
    Find out terminal size
    """
    if os.isatty(sys.stdout.fileno()):
        fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, winsBuff, True)
        return winsBuff[0], winsBuff[1]
    return 0, 0
Na čísla se dá spolehnout dokud nedorazí signál SIGWINCH, pak je potřeba měřit znovu. Konstrukce pole winsBuff počítá s tím, že velikost libc struktury winsize je 4x short int, a nevsadil bych ruku, že to platí na všech platformách. Vlastně bych nevsadil ani suchar, možná bude lepší ten prstíček ohřát…        

Hodnocení: 100 %

        špatnédobré        

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

Komentáře

Nástroje: Začni sledovat (1) ?Zašle upozornění na váš email při vložení nového komentáře. , Tisk

Vložit další komentář

11.2.2010 21:09 kralyk z abclinuxu | skóre: 29 | blog:
Rozbalit Rozbalit vše Re: Kterak zjistiti velikost terminálu - v Pythonu?
Odpovědět | Sbalit | Link | Blokovat | Admin
Jj, řeším to přesně takhle, jen pro zajímavost uvádím svůj kód (C++)
#define SCR_WID_FALLBACK 80
int Shell::screen_width()
{
  int fd;
  struct winsize wsz;

  fd = fileno(stdout);
  if (ioctl (fd, TIOCGWINSZ, &wsz) < 0)
    return SCR_WID_FALLBACK;

  return wsz.ws_col;
}
struktura winsize je (u mně) definována takhle:
struct winsize
  {
    unsigned short int ws_row;
    unsigned short int ws_col;
    unsigned short int ws_xpixel;
    unsigned short int ws_ypixel;
  };
A protože okolo ní nejsou žádný #ifdefy apod., nemuselo by to snad s platform-dependencí být tak hrozné...
Je třeba ovšem pamatovat, že tento postup je závislý na termios(.h).
SPD vůbec není proruská
11.2.2010 21:55 e | skóre: 10
Rozbalit Rozbalit vše Re: Kterak zjistiti velikost terminálu - v Pythonu?
Odpovědět | Sbalit | Link | Blokovat | Admin
A nestačilo by z shellu brát proměnné LINES a COLUMNS? Aspoň můj zsh tydle proměnné nastaveny má
JA RAD PORADM KDYZ VIM vic (hebmilo.cz)
11.2.2010 23:10 Radovan Garabík
Rozbalit Rozbalit vše Re: Kterak zjistiti velikost terminálu - v Pythonu?
NIe, do spusteného procesu sa nepropagujú...

Namiesto array z príkladu odporúčam použiť struct.pack("HHHH", 0, 0, 0, 0), pripadá mi to čistejšie... (riešil som to kedysi v pydf).
rADOn avatar 12.2.2010 00:47 rADOn | skóre: 44 | blog: bloK | Praha
Rozbalit Rozbalit vše Re: Kterak zjistiti velikost terminálu - v Pythonu?
To jistě bylo, ale může se do takové  struktury psát ? (do syscallu se předává adresou).
"2^24 comments ought to be enough for anyone" -- CmdrTaco
12.2.2010 10:33 Radovan Garabík
Rozbalit Rozbalit vše Re: Kterak zjistiti velikost terminálu - v Pythonu?
Samozrejme nie, treba použiť unpack...

Pre referenciu, celé moje riešenie vyzerá takto:

def get_terminal_width_termios():
    try:
        import fcntl, termios
    except ImportError:
        return None
    s = struct.pack("HHHH", 0, 0, 0, 0)
    try:
        lines, cols, xpixels, ypixels = \
            struct.unpack(
                "HHHH",
                fcntl.ioctl(sys.stdout.fileno(),
                termios.TIOCGWINSZ, s)
                )
    except (IOError, AttributeError):
        return None
    return cols


def get_terminal_width_resize():
    c = commands.getoutput('resize').split('\n')
    c = [x for x in c if x.startswith('COLUMNS=')]
    if c:
        c = c[0]
        dummy, c = c.split('=', 1)
        if c[-1] == ';':
            c = c[:-1]
    if c:
        return int(c)
    else:
        return None

def get_terminal_width_dumb():
    return 80

def get_terminal_width():
    handlers = [get_terminal_width_termios, get_terminal_width_resize, get_terminal_width_dumb]
    for handler in handlers:
        width = handler()
        if width is not None:
            return width

    return 80 # fallback, should not happen

rADOn avatar 12.2.2010 15:09 rADOn | skóre: 44 | blog: bloK | Praha
Rozbalit Rozbalit vše Re: Kterak zjistiti velikost terminálu - v Pythonu?
Mel jsem na mysli jestli jde predat pointer ceckovemu syscallu bez rizika, ze kernel prostreli nejake interni struktury a posle interpret do SIGSEGV. Coz, zda se, jde.
"2^24 comments ought to be enough for anyone" -- CmdrTaco
15.2.2010 12:24 Radovan Garabík
Rozbalit Rozbalit vše Re: Kterak zjistiti velikost terminálu - v Pythonu?
Samozrejme že to ide, python to nemá ako skontrolovať...

Založit nové vláknoNahoru

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.