1 /// Creates a control sequence. 2 /// 3 /// This macro prepends provided sequence with the control sequence introducer `ESC [` (`\x1B[`). 4 /// 5 /// # Examples 6 /// 7 /// ``` 8 /// use anes::csi; 9 /// 10 /// assert_eq!(csi!("?1049h"), "\x1B[?1049h"); 11 /// ``` 12 #[macro_export] 13 macro_rules! csi { 14 ($($arg:expr),*) => { concat!("\x1B[", $($arg),*) }; 15 } 16 17 /// Creates an escape sequence. 18 /// 19 /// This macro prepends provided sequence with the `ESC` (`\x1B`) character. 20 /// 21 /// # Examples 22 /// 23 /// ``` 24 /// use anes::esc; 25 /// 26 /// assert_eq!(esc!("7"), "\x1B7"); 27 /// ``` 28 #[macro_export] 29 macro_rules! esc { 30 ($($arg:expr),*) => { concat!("\x1B", $($arg),*) }; 31 } 32 33 /// Creates a select graphic rendition sequence. 34 /// 35 /// This macro prepends provided sequence with the `ESC[` (`\x1B[`) character and appends `m` character. 36 /// 37 /// Also known as Set Graphics Rendition on Linux. 38 /// 39 /// # Examples 40 /// 41 /// ``` 42 /// use anes::sgr; 43 /// 44 /// assert_eq!(sgr!("0"), "\x1B[0m"); 45 /// ``` 46 #[macro_export] 47 macro_rules! sgr { 48 ($($arg:expr),*) => { concat!("\x1B[", $($arg),* , "m") }; 49 } 50 51 /// Creates an ANSI sequence. 52 /// 53 /// You can use this macro to create your own ANSI sequence. All `anes` sequences are 54 /// created with this macro. 55 /// 56 /// # Examples 57 /// 58 /// An unit struct: 59 /// 60 /// ``` 61 /// use anes::{esc, sequence}; 62 /// 63 /// sequence!( 64 /// /// Saves the cursor position. 65 /// struct SaveCursorPosition => esc!("7") 66 /// ); 67 /// 68 /// assert_eq!(&format!("{}", SaveCursorPosition), "\x1B7"); 69 /// ``` 70 /// 71 /// An enum: 72 /// 73 /// ``` 74 /// use anes::{csi, sequence}; 75 /// 76 /// sequence!( 77 /// /// Clears part of the buffer. 78 /// enum ClearBuffer { 79 /// /// Clears from the cursor position to end of the screen. 80 /// Below => csi!("J"), 81 /// /// Clears from the cursor position to beginning of the screen. 82 /// Above => csi!("1J"), 83 /// /// Clears the entire buffer. 84 /// All => csi!("2J"), 85 /// /// Clears the entire buffer and all saved lines in the scrollback buffer. 86 /// SavedLines => csi!("3J"), 87 /// } 88 /// ); 89 /// 90 /// assert_eq!(&format!("{}", ClearBuffer::Below), "\x1B[J"); 91 /// assert_eq!(&format!("{}", ClearBuffer::Above), "\x1B[1J"); 92 /// assert_eq!(&format!("{}", ClearBuffer::All), "\x1B[2J"); 93 /// assert_eq!(&format!("{}", ClearBuffer::SavedLines), "\x1B[3J"); 94 /// ``` 95 /// 96 /// A struct: 97 /// 98 /// ``` 99 /// use anes::{csi, sequence}; 100 /// 101 /// sequence!( 102 /// /// Moves the cursor to the given location (column, row). 103 /// /// 104 /// /// # Notes 105 /// /// 106 /// /// Top/left cell is represented as `1, 1`. 107 /// struct MoveCursorTo(u16, u16) => 108 /// |this, f| write!(f, csi!("{};{}H"), this.0, this.1) 109 /// ); 110 /// 111 /// assert_eq!(&format!("{}", MoveCursorTo(10, 5)), "\x1B[10;5H"); 112 /// ``` 113 #[macro_export] 114 macro_rules! sequence { 115 // Static unit struct 116 ( 117 $(#[$meta:meta])* 118 struct $name:ident => $value:expr 119 ) => { 120 $(#[$meta])* 121 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] 122 pub struct $name; 123 124 impl ::std::fmt::Display for $name { 125 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { 126 write!(f, $value) 127 } 128 } 129 }; 130 // Static enum 131 ( 132 $(#[$meta:meta])* 133 enum $name:ident { 134 $( 135 $(#[$variant_meta:meta])* 136 $variant:ident => $variant_value:expr 137 ),* 138 $(,)? 139 } 140 ) => { 141 $(#[$meta])* 142 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] 143 pub enum $name { 144 $( 145 $(#[$variant_meta])* 146 $variant, 147 )* 148 } 149 150 impl ::std::fmt::Display for $name { 151 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { 152 write!(f, "{}", match self { 153 $( 154 $name::$variant => $variant_value, 155 )* 156 }) 157 } 158 } 159 }; 160 // Dynamic struct 161 ( 162 $(#[$meta:meta])* 163 struct $type:ident( 164 $($fields:ty),* 165 $(,)? 166 ) 167 => 168 $write:expr 169 ) => { 170 $(#[$meta])* 171 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] 172 pub struct $type($(pub $fields),*); 173 174 impl ::std::fmt::Display for $type { 175 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { 176 let write: &dyn Fn(&Self, &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result = 177 &$write; 178 write(self, f) 179 } 180 } 181 }; 182 } 183 184 /// Queues ANSI escape sequence(s). 185 /// 186 /// What does queue mean exactly? All sequences are queued with the 187 /// `write!($dst, "{}", $sequence)` macro without calling the 188 /// [`flush`](https://doc.rust-lang.org/std/io/trait.Write.html#tymethod.flush) method. 189 /// 190 /// Check the [`execute!`](macro.execute.html) macro if you'd like execute them 191 /// immediately (call the `flush` method after all sequences were queued). 192 /// 193 /// # Examples 194 /// 195 /// ```no_run 196 /// use std::io::{Result, Write}; 197 /// 198 /// use anes::queue; 199 /// 200 /// fn main() -> Result<()> { 201 /// let mut stdout = std::io::stdout(); 202 /// queue!( 203 /// &mut stdout, 204 /// anes::SaveCursorPosition, 205 /// anes::MoveCursorTo(10, 10) 206 /// )?; 207 /// 208 /// queue!(&mut stdout, anes::RestoreCursorPosition,)?; 209 /// 210 /// // ANSI sequences are not executed until you flush it! 211 /// stdout.flush() 212 /// } 213 /// ``` 214 #[macro_export] 215 macro_rules! queue { 216 ($dst:expr, $($sequence:expr),* $(,)?) => {{ 217 let mut error = None; 218 219 $( 220 if let Err(e) = write!($dst, "{}", $sequence) { 221 error = Some(e); 222 } 223 )* 224 225 if let Some(error) = error { 226 Err(error) 227 } else { 228 Ok(()) 229 } 230 }} 231 } 232 233 /// Executes ANSI escape sequence(s). 234 /// 235 /// What does execute mean exactly? All sequences are queued with the 236 /// `write!($dst, "{}", $sequence)` macro and then the 237 /// [`flush`](https://doc.rust-lang.org/std/io/trait.Write.html#tymethod.flush) method 238 /// is called. 239 /// 240 /// Check the [`queue!`](macro.queue.html) macro if you'd like queue sequences 241 /// and execute them later. 242 /// 243 /// ```no_run 244 /// use std::io::{Result, Write}; 245 /// 246 /// use anes::execute; 247 /// 248 /// fn main() -> Result<()> { 249 /// let mut stdout = std::io::stdout(); 250 /// execute!( 251 /// &mut stdout, 252 /// anes::SaveCursorPosition, 253 /// anes::MoveCursorTo(10, 10), 254 /// anes::RestoreCursorPosition 255 /// )?; 256 /// Ok(()) 257 /// } 258 /// ``` 259 #[macro_export] 260 macro_rules! execute { 261 ($dst:expr, $($sequence:expr),* $(,)?) => {{ 262 if let Err(e) = $crate::queue!($dst, $($sequence),*) { 263 Err(e) 264 } else { 265 $dst.flush() 266 } 267 }} 268 } 269 270 #[cfg(test)] 271 macro_rules! test_sequences { 272 ( 273 $( 274 $name:ident( 275 $($left:expr => $right:expr),* 276 $(,)? 277 ) 278 ),* 279 $(,)? 280 ) => { 281 #[cfg(test)] 282 mod tests { 283 use super::*; 284 285 $( 286 #[test] 287 fn $name() { 288 $( 289 assert_eq!(&format!("{}", $left), $right); 290 )* 291 } 292 )* 293 } 294 } 295 } 296 297 #[cfg(test)] 298 mod tests { 299 use std::io::{Error, ErrorKind, Write}; 300 301 #[test] csi()302 fn csi() { 303 assert_eq!(csi!("foo"), "\x1B[foo"); 304 } 305 306 #[test] esc()307 fn esc() { 308 assert_eq!(esc!("bar"), "\x1Bbar"); 309 } 310 311 #[test] sgr()312 fn sgr() { 313 assert_eq!(sgr!("bar"), "\x1B[barm"); 314 } 315 316 #[test] static_struct_sequence()317 fn static_struct_sequence() { 318 sequence!( 319 struct TestSeq => csi!("foo") 320 ); 321 322 assert_eq!(&format!("{}", TestSeq), "\x1B[foo"); 323 } 324 325 #[test] static_enum_sequence()326 fn static_enum_sequence() { 327 sequence!( 328 enum TestSeq { 329 Foo => csi!("foo"), 330 Bar => esc!("bar"), 331 } 332 ); 333 334 assert_eq!(&format!("{}", TestSeq::Foo), "\x1B[foo"); 335 assert_eq!(&format!("{}", TestSeq::Bar), "\x1Bbar"); 336 } 337 338 #[test] dynamic_struct_sequence()339 fn dynamic_struct_sequence() { 340 sequence!( 341 struct TestSeq(u16) => 342 |this, f| write!(f, csi!("foo{}bar"), this.0) 343 ); 344 345 assert_eq!(&format!("{}", TestSeq(10)), "\x1B[foo10bar"); 346 } 347 348 #[test] queue_allows_trailing_comma()349 fn queue_allows_trailing_comma() { 350 let mut writer = Writer::default(); 351 352 assert!(queue!(&mut writer, "foo",).is_ok()); 353 assert_eq!(&writer.buffer, "foo"); 354 } 355 356 #[test] queue_writes_single_sequence()357 fn queue_writes_single_sequence() { 358 let mut writer = Writer::default(); 359 360 assert!(queue!(&mut writer, "foo").is_ok()); 361 assert_eq!(&writer.buffer, "foo"); 362 } 363 364 #[test] queue_writes_multiple_sequences()365 fn queue_writes_multiple_sequences() { 366 let mut writer = Writer::default(); 367 368 assert!(queue!(&mut writer, "foo", "bar", "baz").is_ok()); 369 assert_eq!(&writer.buffer, "foobarbaz"); 370 } 371 372 #[test] queue_does_not_flush()373 fn queue_does_not_flush() { 374 let mut writer = Writer::default(); 375 376 assert!(queue!(&mut writer, "foo").is_ok()); 377 assert!(!writer.flushed); 378 assert!(writer.flushed_buffer.is_empty()); 379 } 380 381 #[test] execute_allows_trailing_comma()382 fn execute_allows_trailing_comma() { 383 let mut writer = Writer::default(); 384 385 assert!(execute!(&mut writer, "foo",).is_ok()); 386 assert_eq!(&writer.flushed_buffer, "foo"); 387 } 388 389 #[test] execute_writes_single_sequence()390 fn execute_writes_single_sequence() { 391 let mut writer = Writer::default(); 392 393 assert!(execute!(&mut writer, "foo").is_ok()); 394 assert_eq!(&writer.flushed_buffer, "foo"); 395 } 396 397 #[test] execute_writes_multiple_sequences()398 fn execute_writes_multiple_sequences() { 399 let mut writer = Writer::default(); 400 401 assert!(execute!(&mut writer, "foo", "bar", "baz").is_ok()); 402 assert_eq!(&writer.flushed_buffer, "foobarbaz"); 403 } 404 405 #[test] execute_does_flush()406 fn execute_does_flush() { 407 let mut writer = Writer::default(); 408 409 assert!(execute!(&mut writer, "foo").is_ok()); 410 assert!(writer.flushed); 411 assert_eq!(&writer.flushed_buffer, "foo"); 412 assert!(writer.buffer.is_empty()); 413 } 414 415 #[derive(Default)] 416 struct Writer { 417 buffer: String, 418 flushed_buffer: String, 419 flushed: bool, 420 } 421 422 impl Write for Writer { write(&mut self, buf: &[u8]) -> Result<usize, Error>423 fn write(&mut self, buf: &[u8]) -> Result<usize, Error> { 424 let s = std::str::from_utf8(buf).map_err(|_| ErrorKind::InvalidData)?; 425 426 self.buffer.push_str(s); 427 Ok(s.len()) 428 } 429 flush(&mut self) -> Result<(), Error>430 fn flush(&mut self) -> Result<(), Error> { 431 self.flushed_buffer = self.buffer.clone(); 432 self.buffer = String::new(); 433 self.flushed = true; 434 Ok(()) 435 } 436 } 437 } 438