use std::fmt;
use std::io::{Read, Write, Result, Error, ErrorKind};
use std::iter::Peekable;
pub enum Sequence<'a> {
Reset,
LineWrap(bool),
FontDefault,
FontAlternate,
CursorAt(u32, u32),
CursorMove(i32, i32),
CursorSave,
CursorRestore,
CursorSaveAttributes,
CursorRestoreAttributes,
ScrollEnable(Option<(u32, u32)>),
Scroll(i32),
EraseEndOfLine,
EraseStartOfLine,
EraseLine,
EraseDown,
EraseUp,
EraseScreen,
SetAttributes(&'a [Attribute])
}
pub enum Attribute {
Reset,
Bright,
Dim,
Underscore,
Blink,
Reverse,
Hidden,
Foreground(Color),
Background(Color)
}
pub enum Color {
Black,
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White
}
impl<'a> fmt::Display for Sequence<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Sequence::*;
match self {
Reset => write!(f, "\x1bc"),
LineWrap(true) => write!(f, "\x1b[7h"),
LineWrap(false) => write!(f, "\x1b[7l"),
FontDefault => write!(f, "\x1b("),
FontAlternate => write!(f, "\x1b)"),
CursorAt(row, column) => write!(f, "\x1b[{};{}H", row, column),
CursorMove(drow, dcolumn) => {
if *drow != 0 {
if *drow < 0 {
write!(f, "\x1b[{}A", -drow)?;
} else {
write!(f, "\x1b[{}B", drow)?;
}
}
if *dcolumn != 0 {
if *dcolumn > 0 {
write!(f, "\x1b[{}C", dcolumn)?;
} else {
write!(f, "\x1b[{}D", -dcolumn)?;
}
}
Ok(())
},
CursorSave => write!(f, "\x1b[s"),
CursorRestore => write!(f, "\x1b[u"),
CursorSaveAttributes => write!(f, "\x1b7"),
CursorRestoreAttributes => write!(f, "\x1b8"),
ScrollEnable(None) => write!(f, "\x1b[r"),
ScrollEnable(Some((start, end))) => write!(f, "\x1b[{};{}r", start, end),
Scroll(d) => {
if *d < 0 {
for _ in 0..(-*d) {
write!(f, "\x1b[D")?;
}
} else {
for _ in 0..*d {
write!(f, "\x1b[M")?;
}
}
Ok(())
},
EraseEndOfLine => write!(f, "\x1b[K"),
EraseStartOfLine => write!(f, "\x1b[1K"),
EraseLine => write!(f, "\x1b[2K"),
EraseDown => write!(f, "\x1b[J"),
EraseUp => write!(f, "\x1b[1J"),
EraseScreen => write!(f, "\x1b[2J"),
SetAttributes(attributes) => {
write!(f, "\x1b[{}m", DisplayAttributes(attributes))
}
}
}
}
impl fmt::Display for Attribute {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Attribute::*;
match self {
Reset => write!(f, "0"),
Bright => write!(f, "1"),
Dim => write!(f, "2"),
Underscore => write!(f, "4"),
Blink => write!(f, "5"),
Reverse => write!(f, "7"),
Hidden => write!(f, "8"),
Foreground(c) => write!(f, "{}", 30+c.index()),
Background(c) => write!(f, "{}", 40+c.index()),
}
}
}
impl Color {
pub fn index(&self) -> u8 {
use Color::*;
match self {
Black => 0,
Red => 1,
Green => 2,
Yellow => 3,
Blue => 4,
Magenta => 5,
Cyan => 6,
White => 7
}
}
}
struct DisplayAttributes<'a>(&'a [Attribute]);
impl<'a> fmt::Display for DisplayAttributes<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.0.split_first() {
Some((head, tail)) => {
write!(f, "{}", head)?;
for a in tail {
write!(f, ";{}", a)?;
}
Ok(())
},
None => Ok(())
}
}
}
pub enum Query {
CursorPosition
}
impl fmt::Display for Query {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Query::*;
match self {
CursorPosition => write!(f, "\x1b[6n")
}
}
}
pub enum Response {
CursorPosition(u32, u32)
}
pub struct Device<I: Read, O: Write> {
input: I,
output: O,
buffer: Vec<u8>,
offset: usize
}
impl<I: Read, O: Write> Device<I, O> {
pub fn new(input: I, output: O) -> Device<I, O> {
Device {
input: input,
output: output,
buffer: Vec::new(),
offset: 0
}
}
fn next_byte(&mut self) -> Result<Option<u8>> {
let mut buffer = [0];
let n = self.input.read(&mut buffer)?;
if n == 0 {
Ok(None)
} else {
Ok(Some(buffer[0]))
}
}
fn response(&mut self) -> Result<Response> {
loop {
match self.next_byte()? {
Some(0x1b) => {
return self.parse_response()
},
Some(c) => {
self.buffer.push(c)
},
None => return Err(Error::new(ErrorKind::UnexpectedEof, "no response from the device"))
}
}
}
fn parse_response(&mut self) -> Result<Response> {
let mut buffer = Vec::new();
loop {
match self.next_byte()? {
Some(c) => {
match c {
0x52 => {
let mut it = buffer.into_iter().peekable();
expect_byte(&mut it, 0x5b)?;
let row = read_u32(&mut it)?;
expect_byte(&mut it, 0x3b)?;
let column = read_u32(&mut it)?;
return Ok(Response::CursorPosition(row, column))
},
_ => {
buffer.push(c)
}
}
},
None => return Err(Error::new(ErrorKind::UnexpectedEof, "incomplete device response"))
}
}
}
#[allow(irrefutable_let_patterns)]
pub fn cursor_position(&mut self) -> Result<(u32, u32)> {
write!(self.output, "{}", Query::CursorPosition)?;
if let Response::CursorPosition(x, y) = self.response()? {
Ok((x, y))
} else {
Err(Error::new(ErrorKind::InvalidData, "invalid device response"))
}
}
pub fn reset(&mut self) -> Result<()> {
write!(self.output, "{}", Sequence::Reset)
}
pub fn line_wrap(&mut self, enable: bool) -> Result<()> {
write!(self.output, "{}", Sequence::LineWrap(enable))
}
pub fn font_default(&mut self) -> Result<()> {
write!(self.output, "{}", Sequence::FontDefault)
}
pub fn font_alternate(&mut self) -> Result<()> {
write!(self.output, "{}", Sequence::FontAlternate)
}
pub fn cursor_at(&mut self, row: u32, column: u32) -> Result<()> {
write!(self.output, "{}", Sequence::CursorAt(row, column))
}
pub fn cursor_move(&mut self, drow: i32, dcolumn: i32) -> Result<()> {
write!(self.output, "{}", Sequence::CursorMove(drow, dcolumn))
}
pub fn cursor_save(&mut self) -> Result<()> {
write!(self.output, "{}", Sequence::CursorSave)
}
pub fn cursor_restore(&mut self) -> Result<()> {
write!(self.output, "{}", Sequence::CursorRestore)
}
pub fn cursor_save_attributes(&mut self) -> Result<()> {
write!(self.output, "{}", Sequence::CursorSaveAttributes)
}
pub fn cursor_restore_attributes(&mut self) -> Result<()> {
write!(self.output, "{}", Sequence::CursorRestoreAttributes)
}
pub fn scroll_enable(&mut self, region: Option<(u32, u32)>) -> Result<()> {
write!(self.output, "{}", Sequence::ScrollEnable(region))
}
pub fn scroll(&mut self, rows: i32) -> Result<()> {
write!(self.output, "{}", Sequence::Scroll(rows))
}
pub fn erase_end_of_line(&mut self) -> Result<()> {
write!(self.output, "{}", Sequence::EraseEndOfLine)
}
pub fn erase_start_of_line(&mut self) -> Result<()> {
write!(self.output, "{}", Sequence::EraseStartOfLine)
}
pub fn erase_line(&mut self) -> Result<()> {
write!(self.output, "{}", Sequence::EraseLine)
}
pub fn erase_down(&mut self) -> Result<()> {
write!(self.output, "{}", Sequence::EraseDown)
}
pub fn erase_up(&mut self) -> Result<()> {
write!(self.output, "{}", Sequence::EraseUp)
}
pub fn erase_screen(&mut self) -> Result<()> {
write!(self.output, "{}", Sequence::EraseScreen)
}
pub fn set_attributes(&mut self, attributes: &[Attribute]) -> Result<()> {
write!(self.output, "{}", Sequence::SetAttributes(attributes))
}
}
fn expect_byte<I: Iterator<Item = u8>>(it: &mut Peekable<I>, expected: u8) -> Result<()> {
match it.next() {
Some(b) if b == expected => Ok(()),
_ => Err(Error::new(ErrorKind::InvalidData, "invalid device response"))
}
}
fn read_u32<I: Iterator<Item = u8>>(it: &mut Peekable<I>) -> Result<u32> {
let mut empty = true;
let mut value = 0u32;
loop {
match it.peek() {
Some(b) => {
if *b >= 0x30 && *b <= 0x39 {
empty = false;
value = value * 10 + (*b - 0x30) as u32;
} else {
break
}
},
None => {
break
}
}
}
if empty {
Err(Error::new(ErrorKind::InvalidData, "invalid device response"))
} else {
Ok(value)
}
}
impl<I: Read, O: Write> Read for Device<I, O> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let len = std::cmp::min(self.buffer.len()-self.offset, buf.len());
if len > 0 {
for i in 0..len {
buf[i] = self.buffer[self.offset];
self.offset += 1;
}
if self.offset >= self.buffer.len() {
self.offset = 0;
self.buffer.clear();
}
}
Ok(self.input.read(&mut buf[len..])? + len)
}
}
impl<I: Read, O: Write> Write for Device<I, O> {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.output.write(buf)
}
fn flush(&mut self) -> Result<()> {
self.output.flush()
}
}