1use std::sync::Arc;
2
3use crossbeam_skiplist::SkipMap;
4use tokio::sync::Mutex;
5
6use crate::{Pane, terminal::Terminal};
7
8pub type SharedRenderer<K> = Arc<Renderer<K>>;
10
11pub struct Renderer<K: Ord + Send + 'static> {
13 terminal: Mutex<Terminal>,
14 panes: SkipMap<K, Pane>,
15}
16
17impl<K: Ord + Send + 'static> Renderer<K> {
18 pub fn try_new() -> anyhow::Result<Self> {
19 Ok(Self {
20 terminal: Mutex::new(Terminal {
21 position: crossterm::cursor::position()?,
22 }),
23 panes: SkipMap::new(),
24 })
25 }
26
27 pub async fn try_new_with_panes<I>(init_panes: I, draw: bool) -> anyhow::Result<Self>
28 where
29 I: IntoIterator<Item = (K, Pane)>,
30 {
31 let renderer = Self::try_new()?;
32 renderer.update(init_panes);
33 if draw {
34 renderer.render().await?;
35 }
36 Ok(renderer)
37 }
38
39 pub fn update<I>(&self, items: I) -> &Self
40 where
41 I: IntoIterator<Item = (K, Pane)>,
42 {
43 items.into_iter().for_each(|(index, pane)| {
44 self.panes.insert(index, pane);
45 });
46 self
47 }
48
49 pub fn remove<I>(&self, items: I) -> &Self
50 where
51 I: IntoIterator<Item = K>,
52 {
53 items.into_iter().for_each(|index| {
54 self.panes.remove(&index);
55 });
56 self
57 }
58
59 pub async fn render(&self) -> anyhow::Result<()> {
61 let panes: Vec<Pane> = self
62 .panes
63 .iter()
64 .map(|entry| entry.value().clone())
65 .collect();
66 let mut terminal = self.terminal.lock().await;
67 terminal.draw(&panes)
68 }
69}