Skip to main content

justerm_core/
event.rs

1//! Consumer event surface (#12): point-in-time notifications the engine
2//! accumulates while parsing, for the consumer to drain.
3//!
4//! Pull, not push — the engine queues events during `feed` and the consumer
5//! takes them with `drain_events`, mirroring the rest of the pull cadence
6//! (`damage` / `frame` / `reset_damage`). No callback is injected across the
7//! boundary, so the engine stays decoupled from the consumer's event loop
8//! (unlike alacritty's `EventListener`, whose push model would couple them).
9//!
10//! OSC 8 hyperlinks are deliberately absent — a hyperlink is per-cell state
11//! (which cells are links), not a point-in-time event, so it is modelled like
12//! graphemes in its own slice (#26), not here.
13
14use crate::serialize::{MarkerId, MarkerKind};
15
16/// A consumer-facing event emitted while parsing the VT stream.
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub enum TermEvent {
19    /// The window/icon title was set (OSC 0 or OSC 2).
20    Title(String),
21    /// The terminal bell rang (BEL, `0x07`).
22    Bell,
23    /// The working directory was reported (OSC 7), e.g. `file://host/path`.
24    Cwd(String),
25    /// The app requested 80/132-column mode (DECCOLM `?3`). justerm is
26    /// dimension-free, so this is a *request* — the consumer may honor it by
27    /// calling `resize(cols, rows)`, or ignore it. `cols` is 80 or 132 (#82).
28    ColumnMode { cols: usize },
29    /// The app queried the light/dark color scheme (DSR `CSI ? 996 n`). justerm
30    /// is theme-agnostic, so the consumer (which knows the scheme) answers by
31    /// calling `Engine::report_color_scheme` (#85).
32    ColorSchemeQuery,
33    /// The app set ANSI palette entry `index` to `spec` (OSC 4). One event per
34    /// `index ; spec` pair in the sequence. The cell still references
35    /// `Indexed(index)` — only the consumer's `palette[index]` changes, so the
36    /// engine stays theme-agnostic (#122).
37    SetPaletteColor { index: u8, spec: String },
38    /// The app set the default foreground colour (OSC 10). Raw spec, forwarded
39    /// for the consumer to apply — theme-agnostic, like [`SetBackground`](Self::SetBackground) (#122).
40    SetForeground(String),
41    /// The app set the default background colour (OSC 11). The engine is
42    /// theme-agnostic, so it forwards the raw spec string (`rgb:…`/`#…`) for the
43    /// consumer to parse and apply to its palette — it never holds hex (#122).
44    SetBackground(String),
45    /// The app reset palette entries to the theme default (OSC 104). `None` =
46    /// the whole table (no argument); `Some(index)` = one entry, one event per
47    /// index given. The consumer restores its palette (#122).
48    ResetPaletteColor(Option<u8>),
49    /// The app queried ANSI palette entry `index` (OSC 4 with `?` for that pair);
50    /// the consumer answers with `report_palette_color` (#122).
51    QueryPaletteColor { index: u8 },
52    /// The app reset the default foreground to the theme default (OSC 110, #122).
53    ResetForeground,
54    /// The app reset the default background to the theme default (OSC 111, #122).
55    ResetBackground,
56    /// The app queried the default foreground colour (OSC 10 with `?`); the
57    /// consumer answers with `report_foreground` (#122).
58    QueryForeground,
59    /// The app queried the default background colour (OSC 11 with `?`). The
60    /// theme-agnostic engine relays it; the consumer answers with
61    /// `report_background` (#122), mirroring `ColorSchemeQuery`.
62    QueryBackground,
63    /// A decoration marker's line left the buffer — evicted past the scrollback
64    /// cap, or scrolled out of an in-screen region (#118). The handle is now
65    /// dead; the consumer drops the decoration bound to it. This is the
66    /// frame-mode equivalent of xterm's `IMarker.onDispose` — disposal is a
67    /// point-in-time fact (a marker absent from a frame may merely be scrolled
68    /// off-screen), so it rides the event queue, not the frame overlay.
69    MarkerDisposed(MarkerId),
70    /// A marker was created (#490) — by `add_marker`, or by the *stream* through an
71    /// OSC 133 command mark, which the consumer never called for.
72    ///
73    /// The mirror of [`TermEvent::MarkerDisposed`], and it exists for the same reason
74    /// ADR-0020 R1 gives: an appearance is an occurrence, not state, so it rides this
75    /// queue rather than a frame field. Without it a consumer that pulled a marker
76    /// index (`Engine::marker_index`) has no way to learn of a marker born after its
77    /// pull — the population would only ever shrink.
78    ///
79    /// `line` is absolute at the moment of creation, on the **same basis** the pull
80    /// reports (`Frame::evicted_total`), so a consumer appends the entry and rebases it
81    /// exactly like a pulled one. Deliberately not an epoch bump: a bump costs a whole
82    /// re-pull, and creation is `O(1)` information.
83    MarkerCreated {
84        id: MarkerId,
85        line: u32,
86        kind: MarkerKind,
87    },
88}