TermBuf
A terminal screen held in memory, repainted with a diff.
An application draws into a buffer and asks for a paint. What reaches the terminal is the difference between what it is showing and what the buffer holds, encoded against what that particular terminal turned out to be able to do. Drawing the same frame twice sends nothing.
TermBuf::Terminal.open do |terminal|
terminal.batch do |screen|
screen.clear
screen.write 2, 1, "hello", TermBuf::Style::DEFAULT.bold
end
terminal.paint
terminal.events.receive
end
The three layers
Terminal is the one to reach for. It owns the device, runs a fibre that owns
the buffer, and delivers keystrokes and resizes on Terminal#events.
Buffer and Sink are that fibre's insides, usable on their own: a buffer of
cells, and one output of it holding what that terminal is believed to be
showing along with the Painter and Encoder that get it there. A second
sink over the same buffer is a second display, painted independently.
Nothing in this layer touches a device, which is what makes it testable
against a model terminal.
Capabilities decides what the encoder may emit. It is settled once at
startup from the environment, from asking the terminal directly, and from
TERMBUF_CAPS; see CapabilityResolver.
Drawing
Drawing is the drawing API, mixed into both Terminal and Batcher.
Coordinates are zero based from the top left. Text is placed one extended
grapheme cluster per cell, and a cluster the terminal draws double width takes
two — see Unicode.string_width. Unicode.truncate, Unicode.ellipsize,
Unicode.fit, and Unicode.window fit a string to a column width under the
same measurement.
Terminal#batch collects a frame's drawing and sends it to the owning fibre
as one channel operation, which is what a full redraw should use.
Drawing#view gives back a rectangle of a surface addressed from its own top
left and cut at its own edges, which is what a panel drawn over other content
wants. Buffer and BufferSurface need no terminal at all, and
Buffer#blit copies one buffer's cells into another, so a shard wanting to
composite its own off-screen panels has what it needs.
Cursors
A Cursor is somewhere to stream text to: a position, a Style, and the
Region it wraps and scrolls inside. Cursor#io is an IO, so anything that
writes to one can be pointed at a pane. Terminal#hardware_cursor= puts the
terminal's own cursor wherever a chosen cursor is, after every paint.
A region an application made keeps the rectangle it was given; only the
screen-wide one follows the window. Terminal#on_resize is where an
application states its layout once rather than at every Events::Resize.
Input
Terminal#events carries everything the terminal has to say. Keystrokes
arrive as Events::Key with a decoded Key; text arrives as Events::Paste
when it was pasted rather than typed; replies to queries the application
registered with Terminal#expect_response arrive as Events::Response.
See Decoder for what separates the three, and Input::Stream for the
fibres that run it. An application wanting a reply as something other than
its bytes registers with Input::Patterns itself.
All of it lives under TermBuf::Input and is defined in the termbuf-input
shard, which depends on nothing outside the standard library, so a program
that only wants to read a keyboard can use it without a screen buffer
attached. Key is Input::Key, Events::Key is Input::Events::Key, and
so on for every name on the input side: the short spellings are aliases and
are not going anywhere. The one event that stayed behind is Events::Resize,
which carries a ScreenSize and so belongs to the terminal rather than to
the keyboard.
Constants
Nested types
- TermBuf::Attributes
- TermBuf::Batcher
- TermBuf::Blend
- TermBuf::Buffer
- TermBuf::BufferSurface
- TermBuf::Capabilities
- TermBuf::Capability
- TermBuf::CapabilityOverrides
- TermBuf::CapabilityResolver
- TermBuf::Cell
- TermBuf::Clipboard
- TermBuf::ClusterPool
- TermBuf::Color
- TermBuf::ColorStack
- TermBuf::Command
- TermBuf::Commands
- TermBuf::Cursor
- TermBuf::CursorIO
- TermBuf::CursorShape
- TermBuf::Damage
- TermBuf::Decoder
- TermBuf::Drawing
- TermBuf::Encoder
- TermBuf::EnvironmentDetector
- TermBuf::Event
- TermBuf::Events
- TermBuf::Gradient
- TermBuf::Grid
- TermBuf::Image
- TermBuf::ImageStore
- TermBuf::Input
- TermBuf::Key
- TermBuf::Link
- TermBuf::LinkId
- TermBuf::LinkTable
- TermBuf::Meter
- TermBuf::Modifiers
- TermBuf::Op
- TermBuf::Ops
- TermBuf::Painter
- TermBuf::Placement
- TermBuf::Prober
- TermBuf::Quirk
- TermBuf::QuirkOverrides
- TermBuf::Rect
- TermBuf::Region
- TermBuf::ScreenSize
- TermBuf::ScrollHint
- TermBuf::SgrScanner
- TermBuf::Sink
- TermBuf::SizeDetector
- TermBuf::Style
- TermBuf::StyleId
- TermBuf::StyleTable
- TermBuf::Terminal
- TermBuf::Tty
- TermBuf::Underline
- TermBuf::Unicode
- TermBuf::View
- TermBuf::WidthProbe