use std::fmt;
use std::io::{self, Write, Error, ErrorKind, Read};
use async::async_stdin;
use std::time::{SystemTime, Duration};
use raw::CONTROL_SEQUENCE_TIMEOUT;
derive_csi_sequence!("Hide the cursor.", Hide, "?25l");
derive_csi_sequence!("Show the cursor.", Show, "?25h");
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Goto(pub u16, pub u16);
impl Default for Goto {
fn default() -> Goto {
Goto(1, 1)
}
}
impl fmt::Display for Goto {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
debug_assert!(self != &Goto(0, 0), "Goto is one-based.");
write!(f, csi!("{};{}H"), self.1, self.0)
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Left(pub u16);
impl fmt::Display for Left {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, csi!("{}D"), self.0)
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Right(pub u16);
impl fmt::Display for Right {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, csi!("{}C"), self.0)
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Up(pub u16);
impl fmt::Display for Up {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, csi!("{}A"), self.0)
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Down(pub u16);
impl fmt::Display for Down {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, csi!("{}B"), self.0)
}
}
pub trait DetectCursorPos {
fn cursor_pos(&mut self) -> io::Result<(u16, u16)>;
}
impl<W: Write> DetectCursorPos for W {
fn cursor_pos(&mut self) -> io::Result<(u16, u16)> {
let mut stdin = async_stdin();
write!(self, "\x1B[6n")?;
self.flush()?;
let mut buf: [u8; 1] = [0];
let mut read_chars = Vec::new();
let timeout = Duration::from_millis(CONTROL_SEQUENCE_TIMEOUT);
let now = SystemTime::now();
while buf[0] != b'R' && now.elapsed().unwrap() < timeout {
if stdin.read(&mut buf)? > 0 {
read_chars.push(buf[0]);
}
}
if read_chars.len() == 0 {
return Err(Error::new(ErrorKind::Other, "Cursor position detection timed out."));
}
read_chars.pop(); let read_str = String::from_utf8(read_chars).unwrap();
let beg = read_str.rfind('[').unwrap();
let coords: String = read_str.chars().skip(beg + 1).collect();
let mut nums = coords.split(';');
let cy = nums.next()
.unwrap()
.parse::<u16>()
.unwrap();
let cx = nums.next()
.unwrap()
.parse::<u16>()
.unwrap();
Ok((cx, cy))
}
}