ratatui_kit/hooks/
use_insert_before.rs

1use std::{
2    collections::VecDeque,
3    sync::{Arc, Mutex},
4    task::{Poll, Waker},
5};
6
7use ratatui::{buffer::Buffer, widgets::Widget};
8
9use crate::{Hook, Hooks, Terminal};
10
11mod private {
12    pub trait Sealed {}
13    impl Sealed for crate::hooks::Hooks<'_, '_> {}
14}
15
16type FnBox = Box<dyn FnOnce(&mut Buffer) + Send>;
17
18#[derive(Clone, Default)]
19pub struct InsertBeforeHandler {
20    queue: Arc<Mutex<VecDeque<(u16, FnBox)>>>,
21    waker: Arc<Mutex<Option<Waker>>>,
22}
23
24impl Hook for InsertBeforeHandler {
25    fn poll_change(
26        mut self: std::pin::Pin<&mut Self>,
27        cx: &mut std::task::Context,
28    ) -> std::task::Poll<()> {
29        let mut waker = self.waker.lock().unwrap();
30        let mut queue = self.queue.lock().unwrap();
31        if queue.is_empty() {
32            waker.replace(cx.waker().clone());
33            Poll::Pending
34        } else {
35            Poll::Ready(())
36        }
37    }
38
39    fn post_component_update(&mut self, updater: &mut crate::ComponentUpdater) {
40        let mut queue = self.queue.lock().unwrap();
41        for (height, callback) in queue.drain(..) {
42            updater.terminal().insert_before(height, callback);
43        }
44    }
45}
46
47impl InsertBeforeHandler {
48    pub fn insert_before<F>(&self, height: u16, callback: F) -> &Self
49    where
50        F: FnOnce(&mut Buffer) + Send + 'static,
51    {
52        let mut queue = self.queue.lock().unwrap();
53        queue.push_back((height, Box::new(callback)));
54        self
55    }
56
57    pub fn render_before<T: Widget + Send + 'static>(&self, widget: T, height: u16) -> &Self {
58        self.insert_before(height, move |buf| {
59            widget.render(buf.area, buf);
60        });
61        self
62    }
63
64    pub fn finish(&self) {
65        if let Some(waker) = self.waker.lock().unwrap().take() {
66            waker.wake();
67        }
68    }
69}
70
71pub trait UseInsertBefore: private::Sealed {
72    fn use_insert_before(&mut self) -> InsertBeforeHandler;
73}
74
75impl UseInsertBefore for Hooks<'_, '_> {
76    fn use_insert_before(&mut self) -> InsertBeforeHandler {
77        self.use_hook(InsertBeforeHandler::default).clone()
78    }
79}