pub struct Program<I, O>{ /* private fields */ }Expand description
An interactive terminal session composing a Terminal, an
EventSource, and a Screen to render with. See
the module documentation for the lifecycle.
Program is Send and Sync whenever its input and output handles
are, so it can be moved onto another thread or held across an .await
point in a multi-threaded async runtime.
Implementations§
Source§impl<I: Input, O: Write> Program<I, O>
impl<I: Input, O: Write> Program<I, O>
Sourcepub fn set_cursor_style(
&mut self,
shape: CursorShape,
blinking: bool,
) -> Result<()>
pub fn set_cursor_style( &mut self, shape: CursorShape, blinking: bool, ) -> Result<()>
Sourcepub fn set_pointer_shape(&mut self, shape: &str) -> Result<()>
pub fn set_pointer_shape(&mut self, shape: &str) -> Result<()>
Set the pointer (mouse cursor) shape (OSC 22) and flush.
shape is a pointer shape name such as "default", "text", or
"pointer". The shape is recorded for save/restore.
Sourcepub fn reset_pointer_shape(&mut self) -> Result<()>
pub fn reset_pointer_shape(&mut self) -> Result<()>
Reset the pointer (mouse cursor) shape to the terminal default
(OSC 22 ; default) and flush.
Uses the explicit "default" shape name rather than an empty one: some
terminals don’t treat an empty OSC 22 as a reset.
Sourcepub fn set_progress_state(&mut self, progress: ProgressState) -> Result<()>
pub fn set_progress_state(&mut self, progress: ProgressState) -> Result<()>
Report progress to the terminal (OSC 9;4) and flush.
Terminals that support it show the progress in the taskbar, tab, or
window chrome; the rest ignore the sequence. Percentages are clamped
to 0..=100.
The state is recorded for save/restore: it is removed on a shell
handoff (pause, suspend,
finish) and re-reported by
resume. Take it down with
reset_progress_state.
Sourcepub fn reset_progress_state(&mut self) -> Result<()>
pub fn reset_progress_state(&mut self) -> Result<()>
Remove the progress report (OSC 9;4;0) and flush.
Sourcepub fn enable_mouse(&mut self, tracking: MouseTracking) -> Result<()>
pub fn enable_mouse(&mut self, tracking: MouseTracking) -> Result<()>
Enable mouse tracking and flush.
This emits exactly what is asked for and does not consult terminal
capabilities. Unsupported modes are ignored by
the terminal, and because the mode requests are mutually exclusive, each
terminal settles on the most capable variant it understands:
- Tracking: button (
1000) and button-event (1002) are always requested, so a terminal reports drag where it can and plain clicks otherwise. WithMouseTracking::MOTION, any-event tracking (1003) is added on top, so motion without a button held is reported where supported. - Encoding: SGR (
1006) is always requested, since the legacy byte encoding caps coordinates at 223 and SGR is universally supported. WithMouseTracking::PIXELS, SGR-pixel (1016) is added; terminals that support it report pixel coordinates, and the rest fall back to SGR cell coordinates.
Pass MouseTracking::empty() for basic button tracking with no
extras. To turn mouse tracking off, call disable_mouse.
To learn which variant a terminal actually chose, read
capabilities (for example
supports(Mode::MOUSE_SGR_PIXEL) to
tell whether pixels or cells will arrive). When pixel reporting is active, a
Mouse event’s pixel coordinates can be converted
to cells with mouse_pixels_to_cells.
Mouse coordinates are physical screen coordinates. Inline, follow this
with request_origin to learn where the managed
area sits, so mouse_to_origin can map them
into it.
The request is recorded for save/restore.
Sourcepub fn disable_mouse(&mut self) -> Result<()>
pub fn disable_mouse(&mut self) -> Result<()>
Disable all mouse tracking modes and encodings, and flush.
Sourcepub fn enable_bracketed_paste(&mut self) -> Result<()>
pub fn enable_bracketed_paste(&mut self) -> Result<()>
Enable bracketed paste mode (DEC private mode 2004) and flush.
Sourcepub fn disable_bracketed_paste(&mut self) -> Result<()>
pub fn disable_bracketed_paste(&mut self) -> Result<()>
Disable bracketed paste mode (DEC private mode 2004) and flush.
Sourcepub fn enable_focus_events(&mut self) -> Result<()>
pub fn enable_focus_events(&mut self) -> Result<()>
Enable focus in/out reporting (DEC private mode 1004) and flush.
Sourcepub fn disable_focus_events(&mut self) -> Result<()>
pub fn disable_focus_events(&mut self) -> Result<()>
Disable focus in/out reporting (DEC private mode 1004) and flush.
Sourcepub fn enable_color_scheme_updates(&mut self) -> Result<()>
pub fn enable_color_scheme_updates(&mut self) -> Result<()>
Enable color-scheme update notifications (DEC private mode 2031) and
flush. The terminal then sends a CSI ? 997 ; {1|2} n report
whenever the user or operating system switches between dark and
light schemes; these surface as Event::ColorScheme. The report
indicates only the dark/light preference, not the actual colors.
Sourcepub fn disable_color_scheme_updates(&mut self) -> Result<()>
pub fn disable_color_scheme_updates(&mut self) -> Result<()>
Disable color-scheme update notifications (DEC private mode 2031) and flush.
Sourcepub fn enable_visibility_reports(&mut self) -> Result<()>
pub fn enable_visibility_reports(&mut self) -> Result<()>
Enable terminal visibility reports (DEC private mode 2033) and flush.
The terminal then sends a CSI ? 999 ; {1|2} n report whenever the
view stops being observable or becomes observable again, which the
decoder surfaces as Event::Visibility. Being covered by another
window, scrolled out of a tab, or on a minimized window all count.
The report is advisory and asymmetric: Visibility::Hidden means
the terminal knows nothing can be seen, so a render can be skipped,
while Visibility::Visible only means it may be observable. A
terminal that never reports is therefore treated as visible, which is
what makes ignoring this mode safe.
Visibility is independent of focus: an unfocused window is usually still visible.
Sourcepub fn disable_visibility_reports(&mut self) -> Result<()>
pub fn disable_visibility_reports(&mut self) -> Result<()>
Disable terminal visibility reports (DEC private mode 2033) and flush.
Sourcepub fn request_visibility(&mut self) -> Result<()>
pub fn request_visibility(&mut self) -> Result<()>
Ask the terminal to report its visibility once and flush.
The reply arrives as Event::Visibility, the same event the
unsolicited reports use. This does not enable or disable
enable_visibility_reports, so it
is the way to read visibility without subscribing to changes. A
terminal that does not implement DEC private mode 2033 answers
nothing at all, so never block waiting for this reply.
Sourcepub fn enable_in_band_resize(&mut self) -> Result<()>
pub fn enable_in_band_resize(&mut self) -> Result<()>
Enable in-band resize notifications (DEC private mode 2048) and
flush. The terminal then reports every surface size change in-band
as a CSI 48 ; height ; width ; ypixel ; xpixel t sequence, which
the decoder surfaces as Event::Resize — no SIGWINCH handler
required. The event source stops synthesizing resizes from SIGWINCH
while this is on, so a size change is reported once, not twice.
Only call this after capabilities reports
supports(Mode::IN_BAND_RESIZE); a
terminal that ignores the mode would otherwise leave you with no
resize events at all.
Sourcepub fn disable_in_band_resize(&mut self) -> Result<()>
pub fn disable_in_band_resize(&mut self) -> Result<()>
Disable in-band resize notifications (DEC private mode 2048) and
flush, handing resize reporting back to the SIGWINCH path.
Sourcepub fn set_title(&mut self, title: &str) -> Result<()>
pub fn set_title(&mut self, title: &str) -> Result<()>
Set both the window title and icon name (OSC 0) and flush.
An empty title clears both overrides, restoring the terminal’s
defaults; the state is recorded as unset so teardown and resume skip
them. To set just one, use
set_window_title (OSC 2) or
set_icon_title (OSC 1).
Sourcepub fn set_window_title(&mut self, title: &str) -> Result<()>
pub fn set_window_title(&mut self, title: &str) -> Result<()>
Set the window title only (OSC 2) and flush.
An empty title clears the override, restoring the terminal’s default
window title. Unlike set_title (OSC 0), this
leaves the icon name untouched.
Sourcepub fn set_icon_title(&mut self, title: &str) -> Result<()>
pub fn set_icon_title(&mut self, title: &str) -> Result<()>
Set the icon name only (OSC 1) and flush.
An empty title clears the override, restoring the terminal’s default
icon name. Unlike set_title (OSC 0), this leaves
the window title untouched.
Sourcepub fn enter_alt_screen(&mut self) -> Result<()>
pub fn enter_alt_screen(&mut self) -> Result<()>
Enter the alternate screen buffer (DECSET 1049) and flush.
The managed area becomes the whole viewport: the screen switches to
absolute addressing and repaints in full on the next
render. The normal buffer, its scrollback, and the
shell prompt are left untouched underneath and come back on
exit_alt_screen.
Cursor visibility and the Kitty keyboard stack are per-screen-buffer on some terminals, so both are re-asserted on the newly active buffer.
Sourcepub fn exit_alt_screen(&mut self) -> Result<()>
pub fn exit_alt_screen(&mut self) -> Result<()>
Leave the alternate screen buffer (DECRST 1049) and flush, restoring the normal buffer and its scrollback. The managed area becomes an inline band again, addressed with relative moves.
Sourcepub fn show_cursor(&mut self) -> Result<()>
pub fn show_cursor(&mut self) -> Result<()>
Show the terminal cursor (DECSET 25) and flush.
Also tells the screen, which hides a visible cursor around each frame’s cell diff so it does not dance across cells as the renderer repositions it.
Sourcepub fn hide_cursor(&mut self) -> Result<()>
pub fn hide_cursor(&mut self) -> Result<()>
Hide the terminal cursor (DECRST 25) and flush.
Sourcepub fn enable_grapheme_clusters(&mut self) -> Result<()>
pub fn enable_grapheme_clusters(&mut self) -> Result<()>
Enable Unicode core / grapheme-cluster mode (DECSET 2027) and flush, switching the screen to measure text per extended grapheme cluster so it agrees with the terminal.
Only call this after capabilities reports
supports(Mode::UNICODE_CORE); a
terminal that ignores the mode still measures per code point, and the
two disagreeing misplaces every cell after the first cluster on a line.
Sourcepub fn disable_grapheme_clusters(&mut self) -> Result<()>
pub fn disable_grapheme_clusters(&mut self) -> Result<()>
Disable grapheme-cluster mode (DECRST 2027) and flush, returning the screen to per-code-point (wcwidth-style) measurement.
Sourcepub fn set_kitty_keyboard(
&mut self,
flags: Option<KittyKeyboardFlags>,
) -> Result<()>
pub fn set_kitty_keyboard( &mut self, flags: Option<KittyKeyboardFlags>, ) -> Result<()>
Set the per-screen-buffer Kitty keyboard enhancements and flush.
Some(flags) enables the selected progressive-enhancement bits;
None disables every enhancement.
The Kitty stack is per-screen-buffer, so the flags are re-applied on
the newly active buffer by enter_alt_screen
/ exit_alt_screen, as part of the switch.
Sourcepub fn set_modify_other_keys(&mut self, mode: ModifyOtherKeysMode) -> Result<()>
pub fn set_modify_other_keys(&mut self, mode: ModifyOtherKeysMode) -> Result<()>
Set the xterm modifyOtherKeys mode (CSI > 4 ; n m) and flush.
Passing ModifyOtherKeysMode::Disabled resets it (CSI > 4 m).
The mode is recorded so Program::finish
can reset it and Program::resume re-apply
it.
Sourcepub fn set_foreground_color(&mut self, color: Color) -> Result<()>
pub fn set_foreground_color(&mut self, color: Color) -> Result<()>
Set the default foreground color (OSC 10) and flush. The color is
converted to 24-bit RGB and emitted as rgb:RRRR/GGGG/BBBB, and is
recorded so Program::finish can restore
the terminal default and Program::resume
can re-apply it.
Sourcepub fn reset_foreground_color(&mut self) -> Result<()>
pub fn reset_foreground_color(&mut self) -> Result<()>
Restore the terminal’s default foreground color (OSC 110) and
flush.
Sourcepub fn set_background_color(&mut self, color: Color) -> Result<()>
pub fn set_background_color(&mut self, color: Color) -> Result<()>
Set the default background color (OSC 11) and flush. See
set_foreground_color for
state-tracking semantics.
Sourcepub fn reset_background_color(&mut self) -> Result<()>
pub fn reset_background_color(&mut self) -> Result<()>
Restore the terminal’s default background color (OSC 111) and
flush.
Sourcepub fn set_cursor_color(&mut self, color: Color) -> Result<()>
pub fn set_cursor_color(&mut self, color: Color) -> Result<()>
Set the cursor color (OSC 12) and flush. See
set_foreground_color for
state-tracking semantics.
Sourcepub fn reset_cursor_color(&mut self) -> Result<()>
pub fn reset_cursor_color(&mut self) -> Result<()>
Restore the terminal’s default cursor color (OSC 112) and flush.
Sourcepub fn set_palette_color(&mut self, index: u8, color: Color) -> Result<()>
pub fn set_palette_color(&mut self, index: u8, color: Color) -> Result<()>
Set a terminal palette color by index (OSC 4) and flush. The
override is tracked so Program::finish can
restore it and Program::resume re-apply it.
Sourcepub fn reset_palette_color(&mut self, index: u8) -> Result<()>
pub fn reset_palette_color(&mut self, index: u8) -> Result<()>
Reset a single terminal palette color to its default
(OSC 104 ; index) and flush.
Sourcepub fn reset_palette_colors(&mut self) -> Result<()>
pub fn reset_palette_colors(&mut self) -> Result<()>
Reset the entire terminal palette to its defaults (OSC 104) and
flush, clearing every tracked palette override.
Sourcepub fn request_window_pixel_size(&mut self) -> Result<()>
pub fn request_window_pixel_size(&mut self) -> Result<()>
Request the window size in pixels (XTWINOPS CSI 14 t). Reply:
Event::WindowPixelSize.
Sourcepub fn request_cell_pixel_size(&mut self) -> Result<()>
pub fn request_cell_pixel_size(&mut self) -> Result<()>
Request the character cell size in pixels (XTWINOPS CSI 16 t).
Reply: Event::CellPixelSize.
Sourcepub fn request_origin(&mut self) -> Result<()>
pub fn request_origin(&mut self) -> Result<()>
Request the physical screen coordinate of the managed area’s top-left
cell: park the cursor there and ask the terminal where it landed
(CSI 6n).
The reply arrives asynchronously as a
CursorPosition event and is
recorded (and clipped to keep the managed area on screen) by
observe_event; read the result with
origin. The event is still delivered to you.
Call this once mouse mapping starts, again whenever the terminal
resizes, and again after resume, each of which can
move the managed area. Without it the origin stays at (0, 0) and
mouse_to_origin is an identity.
A no-op in fullscreen, where the origin is always (0, 0).
Sourcepub fn request_kitty_keyboard(&mut self) -> Result<()>
pub fn request_kitty_keyboard(&mut self) -> Result<()>
Request the terminal’s active Kitty keyboard flags (CSI ? u).
The reply is recorded in capabilities.
Sourcepub fn request_modify_other_keys(&mut self) -> Result<()>
pub fn request_modify_other_keys(&mut self) -> Result<()>
Request the terminal’s modifyOtherKeys state (CSI ? 4 m). The
reply is recorded in capabilities.
Sourcepub fn request_foreground_color(&mut self) -> Result<()>
pub fn request_foreground_color(&mut self) -> Result<()>
Request the default foreground color (OSC 10 ; ? ST). Reply:
Event::ForegroundColor.
Sourcepub fn request_background_color(&mut self) -> Result<()>
pub fn request_background_color(&mut self) -> Result<()>
Request the default background color (OSC 11 ; ? ST). Reply:
Event::BackgroundColor.
Sourcepub fn request_cursor_color(&mut self) -> Result<()>
pub fn request_cursor_color(&mut self) -> Result<()>
Request the cursor color (OSC 12 ; ? ST). Reply:
Event::CursorColor.
Sourcepub fn request_palette_color(&mut self, index: u8) -> Result<()>
pub fn request_palette_color(&mut self, index: u8) -> Result<()>
Request a terminal palette color by index (OSC 4 ; index ; ? ST).
Reply: OSC 4 ; index ; rgb:... ST.
Sourcepub fn request_mode(&mut self, mode: Mode) -> Result<()>
pub fn request_mode(&mut self, mode: Mode) -> Result<()>
Request a terminal mode’s current setting (DECRQM). Reply:
Event::ModeReport.
The reply’s ModeSetting reports whether
the mode is set, reset, or permanently fixed. A permanently reset mode
is recognized but can never be enabled, so check
ModeSetting::is_available
before relying on it.
Sourcepub fn request_cursor_position(&mut self) -> Result<()>
pub fn request_cursor_position(&mut self) -> Result<()>
Request the cursor position (CSI 6 n). Reply:
Event::CursorPosition.
Sourcepub fn request_color_scheme(&mut self) -> Result<()>
pub fn request_color_scheme(&mut self) -> Result<()>
Request the current color scheme (CSI ? 996 n): whether the
terminal’s scheme is dark or light. This reports only the dark/light
preference, not the actual colors. Reply:
Event::ColorScheme.
Sourcepub fn set_system_clipboard(&mut self, data: &[u8]) -> Result<()>
pub fn set_system_clipboard(&mut self, data: &[u8]) -> Result<()>
Set the system clipboard contents (OSC 52 ; c). data is
base64-encoded for transport.
Sourcepub fn set_primary_clipboard(&mut self, data: &[u8]) -> Result<()>
pub fn set_primary_clipboard(&mut self, data: &[u8]) -> Result<()>
Set the primary selection contents (OSC 52 ; p). data is
base64-encoded for transport.
Sourcepub fn request_system_clipboard(&mut self) -> Result<()>
pub fn request_system_clipboard(&mut self) -> Result<()>
Request the system clipboard contents (OSC 52 ; c ; ?). Reply:
Event::Clipboard.
Sourcepub fn request_primary_clipboard(&mut self) -> Result<()>
pub fn request_primary_clipboard(&mut self) -> Result<()>
Request the primary selection contents (OSC 52 ; p ; ?). Reply:
Event::Clipboard.
Source§impl<I, O> Program<I, O>
impl<I, O> Program<I, O>
Sourcepub fn terminal(&self) -> &Terminal<I, O> ⓘ
pub fn terminal(&self) -> &Terminal<I, O> ⓘ
Borrow the Terminal this program drives.
Shared on purpose: the program keeps ownership, so its record of the
modes and raw-mode state it emitted stays the authority for
finish. Everything the program itself changes has a
method here. The borrow is not a seal, though. Terminal::set_state
takes &self, so a caller holding this can still change raw mode
behind the program’s back, and the restore record will not know.
Sourcepub fn env(&self) -> &dyn Env
pub fn env(&self) -> &dyn Env
The environment the Terminal reads variables from.
This is where the answers the terminal never sends live: TERM,
COLORTERM, TERM_PROGRAM, and the rest. Shorthand for
terminal().env(), and the
counterpart to capabilities, which holds only
what the terminal answered.
Sourcepub fn screen_mut(&mut self) -> &mut Screen<O> ⓘ
pub fn screen_mut(&mut self) -> &mut Screen<O> ⓘ
Borrow the Screen mutably — this is how you draw.
let screen = program.screen_mut();
screen.set_str((0, 0), "hello", Style::default());
screen.render()?;Drawing is the expected use. The screen’s render properties are also
reachable here, and setting one directly moves only how frames are
drawn — it emits no mode, so the terminal never hears about it. Prefer
the program’s own enter_alt_screen,
hide_cursor, and
enable_grapheme_clusters, which
emit the mode and move the property together. Teardown follows what
this program emitted, so a property changed behind its back is not
undone by finish and does not survive a
pause / resume round trip.
Sourcepub fn poll_event(&self, timeout: Option<Duration>) -> Result<bool>
pub fn poll_event(&self, timeout: Option<Duration>) -> Result<bool>
Drive the input source for up to timeout, returning whether any
event became available. See EventSource::poll.
Sourcepub fn try_read_event(&mut self) -> Result<Option<Event>>
pub fn try_read_event(&mut self) -> Result<Option<Event>>
Take the next queued event without doing I/O, tracking capabilities as
it passes through. See EventSource::try_read.
Sourcepub fn read_event(&mut self) -> Result<Event>
pub fn read_event(&mut self) -> Result<Event>
Block until the next event, tracking capabilities as it passes
through. See EventSource::read.
Sourcepub fn unread_event(&mut self, event: Event)
pub fn unread_event(&mut self, event: Event)
Return an event to the front of the input queue, so the next
read_event / try_read_event
yields it before anything already queued. Restore a batch in original
order by unreading in reverse.
The event was observed on its way out and is deliberately not observed
again on the way back in: a reply counts once, and observing it twice
would match it against two of the requests still in flight. These
events are therefore held by the program, not returned to the shared
EventSource — use EventSource::unread through
event_source for events the program never saw.
Sourcepub fn event_source(&self) -> Arc<Mutex<EventSource<I>>>
pub fn event_source(&self) -> Arc<Mutex<EventSource<I>>>
A shared handle to the input source behind
read_event and friends, for driving input from a
separate reader over the same decoder rather than a second one racing
the same file descriptor.
The main use is async input: build an
EventStream with
EventStream::from_shared from
this handle and poll it on your executor.
Events taken this way bypass the program, so capability tracking does
not run on them — feed each one to
observe_event yourself.
Sharing one source between a live reader and the program’s own
read_event is best-effort: an event goes to
whichever consumer drains it first, so pick one reader in steady state.
Sourcepub fn event_stream(&self) -> EventStream<I>where
I: 'static,
pub fn event_stream(&self) -> EventStream<I>where
I: 'static,
Build an async EventStream over this
program’s input, for reading events with events.next().await inside a
select! on any executor. The stream shares the program’s decoder, so
it does not race a second reader on the same file descriptor.
The stream hands back events directly, so — unlike
read_event — capability tracking does not run.
Pass each event to observe_event to keep it
alive. Read through the stream or through read_event in steady
state, not both at once: a shared source hands each event to whichever
consumer drains it first.
Sourcepub fn capabilities(&self) -> &Capabilities
pub fn capabilities(&self) -> &Capabilities
What the terminal has told us about itself so far, as the replies
themselves rather than a summary. Empty until the terminal has answered
something, whichever way the question was put:
query_capabilities, an individual
request_* method, or a report the terminal sends unprompted, such as a
color-scheme change under DEC mode 2031.
Sourcepub fn window_cells(&self) -> Option<Size>
pub fn window_cells(&self) -> Option<Size>
Last observed full terminal size in cells, or None before the first
observation. This is the whole terminal, which inline differs from the
managed area returned by Screen::size.
Sourcepub fn window_pixels(&self) -> Option<Size>
pub fn window_pixels(&self) -> Option<Size>
Last observed full terminal size in pixels, or None when the
terminal has not reported one.
Sourcepub fn cell_pixels(&self) -> Option<Size>
pub fn cell_pixels(&self) -> Option<Size>
Size of one character cell in pixels, or None when the terminal has
reported nothing to derive it from.
Prefers the terminal’s own CSI 16 t reply (see
request_cell_pixel_size) and
otherwise divides window_pixels by
window_cells, which only approximates it: the
window pixel size includes any padding the terminal draws around the
grid, so the quotient can be a pixel or two short.
The CSI 16 t value is the last one the terminal reported, and it is
kept until another reply replaces it. A font-size change resizes the
cell without any reply, so call
request_cell_pixel_size again after
a resize to refresh it.
Sourcepub fn terminal_name(&self) -> Option<&str>
pub fn terminal_name(&self) -> Option<&str>
The terminal’s self-reported name from its XTVERSION reply (e.g.
"XTerm(380)"), or None when it has not answered. Shorthand for
Capabilities::terminal_name.
Sourcepub fn mouse_pixels_to_cells(&self, mouse: Mouse) -> Option<Mouse>
pub fn mouse_pixels_to_cells(&self, mouse: Mouse) -> Option<Mouse>
Convert a mouse event carrying pixel coordinates into cell
coordinates, using cell_pixels. Returns None
when the cell size is unknown. It is not refreshed on its own: call
request_cell_pixel_size at startup,
and again after a resize or a font-size change.
Sourcepub fn origin(&self) -> Position
pub fn origin(&self) -> Position
The tracked physical screen coordinate of the managed area’s top-left
cell. Always (0, 0) in fullscreen. Inline it holds whatever the last
request_origin reply reported, and stays at
(0, 0) until you make that call.
Sourcepub fn mouse_to_origin(&self, mouse: Mouse) -> Mouse
pub fn mouse_to_origin(&self, mouse: Mouse) -> Mouse
Translate a mouse event’s screen coordinates into coordinates relative
to the managed area, by subtracting the tracked origin.
A no-op in fullscreen, where the origin is (0, 0), and inline until
request_origin has answered.
Sourcepub fn observe_event(&mut self, event: &Event) -> Result<()>
pub fn observe_event(&mut self, event: &Event) -> Result<()>
Apply an event to the program’s capability tracking. The event is inspected, never consumed.
read_event and
try_read_event call this for you — you only
need it when you take events from somewhere else, namely the async
event_stream or a shared
event_source.
Observe each event exactly once. A second call on an event a read already observed is not harmless: replies are matched against the requests still in flight, so observing one reply twice consumes two requests and the answer to the second goes unrecorded.
Capability-report replies to the queries you fire with
query_capabilities and the individual
request_* methods are recorded into
capabilities, window-size reports update
window_cells /
window_pixels, and the render-affecting
reports are applied to the Screen.
A reply is recorded only when it says what it is about: a mode report
carries its mode, an XTGETTCAP reply its capability names, a palette
reply its index. The DECRPSS setting report
(Event::SettingReport) is the one reply that does not. An
unrecognized reply names nothing at all, and a success spells the
setting out as one CSI string, with the control function and its
parameters run together.
Which setting was asked about is knowable only from the DECRQSS
request, and that request is yours, so the report reaches you
unchanged and nothing is stored.
Observing is otherwise passive, with one class of exception: a mode
report proving support for grapheme clusters or in-band resize enables
that mode when the matching
ProgramOptions prefer_* field is set, which writes to the
terminal. That adoption happens only while the application has taken no
position of its own: calling the mode’s enable_* or disable_*
method, in either direction and at any point, settles it for good, and
adoption itself counts as settling it. So each mode is adopted at most
once, and never against an explicit choice.
Observing never queries. Nothing here asks the terminal a question, so
no reply appears on the event stream that the application did not ask
for. Values the terminal only reports on request, such as the pixel
sizes and the inline origin, go stale until you call
the matching request_* method.
// Async loop: the stream bypasses the program, so observe explicitly.
use tokio_stream::StreamExt;
let mut events = program.event_stream();
while let Some(ev) = events.next().await {
let ev = ev?;
program.observe_event(&ev)?;
// ... handle ev ...
program.screen_mut().render()?;
}Source§impl<I, O> Program<I, O>
impl<I, O> Program<I, O>
Sourcepub fn query_capabilities(&mut self, extra: &[u8]) -> Result<()>
pub fn query_capabilities(&mut self, extra: &[u8]) -> Result<()>
Probe the terminal for its capabilities, then flush.
A Program never queries the terminal on its own — call this when
you want capabilities populated. It writes the
default query set (Kitty keyboard, the DECRQM modes behind
Capabilities, XTVERSION, xterm modifyOtherKeys, and — when the
environment did not already imply true color — XTGETTCAP RGB/Tc),
then extra, then a Primary DA request.
extra is written verbatim, so it can carry any additional query
escapes you want answered under the same Primary DA terminator. Pass
&[] for none.
The DECRQM, XTVERSION, and XTGETTCAP queries are skipped on Apple’s
Terminal.app, which mishandles them. Nothing is recorded in their
place: capabilities keeps reporting only what
the terminal actually said. Its known direct-color support is applied
to the renderer’s color profile alone.
§Draining the replies is yours
This method only writes. The replies arrive asynchronously as
ordinary events, and reading them is the caller’s job — nothing here
waits. Primary DA is sent last precisely so its reply terminates the
stream: read events until Event::PrimaryDeviceAttributes lands and
every earlier reply has necessarily arrived, at which point
capabilities is complete.
If you never read that far, the unread replies are still sitting in the
input buffer when you restore the terminal, and the shell will see them
as typed input. A terminal that answers nothing never sends the Primary
DA reply either, so bound the wait yourself with
poll_event.
let mut program = Program::stdio()?;
program.init()?;
program.query_capabilities(&[])?;
let deadline = Instant::now() + Duration::from_millis(300);
while let Some(timeout) = deadline.checked_duration_since(Instant::now()) {
if !program.poll_event(Some(timeout))? {
break;
}
if matches!(program.try_read_event()?, Some(Event::PrimaryDeviceAttributes(_))) {
break;
}
}
let caps = program.capabilities();Source§impl<I, O> Program<I, O>
impl<I, O> Program<I, O>
Sourcepub fn new(terminal: Terminal<I, O>) -> Result<Self>
pub fn new(terminal: Terminal<I, O>) -> Result<Self>
Construct a program over terminal without touching the terminal:
size the screen to it and create an EventSource on its input
half. The terminal is left as-is; call Self::init to enter raw
mode and begin a session.
Sourcepub fn init(&mut self) -> Result<()>
pub fn init(&mut self) -> Result<()>
Begin a session with the default ProgramOptions. See
Self::init_with.
Sourcepub fn init_with(&mut self, options: ProgramOptions) -> Result<()>
pub fn init_with(&mut self, options: ProgramOptions) -> Result<()>
Begin a session: enter raw mode and apply the always-on defaults from
options. This never probes the terminal; the prefer_* defaults
stay dormant until you call
query_capabilities and read the replies.
Call once after Self::new, before rendering.
Sourcepub fn get_window_size(&self) -> Result<Winsize>
pub fn get_window_size(&self) -> Result<Winsize>
Query the current terminal window size (output half first, input as
fallback). This is a live query; the cached
window_cells /
window_pixels accessors return the
last-observed values without I/O.
Sourcepub fn autoresize(&mut self) -> Result<()>
pub fn autoresize(&mut self) -> Result<()>
Re-query the terminal size and resize the managed area to fit: the full
terminal size when fullscreen, or the terminal width with the current
managed height preserved when inline. Refreshes the cached
window_cells, and
window_pixels when the platform reports pixel
dimensions. Nothing is asked of the terminal: this reads the size the
operating system already knows. On platforms whose size query carries
no pixel dimensions (the Windows console), refresh those with
request_window_pixel_size.
When the managed area already fits the queried size, this returns
without resizing and without repainting, so it is safe to call on every
resize report. Terminals send a report per pixel of a window drag while
the cell grid only changes at cell boundaries, so most reports ask for a
size the area already has. To re-establish the area whatever the size,
call Screen::resize instead.
Sourcepub fn finish(self) -> Result<()>
pub fn finish(self) -> Result<()>
Consume the program and hand the terminal back to the shell: tear down every staged mode, reset the managed area, flush, and restore the terminal’s prior state.
The terminal state is restored even when the teardown writes fail, so a broken pipe cannot leave the terminal in raw mode. The teardown error is still returned.
Sourcepub fn pause(&mut self) -> Result<()>
pub fn pause(&mut self) -> Result<()>
Hand the terminal back to the shell without consuming the program,
e.g. to run a child process. Re-enter with Self::resume. Like
Self::finish but keeps the program so the session can continue, and
likewise restores the terminal even when the teardown writes fail.
Sourcepub fn resume(&mut self) -> Result<()>
pub fn resume(&mut self) -> Result<()>
Re-acquire the terminal after a Self::pause or Self::suspend:
re-enter raw mode, refit the managed area to the current viewport, re-apply
the saved render state and modes, and force a full repaint.
Re-enables TABS and
BS and resets the hardware tab stops, since
whatever ran while paused may have disturbed both.