use std::io::{Write, Result as IoResult}; use {Color, Style}; /// Extension to the `Write` trait. /// /// This extension to the `Write` trait is capable of producing the correct ANSI escape sequences /// for given commands, effectively controlling the terminal. pub trait TermWrite { /// Print the CSI (control sequence introducer) followed by a byte string. fn csi(&mut self, b: &[u8]) -> IoResult; /// Print OSC (operating system command) followed by a byte string. fn osc(&mut self, b: &[u8]) -> IoResult; /// Print OSC (device control string) followed by a byte string. fn dsc(&mut self, b: &[u8]) -> IoResult; /// Clear the entire screen. fn clear(&mut self) -> IoResult { self.csi(b"2J") } /// Clear everything _after_ the cursor. fn clear_after(&mut self) -> IoResult { self.csi(b"J") } /// Clear everything _before_ the cursor. fn clear_before(&mut self) -> IoResult { self.csi(b"1J") } /// Clear the current line. fn clear_line(&mut self) -> IoResult { self.csi(b"2K") } /// Clear from the cursor until newline. fn clear_until_newline(&mut self) -> IoResult { self.csi(b"K") } /// Show the cursor. fn show_cursor(&mut self) -> IoResult { self.csi(b"?25h") } /// Hide the cursor. fn hide_cursor(&mut self) -> IoResult { self.csi(b"?25l") } /// Reset the rendition mode. /// /// This will reset both the current style and color. fn reset(&mut self) -> IoResult { self.csi(b"m") } /// Restore the defaults. /// /// This will reset color, position, cursor state, and so on. It is recommended that you use /// this before you exit your program, to avoid messing up the user's terminal. fn restore(&mut self) -> IoResult { Ok(try!(self.reset()) + try!(self.clear()) + try!(self.goto(0, 0)) + try!(self.show_cursor())) } /// Go to a given position. /// /// The position is 0-based. fn goto(&mut self, mut x: u16, mut y: u16) -> IoResult { x += 1; y += 1; self.csi(&[ b'0' + (y / 10000) as u8, b'0' + (y / 1000) as u8 % 10, b'0' + (y / 100) as u8 % 10, b'0' + (y / 10) as u8 % 10, b'0' + y as u8 % 10, b';', b'0' + (x / 10000) as u8, b'0' + (x / 1000) as u8 % 10, b'0' + (x / 100) as u8 % 10, b'0' + (x / 10) as u8 % 10, b'0' + x as u8 % 10, b'H', ]) } /// Set graphic rendition. fn rendition(&mut self, r: u8) -> IoResult { self.csi(&[ b'0' + r / 100, b'0' + r / 10 % 10, b'0' + r % 10, b'm', ]) } /// Set foreground color fn color(&mut self, color: Color) -> IoResult { let ansi = color.to_ansi_val(); self.csi(&[ b'3', b'8', b';', b'5', b';', b'0' + ansi / 100, b'0' + ansi / 10 % 10, b'0' + ansi % 10, b'm', ]) } /// Set background color fn bg_color(&mut self, color: Color) -> IoResult { let ansi = color.to_ansi_val(); self.csi(&[ b'4', b'8', b';', b'5', b';', b'0' + ansi / 100, b'0' + ansi / 10 % 10, b'0' + ansi % 10, b'm', ]) } /// Set rendition mode (SGR). fn style(&mut self, mode: Style) -> IoResult { self.rendition(mode as u8) } } impl TermWrite for W { fn csi(&mut self, b: &[u8]) -> IoResult { Ok(try!(self.write(b"\x1B[")) + try!(self.write(b))) } fn osc(&mut self, b: &[u8]) -> IoResult { Ok(try!(self.write(b"\x1B]")) + try!(self.write(b))) } fn dsc(&mut self, b: &[u8]) -> IoResult { Ok(try!(self.write(b"\x1BP")) + try!(self.write(b))) } }