mod debug;
#[cfg(target_family = "unix")]
mod ncurses;
mod system_event_thread;
#[cfg(target_family = "unix")]
mod termios;
#[cfg(target_arch = "wasm32")]
mod web_terminal;
#[cfg(target_os = "windows")]
mod windows_console;
#[cfg(target_os = "windows")]
mod windows_vt;
#[cfg(any(target_family = "unix", feature = "CROSSTERM"))]
mod crossterm;
pub(crate) mod utils;
#[cfg(test)]
mod tests;
use std::sync::mpsc::Sender;
use super::graphics::Size;
use super::graphics::Surface;
use super::system::Error;
use super::system::ErrorKind;
use super::system::SystemEvent;
#[cfg(not(target_arch = "wasm32"))]
pub(super) use self::system_event_thread::SystemEventReader;
use self::debug::DebugTerminal;
#[cfg(target_family = "unix")]
use self::ncurses::NcursesTerminal;
#[cfg(target_family = "unix")]
use self::termios::TermiosTerminal;
#[cfg(target_arch = "wasm32")]
use self::web_terminal::WebTerminal;
#[cfg(target_os = "windows")]
use self::windows_console::WindowsConsoleTerminal;
#[cfg(target_os = "windows")]
use self::windows_vt::WindowsVTTerminal;
#[cfg(any(target_family = "unix", feature = "CROSSTERM"))]
use self::crossterm::CrossTerm;
pub(crate) trait Backend {
fn update_screen(&mut self, surface: &Surface);
fn on_resize(&mut self, new_size: Size);
fn size(&self) -> Size;
fn clipboard_text(&self) -> Option<String>;
fn set_clipboard_text(&mut self, text: &str);
fn has_clipboard_text(&self) -> bool;
fn query_system_event(&mut self) -> Option<SystemEvent> {
None
}
fn is_single_threaded(&self) -> bool;
fn on_close(&mut self) {}
}
#[repr(u8)]
#[derive(Copy, Clone, PartialEq)]
pub enum Type {
#[cfg(target_os = "windows")]
WindowsConsole,
#[cfg(target_os = "windows")]
WindowsVT,
#[cfg(target_family = "unix")]
Termios,
#[cfg(target_family = "unix")]
NcursesTerminal,
#[cfg(target_arch = "wasm32")]
WebTerminal,
#[cfg(any(target_family = "unix", feature = "CROSSTERM"))]
CrossTerm,
}
pub(crate) fn new(builder: &crate::system::Builder, sender: Sender<SystemEvent>) -> Result<Box<dyn Backend>, Error> {
if let Some(sz) = builder.size.as_ref() {
if (sz.width == 0) || (sz.height == 0) {
return Err(Error::new(
ErrorKind::InvalidParameter,
format!(
"Invalid size for a terminal ({}x{}). Both width and height must be bigger than 0 !",
sz.width, sz.height
),
));
}
}
if builder.debug_script.is_some() {
let term = DebugTerminal::new(builder)?;
return Ok(Box::new(term));
}
if builder.backend.is_none() {
return build_default_backend(builder, sender);
}
let backend = *builder.backend.as_ref().unwrap();
match backend {
#[cfg(target_os = "windows")]
Type::WindowsConsole => {
let term = WindowsConsoleTerminal::new(builder, sender)?;
Ok(Box::new(term))
}
#[cfg(target_os = "windows")]
Type::WindowsVT => {
let term = WindowsVTTerminal::new(builder, sender)?;
Ok(Box::new(term))
}
#[cfg(target_family = "unix")]
Type::Termios => TermiosTerminal::new(builder, sender),
#[cfg(target_family = "unix")]
Type::NcursesTerminal => {
let term = NcursesTerminal::new(builder, sender)?;
Ok(Box::new(term))
}
#[cfg(target_arch = "wasm32")]
Type::WebTerminal => {
let term = WebTerminal::new(builder, sender)?;
Ok(Box::new(term))
}
#[cfg(any(target_family = "unix", feature = "CROSSTERM"))]
Type::CrossTerm => {
let term = CrossTerm::new(builder, sender)?;
Ok(Box::new(term))
}
}
}
#[cfg(target_arch = "wasm32")]
fn build_default_backend(builder: &crate::system::Builder, sender: Sender<SystemEvent>) -> Result<Box<dyn Backend>, Error> {
let term = WebTerminal::new(builder, sender)?;
Ok(Box::new(term))
}
#[cfg(target_os = "windows")]
fn build_default_backend(builder: &crate::system::Builder, sender: Sender<SystemEvent>) -> Result<Box<dyn Backend>, Error> {
let term = WindowsConsoleTerminal::new(builder, sender)?;
Ok(Box::new(term))
}
#[cfg(target_os = "linux")]
fn build_default_backend(builder: &crate::system::Builder, sender: Sender<SystemEvent>) -> Result<Box<dyn Backend>, Error> {
let term = CrossTerm::new(builder, sender)?;
Ok(Box::new(term))
}
#[cfg(target_os = "macos")]
fn build_default_backend(builder: &crate::system::Builder, sender: Sender<SystemEvent>) -> Result<Box<dyn Backend>, Error> {
TermiosTerminal::new(builder, sender)
}
#[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos", target_arch = "wasm32")))]
fn build_default_backend(builder: &crate::system::Builder, sender: Sender<SystemEvent>) -> Result<Box<dyn Backend>, Error> {
TermiosTerminal::new(builder, sender)
}