ratatui_kit/render/
tree.rs

1use futures::{FutureExt, future::select};
2use std::io::{self};
3
4use crate::{
5    component::{ComponentHelperExt, InstantiatedComponent},
6    context::{ContextStack, SystemContext},
7    element::ElementExt,
8    props::AnyProps,
9    terminal::Terminal,
10};
11
12use super::ComponentDrawer;
13
14pub struct Tree<'a> {
15    root_component: InstantiatedComponent,
16    props: AnyProps<'a>,
17    system_context: SystemContext,
18}
19
20impl<'a> Tree<'a> {
21    pub(crate) fn new(mut props: AnyProps<'a>, helper: Box<dyn ComponentHelperExt>) -> Self {
22        Tree {
23            root_component: InstantiatedComponent::new(props.borrow(), helper),
24            props,
25            system_context: SystemContext::new(),
26        }
27    }
28
29    fn render(&mut self, terminal: &mut Terminal) -> io::Result<()> {
30        let mut component_context_stack = ContextStack::root(&mut self.system_context);
31        self.root_component
32            .update(terminal, &mut component_context_stack, self.props.borrow());
33
34        terminal
35            .draw(|frame| {
36                let area = frame.area();
37                let mut drawer = ComponentDrawer { frame, area };
38                self.root_component.draw(&mut drawer);
39            })
40            .expect("Failed to draw the terminal");
41        terminal.events()?;
42        Ok(())
43    }
44
45    async fn render_loop(&mut self, terminal: &mut Terminal) -> io::Result<()> {
46        loop {
47            self.render(terminal)?;
48            if self.system_context.should_exit() || terminal.received_ctrl_c() {
49                break;
50            }
51            select(self.root_component.wait().boxed(), terminal.wait().boxed()).await;
52            if terminal.received_ctrl_c() {
53                break;
54            }
55        }
56        Ok(())
57    }
58}
59
60pub(crate) fn render<E: ElementExt>(mut element: E, mut terminal: Terminal) -> io::Result<()> {
61    let helper = element.helper();
62    let mut tree = Tree::new(element.props_mut(), helper);
63    tree.render(&mut terminal)?;
64    Ok(())
65}
66
67pub(crate) async fn render_loop<E: ElementExt>(
68    mut element: E,
69    mut terminal: Terminal,
70) -> io::Result<()> {
71    let helper = element.helper();
72    let mut tree = Tree::new(element.props_mut(), helper);
73    tree.render_loop(&mut terminal).await?;
74    Ok(())
75}