1use std::{
2 cell::RefCell,
3 fmt::Debug,
4 rc::{Rc, Weak},
5};
6
7use ratatui::{widgets::Paragraph, Frame};
8
9use crate::component::ComponentData;
10
11thread_local! {
12 pub(crate) static NEXT_NODE_ID: RefCell<u64> = RefCell::new(0);
13}
14
15pub(crate) fn new_node_id() -> u64 {
16 NEXT_NODE_ID.with_borrow_mut(|next| {
17 let id = *next;
18 *next += 1;
19 id
20 })
21}
22
23#[derive(Debug)]
24pub struct Node {
25 pub id: u64,
26 pub kind: NodeKind,
27 pub parent: Option<Weak<RefCell<Node>>>,
28 pub first_child: Option<NodeRef>,
29 pub next_sibling: Option<NodeRef>,
30}
31
32#[derive(Debug, Clone)]
33pub enum NodeKind {
34 Empty,
35 Text(String),
36 Component(Rc<ComponentData>),
37}
38
39#[derive(Clone, Debug)]
40pub struct NodeRef(pub Rc<RefCell<Node>>);
41
42impl NodeRef {
43 pub fn render(self, frame: &mut Frame, area: ratatui::prelude::Rect) {
44 let node = self.0.borrow();
45 match &node.kind {
46 NodeKind::Empty => {}
47 NodeKind::Text(text) => frame.render_widget(Paragraph::new(text.as_str()), area),
48 NodeKind::Component(data) => {
49 data.render(self.clone(), frame, area);
50 }
51 }
52 }
53
54 pub fn id(&self) -> u64 {
55 self.0.borrow().id
56 }
57
58 pub fn parent(&self) -> Option<NodeRef> {
59 let parent = self.0.borrow().parent.clone();
60 parent
61 .map(|parent| parent.upgrade().expect("Parent garbage collected"))
62 .map(|rc| Self(rc))
63 }
64
65 pub fn first_child(&self) -> Option<NodeRef> {
66 self.0.borrow().first_child.clone()
67 }
68
69 pub fn next_sibling(&self) -> Option<NodeRef> {
70 self.0.borrow().next_sibling.clone()
71 }
72
73 pub fn append_sibling(&self, kind: NodeKind) {
74 let mut self_borrow = self.0.borrow_mut();
75
76 let new_node = Rc::new(RefCell::new(Node {
77 id: new_node_id(),
78 kind,
79 parent: self_borrow.parent.clone(),
80 first_child: None,
81 next_sibling: self_borrow.next_sibling.clone(),
82 }));
83
84 self_borrow.next_sibling = Some(NodeRef(new_node));
85 }
86}