x1b 0.2.0

State tracker for 0x1b terminal escape codes. Also gives random characters names.
Documentation
use std::io::{self, Write};
bitflags! {
	flags TextAttr: u8 {
		const TA_BOLD = 1,
		const TA_LOW = 2,
		const TA_UNDER = 4,
		const TA_BLINK = 8,
		const TA_REV = 16,
		const TA_INVIS = 32,
	}
}
impl TextAttr {
	pub fn clear(&mut self) -> bool {
		let ret = self.bits != 0;
		self.bits = 0;
		ret
	}
}
pub struct Cursor {
	pub buf: String,
	pub attr: TextAttr,
	pub x: u16,
	pub y: u16,
}

impl Default for Cursor {
	fn default() -> Self{
		Cursor {
			buf: String::new(),
			attr: TextAttr::empty(),
			x: 1,
			y: 1,
		}
	}
}

impl Cursor {
	pub fn esc(&mut self, s: &str){
		self.buf.push('\x1b');
		self.buf.push('[');
		self.buf.push_str(s)
	}
	pub fn escch(&mut self, c: char){
		self.buf.push('\x1b');
		self.buf.push('[');
		self.buf.push(c)
	}
	pub fn clearattr(&mut self){
		self.attr.clear();
		self.escch('m')
	}
	pub fn hasallattr(&self, ta: TextAttr) -> bool{
		self.attr.contains(ta)
	}
	pub fn hasanyattr(&self, ta: TextAttr) -> bool{
		self.attr.intersects(ta)
	}
	pub fn setattr(&mut self, ta: TextAttr){
		if ta == self.attr { return }
		let mapping = [
			(TA_BOLD, '1'),
			(TA_LOW, '2'),
			(TA_UNDER, '4'),
			(TA_BLINK, '5'),
			(TA_REV, '7'),
			(TA_INVIS, '8')];
		self.buf.push('\x1b');
		self.buf.push('[');
		if ta.contains(self.attr) {
			for &(attr, code) in mapping.iter() {
				if ta.contains(attr) && !self.attr.contains(attr) {
					self.buf.push(code);
					self.buf.push(';')
				}
			}
		} else {
			self.escch('m');
			for &(attr, code) in mapping.iter() {
				if ta.contains(attr) {
					self.buf.push(code);
					self.buf.push(';')
				}
			}

		}
		unsafe { *(self.buf.as_mut_vec().last_mut().unwrap()) = 109 }
		self.attr = ta;
	}
	pub fn setbold(&mut self){
		self.attr.insert(TA_BOLD);
		self.esc("1m")
	}
	pub fn setlow(&mut self){
		self.attr.insert(TA_LOW);
		self.esc("2m")
	}
	pub fn setunder(&mut self){
		self.attr.insert(TA_UNDER);
		self.esc("4m")
	}
	pub fn setblink(&mut self){
		self.attr.insert(TA_BLINK);
		self.esc("5m")
	}
	pub fn setrev(&mut self){
		self.attr.insert(TA_REV);
		self.esc("7m")
	}
	pub fn setinvis(&mut self){
		self.attr.insert(TA_INVIS);
		self.esc("8m")
	}
	pub fn unsetbold(&mut self){
		self.attr.remove(TA_BOLD);
		self.esc("21m")
	}
	pub fn unsetrev(&mut self){
		self.attr.remove(TA_REV);
		self.esc("27m")
	}
	pub fn wrapon(&mut self){
		self.buf.push_str("\x1b7h")
	}
	pub fn wrapoff(&mut self){
		self.buf.push_str("\x1b7l")
	}
	pub fn up1(&mut self){
		self.y -= 1;
		self.escch('A')
	}
	pub fn down1(&mut self){
		self.y += 1;
		self.escch('B')
	}
	pub fn right1(&mut self){
		self.x -= 1;
		self.escch('C')
	}
	pub fn left1(&mut self){
		self.x += 1;
		self.escch('D')
	}
	pub fn up(&mut self, n: u16){
		self.y -= n;
		self.esc(&format!("{}A", n))
	}
	pub fn down(&mut self, n: u16){
		self.y += n;
		self.esc(&format!("{}B", n))
	}
	pub fn right(&mut self, n: u16){
		self.x -= n;
		self.esc(&format!("{}C", n))
	}
	pub fn left(&mut self, n: u16){
		self.x += n;
		self.esc(&format!("{}D", n))
	}
	pub fn x1down(&mut self, n: u16){
		self.x = 1;
		self.y += n;
		self.esc(&format!("{}E", n))
	}
	pub fn x1up(&mut self, n: u16){
		self.x = 1;
		self.y -= n;
		self.esc(&format!("{}F", n))
	}
	pub fn setx(&mut self, x: u16){
		self.x = x;
		self.esc(&format!("{}G", x))
	}
	pub fn sety(&mut self, y: u16){
		self.y = y;
		self.esc(&format!("{}d", y))
	}
	pub fn resetxy(&mut self){
		self.x = 1;
		self.y = 1;
		self.escch('H')
	}
	pub fn mv(&mut self, x: u16, y: u16){
		self.x = x;
		self.y = y;
		self.esc(&format!("{};{}H",y,x))
	}
	pub fn erasebelow(&mut self){
		self.escch('J')
	}
	pub fn eraseabove(&mut self){
		self.esc("1J")
	}
	pub fn eraseall(&mut self){
		self.esc("2J")
	}
	pub fn eraseleft(&mut self){
		self.escch('K')
	}
	pub fn eraseright(&mut self){
		self.esc("1K")
	}
	pub fn eraseline(&mut self){
		self.esc("2K")
	}
	pub fn delln(&mut self){
		self.escch('M')
	}
	pub fn dellns(&mut self, n: u16){
		self.esc(&format!("{}M", n))
	}
	pub fn delch(&mut self){
		self.escch('S')
	}
	pub fn delchs(&mut self, n: u16){
		self.esc(&format!("{}S", n))
	}
	pub fn getattr(&self) -> TextAttr{
		self.attr
	}
	pub fn showcur(&mut self){
		self.esc("?23h")
	}
	pub fn hidecur(&mut self){
		self.esc("?25l")
	}
	pub fn spame(&mut self){
		self.buf.push_str("\x1b#8")
	}
	pub fn getxy(&self) -> (u16, u16){
		(self.x, self.y)
	}
	pub fn rgbbg(&mut self, rgb: (u8, u8, u8), bg: u8){
		self.esc(&format!("{};2;{};{};{}m", bg, rgb.0, rgb.1, rgb.2))
	}
	pub fn rgb(&mut self, rgb: (u8, u8, u8)){
		self.rgbbg(rgb, 38)
	}
	pub fn prchr(&mut self, c: char){
		self.x += 1;
		self.buf.push(c)
	}
	pub fn print(&mut self, s: &str){
		let mut rsp = s.rsplit('\n');
		let last = rsp.next().unwrap();
		let lines = rsp.count();
		self.x += last.len() as u16;
		self.y += lines as u16;
		self.buf.push_str(s)
	}
	pub fn clear(&mut self) -> io::Result<()> {
		self.buf.clear();
		self.x = 1;
		self.y = 1;
		Cursor::dropclear()
	}
	pub fn dropclear() -> io::Result<()> {
		io::stdout().write_all(b"\x1bc")
	}
	pub fn flush(&mut self) -> io::Result<()> {
		let mut out = io::stdout();
		try!(out.write_all(self.buf.as_bytes()));
		try!(out.flush());
		Ok(self.buf.clear())
	}
}