use std::fmt;
use std::io;
use std::sync::{LockResult, TryLockResult};
use std::time::Duration;
use crate::priv_util::{map_lock_result, map_try_lock_result};
use crate::sys;
use crate::terminal::{
Color, Cursor, CursorMode, Event, PrepareConfig, Size, Style, Theme,
Terminal,
};
pub struct Screen(sys::Screen);
pub struct ScreenReadGuard<'a>(sys::ScreenReadGuard<'a>);
pub struct ScreenWriteGuard<'a>(sys::ScreenWriteGuard<'a>);
impl Screen {
pub fn new(config: PrepareConfig) -> io::Result<Screen> {
sys::Screen::stdout(config).map(Screen)
}
pub fn stderr(config: PrepareConfig) -> io::Result<Screen> {
sys::Screen::stderr(config).map(Screen)
}
pub fn with_terminal(term: Terminal, config: PrepareConfig) -> io::Result<Screen> {
sys::Screen::new(term.0, config).map(Screen)
}
#[inline]
pub fn name(&self) -> &str {
self.0.name()
}
#[inline]
pub fn lock_read(&self) -> LockResult<ScreenReadGuard> {
map_lock_result(self.0.lock_read(), ScreenReadGuard)
}
#[inline]
pub fn lock_write(&self) -> LockResult<ScreenWriteGuard> {
map_lock_result(self.0.lock_write(), ScreenWriteGuard)
}
#[inline]
pub fn try_lock_read(&self) -> TryLockResult<ScreenReadGuard> {
map_try_lock_result(self.0.try_lock_read(), ScreenReadGuard)
}
#[inline]
pub fn try_lock_write(&self) -> TryLockResult<ScreenWriteGuard> {
map_try_lock_result(self.0.try_lock_write(), ScreenWriteGuard)
}
}
impl Screen {
pub fn wait_event(&self, timeout: Option<Duration>) -> io::Result<bool> {
self.0.wait_event(timeout)
}
pub fn read_event(&self, timeout: Option<Duration>) -> io::Result<Option<Event>> {
self.0.read_event(timeout)
}
}
impl Screen {
#[inline]
pub fn size(&self) -> Size {
self.0.size()
}
#[inline]
pub fn cursor(&self) -> Cursor {
self.0.cursor()
}
#[inline]
pub fn set_cursor<C: Into<Cursor>>(&self, pos: C) {
self.0.set_cursor(pos.into());
}
#[inline]
pub fn next_line(&self, column: usize) {
self.0.next_line(column);
}
pub fn set_cursor_mode(&self, mode: CursorMode) -> io::Result<()> {
self.0.set_cursor_mode(mode)
}
pub fn clear_screen(&self) {
self.0.clear_screen();
}
#[inline]
pub fn add_style(&self, style: Style) {
self.0.add_style(style);
}
#[inline]
pub fn remove_style(&self, style: Style) {
self.0.remove_style(style);
}
#[inline]
pub fn set_style<S: Into<Option<Style>>>(&self, style: S) {
self.0.set_style(style.into().unwrap_or_default());
}
#[inline]
pub fn set_fg<C: Into<Option<Color>>>(&self, fg: C) {
self.0.set_fg(fg.into());
}
#[inline]
pub fn set_bg<C: Into<Option<Color>>>(&self, bg: C) {
self.0.set_bg(bg.into());
}
#[inline]
pub fn set_theme(&self, theme: Theme) {
self.0.set_theme(theme)
}
#[inline]
pub fn clear_attributes(&self) {
self.0.clear_attributes();
}
#[inline]
pub fn bold(&self) {
self.add_style(Style::BOLD);
}
#[inline]
pub fn italic(&self) {
self.add_style(Style::ITALIC);
}
#[inline]
pub fn underline(&self) {
self.add_style(Style::UNDERLINE);
}
#[inline]
pub fn reverse(&self) {
self.add_style(Style::REVERSE);
}
pub fn refresh(&self) -> io::Result<()> {
self.0.refresh()
}
pub fn write_at<C>(&self, position: C, text: &str)
where C: Into<Cursor> {
self.0.write_at(position.into(), text);
}
pub fn write_styled<F, B, S>(&self, fg: F, bg: B, style: S, text: &str) where
F: Into<Option<Color>>,
B: Into<Option<Color>>,
S: Into<Option<Style>>,
{
self.0.write_styled(fg.into(), bg.into(), style.into().unwrap_or_default(), text);
}
pub fn write_styled_at<C, F, B, S>(&self, position: C,
fg: F, bg: B, style: S, text: &str) where
C: Into<Cursor>,
F: Into<Option<Color>>,
B: Into<Option<Color>>,
S: Into<Option<Style>>,
{
self.0.write_styled_at(position.into(),
fg.into(), bg.into(), style.into().unwrap_or_default(), text);
}
pub fn write_char(&self, ch: char) {
self.0.write_char(ch);
}
pub fn write_str(&self, s: &str) {
self.0.write_str(s);
}
pub fn write_fmt(&self, args: fmt::Arguments) {
let s = args.to_string();
self.write_str(&s)
}
#[doc(hidden)]
pub fn borrow_term_write_guard(&self) -> ScreenWriteGuard {
self.lock_write().unwrap()
}
}
impl<'a> ScreenReadGuard<'a> {
pub fn wait_event(&mut self, timeout: Option<Duration>) -> io::Result<bool> {
self.0.wait_event(timeout)
}
pub fn read_event(&mut self, timeout: Option<Duration>) -> io::Result<Option<Event>> {
self.0.read_event(timeout)
}
}
impl<'a> ScreenWriteGuard<'a> {
#[inline]
pub fn size(&self) -> Size {
self.0.size()
}
#[inline]
pub fn cursor(&self) -> Cursor {
self.0.cursor()
}
#[inline]
pub fn set_cursor<C: Into<Cursor>>(&mut self, pos: C) {
self.0.set_cursor(pos.into());
}
#[inline]
pub fn next_line(&mut self, column: usize) {
self.0.next_line(column);
}
pub fn set_cursor_mode(&mut self, mode: CursorMode) -> io::Result<()> {
self.0.set_cursor_mode(mode)
}
pub fn clear_screen(&mut self) {
self.0.clear_screen();
}
#[inline]
pub fn add_style(&mut self, style: Style) {
self.0.add_style(style)
}
#[inline]
pub fn remove_style(&mut self, style: Style) {
self.0.remove_style(style)
}
#[inline]
pub fn set_style<S: Into<Option<Style>>>(&mut self, style: S) {
self.0.set_style(style.into().unwrap_or_default())
}
#[inline]
pub fn set_fg<C: Into<Option<Color>>>(&mut self, fg: C) {
self.0.set_fg(fg.into())
}
#[inline]
pub fn set_bg<C: Into<Option<Color>>>(&mut self, bg: C) {
self.0.set_bg(bg.into())
}
#[inline]
pub fn set_theme(&mut self, theme: Theme) {
self.0.set_theme(theme)
}
#[inline]
pub fn clear_attributes(&mut self) {
self.0.clear_attributes()
}
#[inline]
pub fn bold(&mut self) {
self.add_style(Style::BOLD)
}
#[inline]
pub fn italic(&mut self) {
self.add_style(Style::ITALIC);
}
#[inline]
pub fn underline(&mut self) {
self.add_style(Style::UNDERLINE)
}
#[inline]
pub fn reverse(&mut self) {
self.add_style(Style::REVERSE)
}
pub fn refresh(&mut self) -> io::Result<()> {
self.0.refresh()
}
pub fn write_at<C>(&mut self, position: C, text: &str)
where C: Into<Cursor> {
self.0.write_at(position.into(), text)
}
pub fn write_styled<F, B, S>(&mut self, fg: F, bg: B, style: S, text: &str) where
F: Into<Option<Color>>,
B: Into<Option<Color>>,
S: Into<Option<Style>>,
{
self.0.write_styled(fg.into(), bg.into(), style.into().unwrap_or_default(), text)
}
pub fn write_styled_at<C, F, B, S>(&mut self, position: C,
fg: F, bg: B, style: S, text: &str) where
C: Into<Cursor>,
F: Into<Option<Color>>,
B: Into<Option<Color>>,
S: Into<Option<Style>>,
{
self.0.write_styled_at(position.into(),
fg.into(), bg.into(), style.into().unwrap_or_default(), text)
}
pub fn write_char(&mut self, ch: char) {
self.0.write_char(ch)
}
pub fn write_str(&mut self, s: &str) {
self.0.write_str(s)
}
pub fn write_fmt(&mut self, args: fmt::Arguments) {
let s = args.to_string();
self.write_str(&s)
}
#[doc(hidden)]
pub fn borrow_term_write_guard(&mut self) -> &mut Self {
self
}
}
#[cfg(unix)]
impl crate::unix::TerminalExt for Screen {
fn read_raw(&mut self, buf: &mut [u8], timeout: Option<Duration>) -> io::Result<Option<Event>> {
self.0.read_raw(buf, timeout)
}
}
#[cfg(unix)]
impl<'a> crate::unix::TerminalExt for ScreenReadGuard<'a> {
fn read_raw(&mut self, buf: &mut [u8], timeout: Option<Duration>) -> io::Result<Option<Event>> {
self.0.read_raw(buf, timeout)
}
}
#[cfg(windows)]
impl crate::windows::TerminalExt for Screen {
fn read_raw(&mut self, buf: &mut [u16], timeout: Option<Duration>) -> io::Result<Option<Event>> {
self.0.read_raw(buf, timeout)
}
fn read_raw_event(&mut self, events: &mut [::winapi::um::wincon::INPUT_RECORD],
timeout: Option<Duration>) -> io::Result<Option<Event>> {
self.0.read_raw_event(events, timeout)
}
}
#[cfg(windows)]
impl<'a> crate::windows::TerminalExt for ScreenReadGuard<'a> {
fn read_raw(&mut self, buf: &mut [u16], timeout: Option<Duration>) -> io::Result<Option<Event>> {
self.0.read_raw(buf, timeout)
}
fn read_raw_event(&mut self, events: &mut [::winapi::um::wincon::INPUT_RECORD],
timeout: Option<Duration>) -> io::Result<Option<Event>> {
self.0.read_raw_event(events, timeout)
}
}