esc_seq/
esc_seq.rs

1use std::io::{ Stdout, Write };
2
3const CSI: [u8; 2] = [0x1b, '[' as u8];
4
5#[allow(dead_code)]
6#[derive(Copy, Clone)]
7enum ClearRegion {
8	AfterCursor = 0,
9	BeforeCursor = 1,
10	All = 2,
11}
12
13#[allow(dead_code)]
14enum ClearTarget {
15	Screen,
16	Line,
17}
18
19#[allow(dead_code)]
20enum Dir {
21	Up,
22	Down,
23	Right,
24	Left,
25}
26
27#[allow(dead_code)]
28enum CsiCommand {
29	Move(Dir),
30	ToRowBeg(Dir, u8),
31	InCurrLineMoveTo(u8),
32	MoveTo { y: u8, x: u8, },
33	Clear { target: ClearTarget, region: ClearRegion },
34	ApplySgrs(Vec<SGR>),
35	ShowCursor,
36	HideCursor,
37}
38
39impl CsiCommand {
40	fn to_seq(&self) -> Option<String> {
41		match self {
42			CsiCommand::Move(Dir::Up) => Some("A".to_string()),
43			CsiCommand::Move(Dir::Down) => Some("B".to_string()),
44			CsiCommand::Move(Dir::Right) => Some("C".to_string()),
45			CsiCommand::Move(Dir::Left) => Some("D".to_string()),
46			CsiCommand::ToRowBeg(Dir::Down, n) => Some(format!("{}E", n)),
47			CsiCommand::ToRowBeg(Dir::Up, n) => Some(format!("{}F", n)),
48			CsiCommand::ToRowBeg(_, _) => None,
49			CsiCommand::InCurrLineMoveTo(n) => Some(format!("{}G", n)),
50			CsiCommand::MoveTo { y, x } if *x >=1 && *y >= 1 => Some(format!("{};{}H", y, x)),
51			CsiCommand::MoveTo { y: _, x: _ } => None,
52			CsiCommand::Clear { target, region } => {
53				let target_str = match target {
54					ClearTarget::Screen => "J",
55					ClearTarget::Line => "K",
56				};
57				Some(format!("{}{}", *region as u8, target_str))
58			},
59			CsiCommand::ApplySgrs(sgrs) => {
60				let x = sgrs.into_iter().map(|x| x.to_code()).collect::<Vec<_>>().join(";");
61				Some(x + "m")
62			},
63			CsiCommand::ShowCursor => Some("?25h".to_string()),
64			CsiCommand::HideCursor => Some("?25l".to_string()),
65		}
66	}
67}
68
69#[allow(dead_code)]
70#[derive(Copy, Clone)]
71pub enum Color {
72	Black,
73	Red,
74	Green,
75	Yellow,
76	Blue,
77	Magenta,
78	Cyan,
79	White,
80}
81
82#[allow(dead_code)]
83pub enum SGR {
84	Reset,
85	Bold,
86	Thin,
87	Italic,
88	Underline,
89	Blink,
90	BlinkFaster,
91	Reverse,
92	Hide,
93	StrikeOut,
94	DefaultFg,
95	DefaultBg,
96	Fg(Color),
97	Bg(Color),
98	BrighterFg(Color),
99	BrighterBg(Color),
100}
101
102impl SGR {
103	fn to_code(&self) -> String {
104		let n: u8 = match self {
105			SGR::Reset => 0,
106			SGR::Bold => 1,
107			SGR::Thin => 2,
108			SGR::Italic => 3,
109			SGR::Underline => 4,
110			SGR::Blink => 5,
111			SGR::BlinkFaster => 6,
112			SGR::Reverse => 7,
113			SGR::Hide => 8,
114			SGR::StrikeOut => 9,
115			SGR::DefaultFg => 39,
116			SGR::DefaultBg => 49,
117			SGR::Fg(x) => 30 + *x as u8,
118			SGR::Bg(x) => 40 + *x as u8,
119			SGR::BrighterFg(x) => 90 + *x as u8,
120			SGR::BrighterBg(x) => 100 + *x as u8,
121		};
122		n.to_string()
123	}
124}
125
126pub struct EscSeq {
127	pub stdout: Stdout,
128}
129
130impl EscSeq {
131	pub fn new() -> EscSeq {
132		EscSeq { stdout: std::io::stdout() }
133	}
134
135	fn write(&mut self, cmd: CsiCommand) {
136		if let Some(x) = cmd.to_seq() {
137			self.stdout.write(&CSI).unwrap();
138			self.stdout.write(x.as_bytes()).unwrap();
139		}
140	}
141
142	pub fn next_line(&mut self) {
143		self.write(CsiCommand::ToRowBeg(Dir::Down, 1));
144	}
145
146	#[allow(dead_code)]
147	pub fn to_line_beg(&mut self) {
148		self.write(CsiCommand::InCurrLineMoveTo(1));
149	}
150
151	pub fn clear_screen(&mut self) {
152		self.write(CsiCommand::Clear { target: ClearTarget::Screen, region: ClearRegion::All });
153	}
154
155	pub fn clear_line(&mut self) {
156		self.write(CsiCommand::Clear { target: ClearTarget::Line, region: ClearRegion::All });
157	}
158
159	pub fn move_to(&mut self, y: u8, x: u8) {
160		self.write(CsiCommand::MoveTo { y, x });
161	}
162
163	pub fn flush(&mut self) {
164		self.stdout.flush().unwrap();
165	}
166
167	pub fn set(&mut self, sgrs: Vec<SGR>) {
168		self.write(CsiCommand::ApplySgrs(sgrs));
169	}
170
171	#[allow(dead_code)]
172	pub fn hide_cursor(&mut self) {
173		self.write(CsiCommand::HideCursor);
174	}
175
176	#[allow(dead_code)]
177	pub fn show_cursor(&mut self) {
178		self.write(CsiCommand::ShowCursor);
179	}
180}