ratatui_kit/render/
tree.rs

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