class TermBuf::Tty

Overview

The terminal device itself: the modes it is in, the screen it is showing, and how big it is.

Everything here is reversible, and reversing it is the point. A program that leaves a terminal in raw mode on the alternate screen has made the user's shell unusable, so #leave undoes exactly what #enter did and can be called any number of times.

It works over any pair of IOs. When those are not a terminal — a pipe, a spec — the mode changes are skipped and the escape sequences still go out, which is what makes the whole driver testable without a device.

Defined in:

termbuf/terminal/tty.cr

Constant Summary

VTIME = 5

Constructors

Instance Method Summary

Constructor Detail

def self.new(input : IO, output : IO, managed : Bool | Nil = nil) #

[View source]
def self.standard : Tty #

The process's own terminal.


[View source]

Instance Method Detail

def enter(capabilities : Capabilities = Capabilities::NONE) : Nil #

Takes the terminal over: raw mode, the alternate screen, no cursor.

capabilities decides which of the optional modes are worth asking for; asking a terminal to enable something it does not have leaves the request printed on screen.


[View source]
def entered? : Bool #

Set once #enter has run, cleared by #leave.


[View source]
def flush : Nil #

Pushes whatever is buffered out to the device.


[View source]
def input : IO #

Where keystrokes and replies come from.


[View source]
def leave(capabilities : Capabilities = Capabilities::NONE) : Nil #

Gives the terminal back exactly as it was found. Safe to call twice, and safe to call when #enter never ran, which is what makes it usable from a signal handler and from at_exit.


[View source]
def managed? : Bool #

Whether this is a terminal whose modes are worth changing.


[View source]
def output : IO #

Where escape sequences go.


[View source]
def raw! : Nil #

Puts the terminal in raw mode, keeping what it was in so #restore_modes can put it back. Crystal's own #raw! would do most of this, but it restores to a cooked terminal rather than to whatever was there before, which is not the same thing when a program was started from something other than an ordinary shell.

This has to happen before the terminal is asked anything. A cooked terminal echoes the replies onto the screen and holds them in the line discipline until a newline that never comes, so the queries appear to go unanswered and then all arrive at once the moment raw mode is set.

Idempotent: calling it again keeps the modes first found, not the raw ones, so #restore_modes still has somewhere to go back to.


[View source]
def raw? : Bool #

Set once the modes have been changed, which happens before #enter when the terminal is about to be probed.


[View source]
def restore_modes : Nil #

Puts the line discipline back the way it was found. Idempotent, and safe to call when raw mode was never entered.


[View source]
def size : ScreenSize #

How big the terminal is now. Asked afresh every time, since the answer changes whenever the window does.


[View source]
def write(text : String) : Nil #

Writes straight to the device, bypassing the buffer.


[View source]