Skip to main content

uncurses/screen/
state.rs

1//! Non-render terminal/input mode state owned by the [`Screen`] facade.
2//!
3//! These modes do not affect how the renderer measures, renders, or
4//! presents a frame — they configure the terminal device and the input
5//! reader. The facade tracks them so it can tear them down on a shell
6//! handoff and re-apply them afterwards.
7//!
8//! [`Screen`]: super::Screen
9
10use std::collections::BTreeMap;
11
12use crate::ansi::cursor::CursorStyle;
13use crate::ansi::kitty::KittyKeyboardFlags;
14use crate::color::Color;
15use crate::event::ModifyOtherKeysMode;
16use crate::layout::Position;
17
18use super::MouseTracking;
19
20/// Tracked non-render mode state for save/restore.
21#[derive(Debug, Clone)]
22pub(super) struct State {
23    /// Cursor style.
24    pub cursor_style: CursorStyle,
25    /// Requested mouse tracking, or `None` when mouse tracking is disabled.
26    pub mouse: Option<MouseTracking>,
27    /// Bracketed paste mode.
28    pub bracketed_paste: bool,
29    /// Focus in/out reporting (DECSET 1004).
30    pub focus_events: bool,
31    /// Color-scheme update notifications (DEC 2031). When `true`, the
32    /// terminal sends unsolicited reports as the user/OS toggles the
33    /// dark/light scheme. Reports the dark/light preference only, not the
34    /// actual colors.
35    pub color_scheme_updates: bool,
36    /// In-band resize notifications (DEC 2048). When `true`, the
37    /// terminal sends a `CSI 48 ; … t` report whenever the surface
38    /// changes size, surfaced as [`Event::Resize`].
39    ///
40    /// [`Event::Resize`]: crate::event::Event::Resize
41    pub in_band_resize: bool,
42    /// Window title set via [`OSC 2`] (or [`OSC 0`], which sets both this and
43    /// [`icon_name`](Self::icon_name)). `None` when no
44    /// [`set_window_title`](super::Screen::set_window_title) or
45    /// [`set_title`](super::Screen::set_title) override has been set.
46    ///
47    /// [`OSC 2`]: crate::ansi::title::write_window_title
48    /// [`OSC 0`]: crate::ansi::title::write_window_title_and_icon
49    pub window_title: Option<String>,
50    /// Icon name set via [`OSC 1`] (or [`OSC 0`], which sets both this and
51    /// [`window_title`](Self::window_title)). `None` when no
52    /// [`set_icon_title`](super::Screen::set_icon_title) or
53    /// [`set_title`](super::Screen::set_title) override has been set.
54    ///
55    /// [`OSC 1`]: crate::ansi::title::write_icon_name
56    /// [`OSC 0`]: crate::ansi::title::write_window_title_and_icon
57    pub icon_name: Option<String>,
58    /// Default foreground color override. `Some(c)` when the facade has
59    /// emitted `OSC 10` to install `c`; `None` when the terminal is
60    /// using its built-in default. Drives `OSC 110` on reset and
61    /// re-emission on restore.
62    pub foreground_color: Option<Color>,
63    /// Default background color override. See [`State::foreground_color`].
64    pub background_color: Option<Color>,
65    /// Cursor color override. See [`State::foreground_color`].
66    pub cursor_color: Option<Color>,
67    /// Indexed palette overrides set via `OSC 4`, keyed by palette index.
68    /// Drives `OSC 104 ; index` on reset and re-emission on restore.
69    pub palette: BTreeMap<u8, Color>,
70    /// Active xterm modifyOtherKeys mode (`CSI > 4 ; n m`). Drives
71    /// `CSI > 4 m` on reset and re-emission on restore.
72    pub modify_other_keys: ModifyOtherKeysMode,
73    /// Pointer (mouse cursor) shape override set via `OSC 22`. `None` when
74    /// using the terminal default. Drives the `OSC 22` reset on reset and
75    /// re-emission on restore.
76    pub pointer_shape: Option<String>,
77    // --- Render-coupled state (formerly tracked by the renderer buffer) -----------
78    /// Whether the alternate screen is currently active.
79    pub alt_screen: bool,
80    /// Cursor visibility.
81    pub cursor_visible: bool,
82    /// Synchronized updates: when `true`, each non-empty frame is wrapped in
83    /// synchronized-output begin/end sequences.
84    pub sync_updates: bool,
85    /// Unicode core / grapheme cluster mode (DEC 2027). When `true`, width is
86    /// calculated per grapheme cluster (UTS-29 + emoji rules); when `false`,
87    /// per code point (wcwidth-style).
88    pub grapheme_clusters: bool,
89    /// Active Kitty keyboard enhancement flag set. The kitty stack is
90    /// per-screen-buffer, so the screen re-emits this onto whichever buffer
91    /// becomes active. `NONE` means no frame is set.
92    pub kitty_keyboard: KittyKeyboardFlags,
93    /// Declarative resting position for the cursor, applied at the end of
94    /// every [`render`](super::Screen::render) via
95    /// [`set_cursor_position`](super::Screen::set_cursor_position). Sticky:
96    /// it persists across frames and is re-applied each render (a no-op when
97    /// the cursor is already there) until changed or cleared. `None` means no
98    /// declarative resting position, so the cursor is left wherever the cell
99    /// diff ended. Visibility is orthogonal — see
100    /// [`show_cursor`](super::Screen::show_cursor) /
101    /// [`hide_cursor`](super::Screen::hide_cursor).
102    pub desired_cursor: Option<Position>,
103}
104
105impl Default for State {
106    fn default() -> Self {
107        Self {
108            cursor_style: CursorStyle::Default,
109            mouse: None,
110            bracketed_paste: false,
111            focus_events: false,
112            color_scheme_updates: false,
113            in_band_resize: false,
114            window_title: None,
115            icon_name: None,
116            foreground_color: None,
117            background_color: None,
118            cursor_color: None,
119            palette: BTreeMap::new(),
120            modify_other_keys: ModifyOtherKeysMode::Disabled,
121            pointer_shape: None,
122            alt_screen: false,
123            cursor_visible: true,
124            sync_updates: false,
125            grapheme_clusters: false,
126            kitty_keyboard: KittyKeyboardFlags::empty(),
127            desired_cursor: None,
128        }
129    }
130}
131
132/// Terminal capabilities detected from the replies to the queries
133/// [`Screen::init`](super::Screen::init) fires. Every field answers a
134/// single question: does the terminal support this? The facade intercepts
135/// the reply events as they flow through
136/// [`read_event`](super::Screen::read_event) / [`try_read_event`](super::Screen::try_read_event),
137/// records support here, and applies the render-affecting ones — the app
138/// never sees the reply events. Read back with
139/// [`Screen::capabilities`](super::Screen::capabilities).
140#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
141pub struct Capabilities {
142    /// Synchronized output (DEC private mode 2026). Applied: frames are
143    /// wrapped in begin/end-synchronized-update markers.
144    pub synchronized_output: bool,
145    /// Unicode core / grapheme-cluster mode (DEC private mode 2027).
146    /// Applied: cell widths are measured per grapheme cluster.
147    pub grapheme_clusters: bool,
148    /// In-band resize notifications (DEC private mode 2048).
149    pub in_band_resize: bool,
150    /// Normal mouse button tracking (DEC private mode 1000).
151    pub mouse_normal: bool,
152    /// Button-event mouse tracking (DEC private mode 1002).
153    pub mouse_button: bool,
154    /// Any-event mouse tracking (DEC private mode 1003).
155    pub mouse_any: bool,
156    /// SGR mouse encoding (DEC private mode 1006).
157    pub mouse_sgr: bool,
158    /// SGR-pixel mouse encoding (DEC private mode 1016).
159    pub mouse_sgr_pixel: bool,
160    /// Sixel graphics (Primary DA attribute 4).
161    pub sixel: bool,
162    /// Clipboard access (Primary DA attribute 52).
163    pub clipboard: bool,
164    /// Kitty keyboard protocol (the terminal answered `CSI ? u`).
165    pub kitty_keyboard: bool,
166    /// xterm modifyOtherKeys (the terminal answered `CSI ? 4 m`).
167    pub modify_other_keys: bool,
168    /// Direct (24-bit) color, confirmed by an XTGETTCAP `RGB`/`Tc` reply.
169    /// Applied: the renderer's color profile is upgraded to
170    /// [`Profile::TrueColor`](crate::color::Profile::TrueColor).
171    pub true_color: bool,
172}