use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::sync::mpsc;
use std::sync::Arc;
use std::time::Duration;
use termwiz::input::InputEvent;
use termwiz::terminal::Terminal;
use termwiz::terminal::TerminalWaker;
use crate::action::Action;
use crate::action::ActionSender;
use crate::error::Error;
use crate::file::FileIndex;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum Event {
Action(Action),
Input(InputEvent),
Loaded(FileIndex),
#[cfg(feature = "load_file")]
Appending(FileIndex),
Reloading(FileIndex),
Render,
Refresh,
RefreshOverlay,
Progress,
SearchFirstMatch(FileIndex),
SearchFinished(FileIndex),
}
#[derive(Debug, Clone)]
pub(crate) struct UniqueInstance(Arc<AtomicBool>);
impl UniqueInstance {
pub(crate) fn new() -> UniqueInstance {
UniqueInstance(Arc::new(AtomicBool::new(false)))
}
}
pub(crate) enum Envelope {
Normal(Event),
Unique(Event, UniqueInstance),
}
#[derive(Clone)]
pub(crate) struct EventSender(mpsc::Sender<Envelope>, TerminalWaker);
impl EventSender {
pub(crate) fn send(&self, event: Event) -> Result<(), Error> {
self.0.send(Envelope::Normal(event))?;
self.1.wake()?;
Ok(())
}
pub(crate) fn send_unique(&self, event: Event, unique: &UniqueInstance) -> Result<(), Error> {
if unique
.0
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
.is_ok()
{
self.0.send(Envelope::Unique(event, unique.clone()))?;
self.1.wake()?;
}
Ok(())
}
}
pub(crate) struct EventStream {
send: mpsc::Sender<Envelope>,
recv: mpsc::Receiver<Envelope>,
waker: TerminalWaker,
}
impl EventStream {
pub(crate) fn new(waker: TerminalWaker) -> EventStream {
let (send, recv) = mpsc::channel();
EventStream { send, recv, waker }
}
pub(crate) fn sender(&self) -> EventSender {
EventSender(self.send.clone(), self.waker.clone())
}
pub(crate) fn action_sender(&self) -> ActionSender {
ActionSender::new(self.sender())
}
pub(crate) fn try_recv(&self, timeout: Option<Duration>) -> Result<Option<Event>, Error> {
let envelope = match timeout {
Some(timeout) => match self.recv.recv_timeout(timeout) {
Ok(envelope) => envelope,
Err(mpsc::RecvTimeoutError::Timeout) => return Ok(None),
Err(e) => return Err(e.into()),
},
None => match self.recv.try_recv() {
Ok(envelope) => envelope,
Err(mpsc::TryRecvError::Empty) => return Ok(None),
Err(e) => return Err(e.into()),
},
};
match envelope {
Envelope::Normal(event) => Ok(Some(event)),
Envelope::Unique(event, unique) => {
unique.0.store(false, Ordering::SeqCst);
Ok(Some(event))
}
}
}
pub(crate) fn get(
&self,
term: &mut dyn Terminal,
wait: Option<Duration>,
) -> Result<Option<Event>, Error> {
loop {
if let Some(event) = self.try_recv(None)? {
return Ok(Some(event));
}
match term.poll_input(wait).map_err(Error::Termwiz)? {
Some(InputEvent::Wake) => {}
Some(input_event) => return Ok(Some(Event::Input(input_event))),
None => return Ok(None),
}
}
}
}