esc-seq 0.1.2

Library to print simple escape sequences
Documentation
use std::io::{ Stdout, Write };

const CSI: [u8; 2] = [0x1b, '[' as u8];

#[allow(dead_code)]
#[derive(Copy, Clone)]
enum ClearRegion {
	AfterCursor = 0,
	BeforeCursor = 1,
	All = 2,
}

#[allow(dead_code)]
enum ClearTarget {
	Screen,
	Line,
}

#[allow(dead_code)]
enum Dir {
	Up,
	Down,
	Right,
	Left,
}

#[allow(dead_code)]
enum CsiCommand {
	Move(Dir),
	ToRowBeg(Dir, u8),
	InCurrLineMoveTo(u8),
	MoveTo { y: u8, x: u8, },
	Clear { target: ClearTarget, region: ClearRegion },
	ApplySgrs(Vec<SGR>),
	ShowCursor,
	HideCursor,
}

impl CsiCommand {
	fn to_seq(&self) -> Option<String> {
		match self {
			CsiCommand::Move(Dir::Up) => Some("A".to_string()),
			CsiCommand::Move(Dir::Down) => Some("B".to_string()),
			CsiCommand::Move(Dir::Right) => Some("C".to_string()),
			CsiCommand::Move(Dir::Left) => Some("D".to_string()),
			CsiCommand::ToRowBeg(Dir::Down, n) => Some(format!("{}E", n)),
			CsiCommand::ToRowBeg(Dir::Up, n) => Some(format!("{}F", n)),
			CsiCommand::ToRowBeg(_, _) => None,
			CsiCommand::InCurrLineMoveTo(n) => Some(format!("{}G", n)),
			CsiCommand::MoveTo { y, x } if *x >=1 && *y >= 1 => Some(format!("{};{}H", y, x)),
			CsiCommand::MoveTo { y: _, x: _ } => None,
			CsiCommand::Clear { target, region } => {
				let target_str = match target {
					ClearTarget::Screen => "J",
					ClearTarget::Line => "K",
				};
				Some(format!("{}{}", *region as u8, target_str))
			},
			CsiCommand::ApplySgrs(sgrs) => {
				let x = sgrs.into_iter().map(|x| x.to_code()).collect::<Vec<_>>().join(";");
				Some(x + "m")
			},
			CsiCommand::ShowCursor => Some("?25h".to_string()),
			CsiCommand::HideCursor => Some("?25l".to_string()),
		}
	}
}

#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum Color {
	Black,
	Red,
	Green,
	Yellow,
	Blue,
	Magenta,
	Cyan,
	White,
}

#[allow(dead_code)]
pub enum SGR {
	Reset,
	Bold,
	Thin,
	Italic,
	Underline,
	Blink,
	BlinkFaster,
	Reverse,
	Hide,
	StrikeOut,
	DefaultFg,
	DefaultBg,
	Fg(Color),
	Bg(Color),
	BrighterFg(Color),
	BrighterBg(Color),
}

impl SGR {
	fn to_code(&self) -> String {
		let n: u8 = match self {
			SGR::Reset => 0,
			SGR::Bold => 1,
			SGR::Thin => 2,
			SGR::Italic => 3,
			SGR::Underline => 4,
			SGR::Blink => 5,
			SGR::BlinkFaster => 6,
			SGR::Reverse => 7,
			SGR::Hide => 8,
			SGR::StrikeOut => 9,
			SGR::DefaultFg => 39,
			SGR::DefaultBg => 49,
			SGR::Fg(x) => 30 + *x as u8,
			SGR::Bg(x) => 40 + *x as u8,
			SGR::BrighterFg(x) => 90 + *x as u8,
			SGR::BrighterBg(x) => 100 + *x as u8,
		};
		n.to_string()
	}
}

pub struct EscSeq {
	pub stdout: Stdout,
}

impl EscSeq {
	pub fn new() -> EscSeq {
		EscSeq { stdout: std::io::stdout() }
	}

	fn write(&mut self, cmd: CsiCommand) {
		if let Some(x) = cmd.to_seq() {
			self.stdout.write(&CSI).unwrap();
			self.stdout.write(x.as_bytes()).unwrap();
		}
	}

	pub fn next_line(&mut self) {
		self.write(CsiCommand::ToRowBeg(Dir::Down, 1));
	}

	#[allow(dead_code)]
	pub fn to_line_beg(&mut self) {
		self.write(CsiCommand::InCurrLineMoveTo(1));
	}

	pub fn clear_screen(&mut self) {
		self.write(CsiCommand::Clear { target: ClearTarget::Screen, region: ClearRegion::All });
	}

	pub fn clear_line(&mut self) {
		self.write(CsiCommand::Clear { target: ClearTarget::Line, region: ClearRegion::All });
	}

	pub fn move_to(&mut self, y: u8, x: u8) {
		self.write(CsiCommand::MoveTo { y, x });
	}

	pub fn flush(&mut self) {
		self.stdout.flush().unwrap();
	}

	pub fn set(&mut self, sgrs: Vec<SGR>) {
		self.write(CsiCommand::ApplySgrs(sgrs));
	}

	#[allow(dead_code)]
	pub fn hide_cursor(&mut self) {
		self.write(CsiCommand::HideCursor);
	}

	#[allow(dead_code)]
	pub fn show_cursor(&mut self) {
		self.write(CsiCommand::ShowCursor);
	}
}