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