Skip to main content

smelt_term/
lib.rs

1//! Pure terminal renderer: double-buffered diff/flush, `LayoutTree`, `Grid`,
2//! `paint_chrome`, and half-block-friendly cell primitives.
3//! Editor concepts (`Window`, `Buffer`, overlays) live in `smelt-edit`.
4//!
5//! Key entry points:
6//! - [`Compositor::render_with`] - drive a frame.
7//! - [`paint_layout_tree`] - walk a [`LayoutTree`] and dispatch leaves.
8//! - [`flush_diff`] - emit SGR escapes for a `Grid` diff.
9//! - [`Grid`] / [`GridSlice`] - `set` / `put_str` (full overwrite; string
10//!   writes return the clipped end column), `put_char` / `put_str_fg` /
11//!   `put_line` (preserve bg where applicable).
12//! - [`TerminalSession`] - raw-mode/alternate-screen lifecycle guard with
13//!   suspend support for shell-outs.
14
15pub mod ansi;
16pub mod compositor;
17pub mod flush;
18pub mod geometry;
19pub mod grid;
20pub mod hit;
21pub mod layout;
22pub mod line;
23pub mod session;
24pub mod snapshot;
25pub mod surface;
26
27pub use compositor::Compositor;
28pub use flush::flush_diff;
29pub use geometry::Insets;
30pub use grid::{
31    display_width, truncate_width, Cell, CellUpdate, Grid, GridSlice, Style, TextAlign,
32};
33pub use hit::HitRegistry;
34pub use layout::{
35    resolve_layout, resolve_layout_ordered, resolve_layout_ordered_with, resolve_layout_with,
36    Align, Border, Constraint, Corner, Gutters, LayoutRect, LayoutTree, LeafSizer, Natural,
37    NaturalRef, NoopSizer, PaintId, Rect, StaticNatural,
38};
39pub use line::{Line, Span};
40pub use session::{SuspendScreen, TerminalSession, TerminalSessionBuilder};
41pub use smelt_style::style::Color;
42pub use smelt_style::theme::Theme;
43pub use snapshot::SnapshotFrame;
44pub use surface::Surface;
45
46/// Per-leaf paint callback: `(paint_id, leaf_rect, grid, theme, terminal_size)`.
47/// The renderer calls this for each resolved [`LayoutTree::Leaf`].
48pub type PaintDispatch<'a> =
49    dyn FnMut(PaintId, Rect, &mut Grid, &std::sync::Arc<Theme>, (u16, u16)) + 'a;
50
51/// Walk `node` against `area`, paint chrome on containers, and dispatch
52/// each resolved leaf rect to `paint`. `Fit` constraints use the default
53/// `NoopSizer` (contribute `0`); use `paint_layout_tree_with` to drive
54/// content-aware sizing.
55pub fn paint_layout_tree(
56    grid: &mut Grid,
57    theme: &std::sync::Arc<Theme>,
58    node: &LayoutTree,
59    area: Rect,
60    term_size: (u16, u16),
61    paint: &mut PaintDispatch,
62) {
63    paint_layout_tree_with(
64        grid,
65        theme,
66        node,
67        area,
68        term_size,
69        &layout::NoopSizer,
70        paint,
71    );
72}
73
74/// Like [`paint_layout_tree`] but uses `sizer` to resolve `Fit` constraints
75/// against each leaf's natural size. Must use the same sizer as the rect
76/// resolution that drives hit-testing and viewport setup, so painted rects
77/// match.
78pub fn paint_layout_tree_with(
79    grid: &mut Grid,
80    theme: &std::sync::Arc<Theme>,
81    node: &LayoutTree,
82    area: Rect,
83    term_size: (u16, u16),
84    sizer: &dyn layout::LeafSizer,
85    paint: &mut PaintDispatch,
86) {
87    match node {
88        LayoutTree::Leaf { id, chrome, .. } => {
89            layout::paint_chrome(grid, area, chrome, theme);
90            let inner = layout::inset_for_chrome(area, chrome);
91            paint(*id, inner, grid, theme, term_size);
92        }
93        LayoutTree::Vbox { items, chrome } | LayoutTree::Hbox { items, chrome } => {
94            layout::paint_chrome(grid, area, chrome, theme);
95            let vertical = matches!(node, LayoutTree::Vbox { .. });
96            let (_, rects) = layout::layout_box_children(items, chrome, area, vertical, sizer);
97            for ((_, child), &rect) in items.iter().zip(rects.iter()) {
98                paint_layout_tree_with(grid, theme, child, rect, term_size, sizer, paint);
99            }
100        }
101    }
102}