Skip to main content

rich/
constrain.rs

1//! Width constraint.
2//!
3//! Port of upstream `rich/constrain.py`. [`Constrain`] renders a child within a
4//! reduced maximum width.
5
6use crate::console::{Console, ConsoleOptions};
7use crate::protocol::Renderable;
8use crate::segment::Segment;
9
10/// Limits a child renderable to at most `width` cells. Mirrors `rich.constrain.Constrain`.
11pub struct Constrain {
12    child: Box<dyn Renderable>,
13    width: Option<usize>,
14}
15
16impl Constrain {
17    /// Constrain `child` to `width` cells (or leave unconstrained when `None`).
18    pub fn new(child: Box<dyn Renderable>, width: Option<usize>) -> Self {
19        Constrain { child, width }
20    }
21}
22
23impl Renderable for Constrain {
24    fn rich_render(&self, console: &Console, options: &ConsoleOptions) -> Vec<Segment> {
25        let width = match self.width {
26            Some(width) => width.min(options.max_width),
27            None => options.max_width,
28        };
29        let child_options = options.update_width(width);
30        self.child.rich_render(console, &child_options)
31    }
32}
33
34#[cfg(test)]
35mod tests {
36    use super::*;
37    use crate::color::ColorSystem;
38    use crate::panel::Panel;
39    use crate::r#box::SQUARE;
40    use crate::text::Text;
41
42    #[test]
43    fn constrains_panel_width() {
44        let console = Console::builder()
45            .force_terminal(true)
46            .color_system(Some(ColorSystem::Truecolor))
47            .width(20)
48            .build();
49        let panel = Panel::new(Box::new(Text::new("hi"))).box_set(SQUARE);
50        let constrained = Constrain::new(Box::new(panel), Some(10));
51        let out = console.render_export(&constrained);
52        assert_eq!(out, "┌────────┐\n│ hi     │\n└────────┘\n");
53    }
54}