class
TermBuf::Terminal
- TermBuf::Terminal
- Reference
- Object
Overview
The terminal, as an application talks to it.
One fibre owns the buffer. Every drawing method builds a command and sends it there, so ordering is total and nothing needs locking. A command that has something to report — a paint, a shutdown — carries a reply channel and the caller waits on it; the rest are fire and forget.
Input is read on a fibre of its own, in its own execution context when the terminal is a real device, because a blocking read would otherwise stall every other fibre sharing that thread.
Whatever happens, the terminal is given back: the owning fibre restores it
on the way out, signal handlers restore it before dying, and at_exit
catches anything that got past both.
Included Modules
Defined in:
termbuf/terminal/terminal.crConstant Summary
-
COMMAND_CAPACITY =
256 -
Deep enough that a full redraw does not stall the fibre sending it, shallow enough to be backpressure rather than an unbounded queue.
-
EVENT_CAPACITY =
256 -
Events waiting for the application. Once this fills, the reader stops reading, which is the right way round: the terminal's own buffer then applies backpressure to the keyboard rather than memory growing here.
Constructors
- .new(tty : Tty, capabilities : Capabilities = Capabilities::NONE, size : ScreenSize | Nil = nil, pending_input : Bytes = Bytes.empty, warnings : Array(String) = [] of String, width_spec : String | Nil = nil, probe_widths : Bool = false)
-
.open(input : IO = STDIN, output : IO = STDOUT, env : Hash(String, String) = ENV.to_h, probe : Bool = true) : Terminal
Detects what the terminal can do, takes it over, and starts running.
Class Method Summary
-
.open(input : IO = STDIN, output : IO = STDOUT, env : Hash(String, String) = ENV.to_h, probe : Bool = true, & : Terminal -> ) : Nil
Opens a terminal, yields it, and closes it however the block ends.
Instance Method Summary
-
#batch(& : Batcher -> ) : Nil
Builds a frame's worth of drawing and sends it as one channel operation.
-
#capabilities : Capabilities
What the terminal was found to be able to do.
-
#close : Nil
Restores the terminal and stops.
-
#closed? : Bool
Whether the terminal has been given back.
-
#cursor(region : Region) : Cursor
A cursor over region, which scrolls and wraps within it.
-
#cursor(rect : Rect, scrollback : Int32 = 0) : Cursor
A cursor over rect, keeping scrollback rows of what scrolls off it.
-
#cursor : Cursor
The cursor streamed output goes to, covering the whole screen.
-
#decoder : Decoder
Turns the bytes the terminal sends into events.
- #escape_timeout : Time::Span
- #escape_timeout=(span : Time::Span) : Time::Span
-
#events : Channel(Event)
Everything the terminal has to say, in the order it happened.
-
#expect_response(prefix : String, terminator : String) : ResponsePattern
Says that a reply beginning with prefix and ending with terminator is expected, so it arrives as an
Events::Responserather than as input. -
#forget_response(pattern : ResponsePattern) : Nil
Stops expecting pattern, so sequences matching it are input again.
-
#hardware_cursor : Cursor | Nil
Which cursor the terminal's own cursor follows, or
nilwhile it is hidden. -
#hardware_cursor=(cursor : Cursor | Nil) : Cursor | Nil
Which cursor the terminal's own cursor follows, or
nilwhile it is hidden. -
#hide_cursor : Nil
Hides the terminal's own cursor.
-
#issue(command : Command) : Nil
Sends command on, or collects it.
-
#last_paint_bytes : Int32
How many bytes the last paint sent.
-
#paint : Nil
Draws, and waits for the bytes to reach the terminal.
-
#paint! : Nil
Rewrites every cell, whatever the buffer thinks the terminal is showing.
-
#paint_async : Nil
Draws without waiting, which is what the frame scheduler uses.
- #paste_notice : Time::Span
- #paste_notice=(span : Time::Span) : Time::Span
- #paste_progress : Time::Span
- #paste_progress=(span : Time::Span) : Time::Span
-
#paste_stall : Time::Span
See
Decoder::PASTE_STALL. -
#paste_stall=(span : Time::Span) : Time::Span
See
Decoder::PASTE_STALL. -
#responses : ResponseRegistry
The replies the application is waiting for.
-
#restore : Nil
Gives the terminal back without going through the owning fibre.
-
#scheduling? : Bool
Whether the frame scheduler is running.
-
#size : ScreenSize
How big the terminal was when it was last looked at.
-
#start : Nil
Takes the terminal over and starts the fibres that run it.
-
#start_frame_scheduler(fps : Int32 = 60) : Nil
Starts painting automatically at up to fps frames a second, coalescing whatever was drawn in between.
-
#started? : Bool
Whether the owning fibre is running.
-
#stop_frame_scheduler : Nil
Stops the scheduler.
-
#sync(&action : Buffer -> Nil) : Nil
Runs action against the buffer on the owning fibre, and waits.
-
#total_paint_bytes : Int64
How many bytes every paint has sent between them.
-
#tty : Tty
The device underneath, for anything the driver does not wrap.
-
#width_readings : Array(TermBuf::WidthProbe::Reading)
What the width probe asked and what came back, for diagnostics.
-
#widths : Unicode::WidthPolicy
How this terminal measures a grapheme cluster, which is what the buffer writes with.
Instance methods inherited from module TermBuf::Drawing
clear(style : Style = Style::DEFAULT) : Nil
clear,
fill(rect : Rect, char : Char = ' ', style : Style = Style::DEFAULT) : Nil
fill,
issue(command : Command) : Nil
issue,
passthrough(bytes : Bytes) : Nilpassthrough(text : String) : Nil passthrough, scroll(rect : Rect, lines : Int32, style : Style = Style::DEFAULT) : Nil scroll, scroll_region(region : Region, lines : Int32, style : Style = Style::DEFAULT) : Nil scroll_region, write(x : Int32, y : Int32, text : String, style : Style = Style::DEFAULT) : Nil write, write_char(x : Int32, y : Int32, char : Char, style : Style = Style::DEFAULT) : Nil write_char
Constructor Detail
Detects what the terminal can do, takes it over, and starts running.
The block form is the one to reach for: it gives the terminal back even when the body raises, which no amount of care in the body can guarantee on its own.
Class Method Detail
Opens a terminal, yields it, and closes it however the block ends.
Instance Method Detail
Builds a frame's worth of drawing and sends it as one channel operation.
What the terminal was found to be able to do. The encoder emits nothing that is not in here.
Restores the terminal and stops. Safe to call more than once, and safe to call from an exception handler.
A cursor over region, which scrolls and wraps within it.
A cursor over rect, keeping scrollback rows of what scrolls off it.
The cursor streamed output goes to, covering the whole screen.
cursor.io is an IO, so puts, print, printf, and anything else
that writes to one can be pointed at the screen.
Made on first use rather than in the constructor, which would hand a half-built terminal to something that keeps hold of it.
Turns the bytes the terminal sends into events. Held here rather than made on the reader fibre so that its deadlines can be adjusted before anything starts reading.
See Decoder::ESCAPE_TIMEOUT. Worth raising over a slow link, where a
sequence can take longer than that to arrive in full.
See Decoder::ESCAPE_TIMEOUT. Worth raising over a slow link, where a
sequence can take longer than that to arrive in full.
Everything the terminal has to say, in the order it happened.
Says that a reply beginning with prefix and ending with terminator is
expected, so it arrives as an Events::Response rather than as input.
Stops expecting pattern, so sequences matching it are input again.
Which cursor the terminal's own cursor follows, or nil while it is
hidden.
Hidden is the default, which is what a full screen application wants: a cursor blinking wherever the last run of text ended is a distraction. An application with somewhere for someone to type points this at the cursor they are typing into, and every paint puts the terminal's cursor back there afterwards.
Which cursor the terminal's own cursor follows, or nil while it is
hidden.
Hidden is the default, which is what a full screen application wants: a cursor blinking wherever the last run of text ended is a distraction. An application with somewhere for someone to type points this at the cursor they are typing into, and every paint puts the terminal's cursor back there afterwards.
Sends command on, or collects it. What a Terminal and a Batcher
disagree about, and all they disagree about.
How many bytes the last paint sent. The point of the buffer is that a frame costs a diff rather than a screenful, and this is how an application checks that it is getting one.
Rewrites every cell, whatever the buffer thinks the terminal is showing. For after a resize, a suspend, or anything else that leaves the screen in a state the buffer cannot know about.
See Decoder::PASTE_STALL. Worth raising for an application expecting
very large pastes over a very slow link.
See Decoder::PASTE_STALL. Worth raising for an application expecting
very large pastes over a very slow link.
The replies the application is waiting for. Anything arriving from the
terminal that matches one becomes an Events::Response; everything else
goes to the decoder, because an escape sequence nobody asked for is a key
someone pressed.
Gives the terminal back without going through the owning fibre. What the
signal handlers and at_exit call, since by then there may be no fibre
left to ask.
How big the terminal was when it was last looked at. Updated by the owning fibre on a resize, so this is a snapshot rather than a promise.
Starts painting automatically at up to fps frames a second, coalescing whatever was drawn in between. A paint with nothing to do costs nothing, so this is safe to leave running.
Off by default: an application that draws in response to input knows better than a timer when a frame is worth sending.
Runs action against the buffer on the owning fibre, and waits.
The escape hatch for anything the drawing API does not cover, and the only safe way to read the buffer: doing it from another fibre would race with whoever is drawing.
What the width probe asked and what came back, for diagnostics. Empty when it did not run.
How this terminal measures a grapheme cluster, which is what the buffer
writes with. Measured at startup unless TERMBUF_WIDTHS=off or the
terminal declined to answer.