ratatui_kit/terminal/
mod.rs1use futures::{Stream, StreamExt, future::pending, stream::BoxStream};
2use std::{
3 collections::VecDeque,
4 fmt::Debug,
5 io,
6 sync::{Arc, Mutex, Weak},
7 task::{Poll, Waker},
8};
9
10mod cross_terminal;
11pub use cross_terminal::CrossTerminal;
12
13pub trait TerminalImpl: Send {
14 type Event: Clone + Debug;
15 fn is_raw_mode_enabled(&self) -> bool;
16 fn event_stream(&mut self) -> io::Result<BoxStream<'static, Self::Event>>;
17 fn received_ctrl_c(event: Self::Event) -> bool;
18 fn draw<F>(&mut self, f: F) -> io::Result<()>
19 where
20 F: FnOnce(&mut ratatui::Frame);
21}
22
23struct TerminalEventsInner<T> {
29 pending: VecDeque<T>,
30 waker: Option<Waker>,
31}
32
33pub struct TerminalEvents<T> {
36 inner: Arc<Mutex<TerminalEventsInner<T>>>,
37}
38
39impl<T> Stream for TerminalEvents<T> {
41 type Item = T;
42 fn poll_next(
43 self: std::pin::Pin<&mut Self>,
44 cx: &mut std::task::Context<'_>,
45 ) -> Poll<Option<Self::Item>> {
46 let mut inner = self.inner.lock().unwrap();
47 if let Some(event) = inner.pending.pop_front() {
48 Poll::Ready(Some(event)) } else {
50 inner.waker = Some(cx.waker().clone()); Poll::Pending
52 }
53 }
54}
55
56pub struct Terminal<T = CrossTerminal>
63where
64 T: TerminalImpl,
65{
66 inner: Box<T>,
67 event_stream: Option<BoxStream<'static, T::Event>>,
68 subscribers: Vec<Weak<Mutex<TerminalEventsInner<T::Event>>>>,
69 received_ctrl_c: bool,
70}
71
72impl<T> Terminal<T>
73where
74 T: TerminalImpl,
75{
76 pub fn new(inner: T) -> Self {
77 Self {
78 inner: Box::new(inner),
79 event_stream: None,
80 subscribers: Vec::new(),
81 received_ctrl_c: false,
82 }
83 }
84
85 pub fn is_raw_mode_enabled(&self) -> bool {
86 self.inner.is_raw_mode_enabled()
87 }
88
89 pub fn received_ctrl_c(&self) -> bool {
90 self.received_ctrl_c
91 }
92
93 pub fn draw<F>(&mut self, f: F) -> io::Result<()>
94 where
95 F: FnOnce(&mut ratatui::Frame),
96 {
97 self.inner.draw(f)
98 }
99
100 pub fn events(&mut self) -> io::Result<TerminalEvents<T::Event>> {
102 if self.event_stream.is_none() {
104 self.event_stream = Some(self.inner.event_stream()?);
105 }
106
107 let inner = Arc::new(Mutex::new(TerminalEventsInner {
109 pending: VecDeque::new(),
110 waker: None,
111 }));
112
113 self.subscribers.push(Arc::downgrade(&inner));
115
116 Ok(TerminalEvents { inner })
117 }
118
119 pub async fn wait(&mut self) {
121 if let Some(stream) = &mut self.event_stream {
122 while let Some(event) = stream.next().await {
123 self.received_ctrl_c = T::received_ctrl_c(event.clone());
125 if self.received_ctrl_c {
126 return; }
128
129 self.subscribers.retain(|subscriber| {
131 if let Some(subscriber) = subscriber.upgrade() {
132 let mut subscriber = subscriber.lock().unwrap();
133 subscriber.pending.push_back(event.clone());
135
136 if let Some(waker) = subscriber.waker.take() {
138 waker.wake(); }
140
141 true } else {
143 false }
145 });
146 }
147 } else {
148 pending().await }
150 }
151}