Skąd mniej zna rozdzielczość terminala?

13

Za każdym razem, gdy ktoś ustawia inny rozmiar wirtualnej konsoli, lessrozpoznaje rozdzielczość okna (zakładam, że ...); zgodnie z tym zmienia liczbę wierszy tekstu, które powinien wizualizować. Jak obliczany jest ten parametr?

Giuseppe Crinò
źródło
Uhm ... ok, ale gdzie mogę znaleźć tę wykonaną procedurę?
Giuseppe Crinò

Odpowiedzi:

22

Jeśli szukasz sposobu na sprawdzenie ze skryptu, możesz wykonać jedną z następujących czynności:

  • Uruchom tput colsi tput lines, jak sugeruje manatwork
  • sprawdź wartości $ LINES i $ COLUMNS

Ale jeśli chcesz poznać szczegóły, zaczynamy:

W przypadku wirtualnych terminali (xterm, i in.) Istnieje ioctl()wywołanie systemowe, które powie ci, jaki jest rozmiar okna. Jeśli to możliwe, lesswykorzystuje to połączenie. Ponadto, po zmianie rozmiaru okna, cokolwiek działa w tym oknie, odbiera SIGWINCHsygnał, który lessinformuje, że powinien sprawdzić nowy rozmiar okna. Na przykład rozpocząłem lessuruchamianie (jako identyfikator procesu 16663), połączyłem się z nim stracei zmieniłem rozmiar okna. Oto co zobaczyłem:

$ strace -p 16663
Process 16663 attached - interrupt to quit
read(3, 0xbfb1f10f, 1)                  = ? ERESTARTSYS (To be restarted)
--- SIGWINCH (Window changed) @ 0 (0) ---
rt_sigaction(SIGWINCH, {0x805cf10, [WINCH], SA_RESTART}, {0x805cf10, [WINCH], SA_RESTART}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=40, ws_col=80, ws_xpixel=0, ws_ypixel=0}) = 0
ioctl(2, TIOCGWINSZ, {ws_row=40, ws_col=80, ws_xpixel=0, ws_ypixel=0}) = 0

Jest to również co tput colsi tput lineszrobić za kulisami, jeśli to możliwe. Aby uzyskać więcej informacji na temat tej metody, zobacz man tty-ioctli wyszukaj TIOCGWINSZ.

Jednak w przypadku innych terminali, takich jak te podłączone do portów szeregowych, nie ma możliwości bezpośredniego uzyskania tych informacji. W takim przypadku lesszaczyna szukać wskazówek w zmiennych środowiskowych.

  • LINESi COLUMNSczęsto będą ustawione na wymiary terminala. W rzeczywistości, jeśli bashlub zshmoże znaleźć wymiary terminala, automatycznie ustawi te zmienne, aby ułatwić niezbyt sprytnym programom sprawdzenie rozmiaru terminala. Jednak większość innych powłok, w tym dashi tcsh, nie ustawia tych zmiennych.
  • TERMjest zwykle ustawiony na typ terminala, w którym to przypadku baza danych terminfo może zawierać oczekiwany rozmiar terminala. Jeśli tput rowsnie możesz użyć IOCTL (na przykład, jeśli jesteś podłączony przez port szeregowy), wróci do wartości tutaj zarejestrowanych. W przypadku terminala, którego rozmiar może się zmienić, jest to tylko przypuszczenie i prawdopodobnie będzie błędne.

Aby uzyskać więcej informacji, zobacz man tputkomendę sterującą terminalem oraz man terminfolistę rzeczy, które możesz powiedzieć terminalowi, aby zrobił.

Jander
źródło
Baza danych terminfo nie robi tego, co tutaj wskazano. Odpowiedź @ warl0ck, która zawiera mniej informacji, jest dokładniejsza.
Thomas Dickey,
@ThomasDickey Masz rację; wszystko, co ma, to oczekiwane wartości. Poprawiłem moją odpowiedź; dzięki.
Jander
7

Jeśli spojrzysz na kod źródłowy, poznasz lesswywołania w ioctl()celu pobrania rozmiaru okna w systemie Linux.

#ifdef TIOCGWINSZ
    {
        struct winsize w;
        if (ioctl(2, TIOCGWINSZ, &w) == 0)
        {
            if (w.ws_row > 0)
                sys_height = w.ws_row;
            if (w.ws_col > 0)
                sys_width = w.ws_col;
        }
    }
#else
#ifdef WIOCGETD
    {
        struct uwdata w;
        if (ioctl(2, WIOCGETD, &w) == 0)
        {
            if (w.uw_height > 0)
                sys_height = w.uw_height / w.uw_vs;
            if (w.uw_width > 0)
                sys_width = w.uw_width / w.uw_hs;
        }
    }
#endif
stokrotka
źródło