ratatui_kit/render/
tree.rs1use 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}