pub use crossterm;
use std::io::{ self, Write };
use crossterm::{ QueueableCommand, terminal, cursor, event };
use crate::preludes::backend_creation::*;
pub fn crossterm_poll_events(
timeout: std::time::Duration,
event_state: &mut crate::event::EventState,
mut key_function: impl FnMut(
crossterm::event::KeyEvent,
&mut crate::event::EventState,
) -> Result<(), io::Error>,
) -> Result<(), io::Error> {
if crossterm::event::poll(timeout)? {
match crossterm::event::read()? {
crossterm::event::Event::Mouse(mouse_event) => {
match mouse_event.kind {
crossterm::event::MouseEventKind::Up(button) => {
match button {
crossterm::event::MouseButton::Left => event_state.mouse.buttons.left = false,
crossterm::event::MouseButton::Middle => event_state.mouse.buttons.middle = false,
crossterm::event::MouseButton::Right => event_state.mouse.buttons.right = false,
};
},
crossterm::event::MouseEventKind::Down(button) => {
match button {
crossterm::event::MouseButton::Left => event_state.mouse.buttons.left = true,
crossterm::event::MouseButton::Middle => event_state.mouse.buttons.middle = true,
crossterm::event::MouseButton::Right => event_state.mouse.buttons.right = true,
};
},
crossterm::event::MouseEventKind::ScrollUp => event_state.mouse.scroll.go_up(1),
crossterm::event::MouseEventKind::ScrollDown => event_state.mouse.scroll.go_down(1),
crossterm::event::MouseEventKind::ScrollLeft => event_state.mouse.scroll.go_left(1),
crossterm::event::MouseEventKind::ScrollRight => event_state.mouse.scroll.go_right(1),
_ => (),
};
event_state.mouse.position = Position::new(mouse_event.column as i16, mouse_event.row as i16);
},
crossterm::event::Event::Key(key_event) => key_function(key_event, event_state)?,
crossterm::event::Event::FocusGained => event_state.terminal.focused = true,
crossterm::event::Event::FocusLost => event_state.terminal.focused = false,
crossterm::event::Event::Paste(paste) => event_state.terminal.paste = Some(std::rc::Rc::new(paste)),
_ => (),
};
}
Ok(())
}
pub struct CrosstermBackend {
pub stdout: io::Stdout,
}
impl CrosstermBackend {
pub fn new() -> Self {
Self {
stdout: io::stdout(),
}
}
}
impl Backend<String> for CrosstermBackend {
fn flush(&mut self) -> Result<(), io::Error> {
self.stdout.flush()
}
fn terminal_size(&self) -> Result<Size, io::Error> {
let raw = terminal::size()?;
Ok(Size::new(raw.0, raw.1))
}
fn set_cursor_pos(&mut self, position: Position) -> Result<(), io::Error> {
self.stdout.queue(cursor::MoveTo(position.col as u16, position.row as u16))?;
Ok(())
}
fn alt_screen(&mut self, enable: bool) -> Result<(), io::Error> {
match enable {
true => self.stdout.queue(terminal::EnterAlternateScreen),
false => self.stdout.queue(terminal::LeaveAlternateScreen),
}?;
Ok(())
}
fn raw_mode(&mut self, enable: bool) -> Result<(), io::Error> {
match enable {
true => terminal::enable_raw_mode()?,
false => terminal::disable_raw_mode()?,
};
Ok(())
}
fn capture_mouse(&mut self, enable: bool) -> Result<(), io::Error> {
match enable {
true => self.stdout.queue(event::EnableMouseCapture),
false => self.stdout.queue(event::DisableMouseCapture),
}?;
Ok(())
}
fn clear(&mut self, clear_type: ClearType) -> Result<(), io::Error> {
macro_rules! queue_clear {
($clear_type: ident) => {
self.stdout.queue(terminal::Clear(terminal::ClearType::$clear_type))
};
}
match clear_type {
ClearType::All => queue_clear!(All),
ClearType::Purge => queue_clear!(Purge),
ClearType::CurrentLine => queue_clear!(CurrentLine),
ClearType::FromCursorDown => queue_clear!(FromCursorDown),
ClearType::FromCursorUp => queue_clear!(FromCursorUp),
ClearType::UntilNewLine => queue_clear!(UntilNewLine),
}?;
Ok(())
}
fn show_cursor(&mut self, enable: bool) -> Result<(), io::Error> {
match enable {
true => self.stdout.queue(cursor::Show)?,
false => self.stdout.queue(cursor::Hide)?,
};
Ok(())
}
fn begin_sync_update(&mut self) -> Result<(), io::Error> {
self.stdout.queue(terminal::BeginSynchronizedUpdate)?;
Ok(())
}
fn end_sync_update(&mut self) -> Result<(), io::Error> {
self.stdout.queue(terminal::EndSynchronizedUpdate)?;
Ok(())
}
fn print(&mut self, content: String) -> Result<(), io::Error> {
write!(self.stdout, "{}", content)?;
Ok(())
}
fn cursor_position(&self) -> Result<Position, io::Error> {
let raw = cursor::position()?;
Ok(Position::new(raw.0 as i16, raw.1 as i16))
}
}