Skip to main content

rich/
containers.rs

1//! Renderable containers.
2//!
3//! Port of upstream `rich/containers.py` (the `Renderables` class). `Lines` is
4//! internal to upstream's `Text` wrapping, which this port does at the segment
5//! level, so it is not ported.
6
7use std::sync::Arc;
8
9use crate::console::{Console, ConsoleOptions};
10use crate::measure::Measurement;
11use crate::protocol::Renderable;
12use crate::segment::Segment;
13
14/// A list of renderables rendered one after another. Mirrors
15/// `rich.containers.Renderables`, which `LogRender` puts in its message column.
16#[derive(Clone, Default)]
17pub struct Renderables {
18    renderables: Vec<Arc<dyn Renderable + Send + Sync>>,
19}
20
21impl Renderables {
22    /// A container of `renderables`, rendered in order.
23    pub fn new(renderables: Vec<Arc<dyn Renderable + Send + Sync>>) -> Self {
24        Renderables { renderables }
25    }
26
27    /// Add a renderable to the end. Port of `Renderables.append`.
28    pub fn append(&mut self, renderable: Arc<dyn Renderable + Send + Sync>) {
29        self.renderables.push(renderable);
30    }
31
32    /// The contained renderables.
33    pub fn renderables(&self) -> &[Arc<dyn Renderable + Send + Sync>] {
34        &self.renderables
35    }
36}
37
38impl Renderable for Renderables {
39    /// `yield from self._renderables`, each through `Console.render`.
40    ///
41    /// Upstream's renderables each end their output with a newline; this
42    /// port's separate lines instead, so each child's output is joined to the
43    /// previous one with a newline. A child that renders nothing adds no line.
44    fn rich_render(&self, console: &Console, options: &ConsoleOptions) -> Vec<Segment> {
45        let options = options.reset_height();
46        let mut segments: Vec<Segment> = Vec::new();
47        let mut first = true;
48        for renderable in &self.renderables {
49            let rendered = console.render(renderable.as_ref(), Some(&options));
50            if rendered.is_empty() {
51                continue;
52            }
53            if !first {
54                segments.push(Segment::line());
55            }
56            first = false;
57            segments.extend(rendered);
58        }
59        segments
60    }
61
62    /// Port of `Renderables.__rich_measure__`: the widest minimum and maximum
63    /// of the children, or `(1, 1)` when there are none.
64    fn measure(&self, console: &Console, options: &ConsoleOptions) -> Measurement {
65        let dimensions: Vec<Measurement> = self
66            .renderables
67            .iter()
68            .map(|renderable| Measurement::get(console, options, renderable.as_ref()))
69            .collect();
70        if dimensions.is_empty() {
71            return Measurement::new(1, 1);
72        }
73        Measurement::new(
74            dimensions.iter().map(|d| d.minimum).max().unwrap_or(0),
75            dimensions.iter().map(|d| d.maximum).max().unwrap_or(0),
76        )
77    }
78}