termal/lib.rs
1//! Library for working with ansi codes to create beutiful terminal outputs.
2//!
3//! The main focus of this library are the macros [`formatc`], [`printc`],
4//! [`printcln`], [`eprintc`], [`eprintcln`], [`writecln`] adn [`writecln`].
5//! They can be used in the same way as you would use the standard rust macros
6//! [`format`], [`print`], [`println`], [`eprint`], [`eprintln`], [`write`] and
7//! [`writeln`]. In addition the macros in this crate have special syntax for
8//! encoding terminal commands.
9//!
10//! ## The macros
11//! For all these macros the following applies:
12//!
13//! If content braces `{}` starts with `'` (e.g. `"{'command}hello"`) than the
14//! content is interpreted by this crate, otherwised it is interpreted by the
15//! [`format`] macro.
16//!
17//! The content can contain one or more commands that will expand directly to a
18//! string literal.
19//!
20//! For most of the color commands the folowing is true:
21//! - The commands have short aliases (e.g. `w` is alias for `white`)
22//! - Some of the commands can be reset, the resetting command has the same
23//! name but it is prepended with `_` (e.g. use `italic` to set font style to
24//! italic and than use `_italic` to unset the italic font style)
25//! - Some commands take arguments and some of the arguments are optional. The
26//! arguments are passed to the command by typing them directly after the
27//! command and separate them by `,` (e.g. `move_to0,0` moves the cursor to
28//! 0, 0. This is also the default value so you can just use `move_to,`).
29//!
30//! ### RGB color commands
31//! The colors can be set either by the [color commands](#color-commands) or
32//! by hex color:
33//!
34//! The hex color starts with `#` and can contain either 1, 2, 3 or 6 hex
35//! digits. They are interpreted as follows:
36//! - **6 digits:** normal 6 digit RGB color (e.g `#FF0000` is pure red)
37//! - **3 digits:** 3 digit RGB color, each digit is repeated twice (e.g.
38//! `#ABC` has the same result as `#AABBCC`)
39//! - **2 digits:** the two digits are repeated 3 times to form one of 256
40//! shades of gray (e.g. `#AB` has the same result as `#ABABAB`)
41//! - **1 digit:** the digit is repeated 6 times to form one of 16 shades of
42//! gray (e.g. `#A` has the same result as `#AAAAAA`)
43//!
44//! If you want to set the foregorund color, you just type the hex (e.g.
45//! `#FF0000` will set the foreground color to pure red). In order to set the
46//! background color, you can append `_` to the color (e.g. `#FF0000_` will set
47//! the background color to pure red).
48//!
49//! If you want to set the underline color, just type the same as background
50//! color, but use `u` instead of the `_`.
51//!
52//! ### Ascii commands
53//! - `bell`: console bell (create sound)
54//! - `backspace`: move left by one
55//! - `htab`, `tab`: horizontal tabulator
56//! - `move_down_scrl`, `mds`: move down by one line scrolling if needed
57//! - `newline`, `nl`: move to the start of the next line
58//! - `vtab`: vertical tabulator
59//! - `carriage_return` | `cr`: move to the start of the current line
60//!
61//! ### Commands for moving the cursor
62//! - `move_to`, `mt`: moves the cursor to the given position, has two
63//! arguments, default values are `0`.
64//! - `move_up`, `mu`: moves the cursor up by the given amount, has one
65//! argument, default value is `1`
66//! - `move_down`, `md`: moves the cursor down by the given amount, has one
67//! argument, default value is `1`
68//! - `move_right`, `mr`: moves the cursor right by the given amount, has one
69//! argument, default value is `1`
70//! - `move_left`, `ml`: moves the cursor left by the given amount, has one
71//! argument, default value is `1`
72//! - `set_down`, `sd`: moves the cursor to the start of line n lines down, has
73//! one argument, default value is `1`
74//! - `set_up`, `su`: moves the cursor to the start of line n lines up, has one
75//! argument, default value is `1`
76//! - `move_to_column`, `mc`: moves the cursor to the given x coordinate, has
77//! one argument, default value is `0`
78//! + `move_up_scrl`, `mus`: moves the cursor up by one line, scrolling if
79//! needed
80//! + `save_cur`, `save`, `s`: saves the current cursor position (single slot,
81//! not stack)
82//! + `load_cur`, `load`, `l`: loads the last saved cursor position
83//!
84//! ### Erase commands
85//! - `erase_to_end`, `e_`: erases from the cursor to the end of the screen
86//! - `erase_from_start`, `_e`: erases from the start of the screen to the cursor
87//! - `erase_screen`, `_e_`: erases the whole screen
88//! - `erase_all`, `e`: erases the whole screen and the scroll buffer
89//! - `erase_ln_end`, `el_`: erases from the cursor to the end of the line
90//! - `erase_ln_start`, `_el`: erases from the start of the line to the cursor
91//! - `erase_line`, `erase_ln`, `_el_`, `el`: erases the current line
92//!
93//! ### Font style and color command
94//! + `reset`, `_`: resets all colors and styles
95//!
96//! ### Font style commands
97//! - `bold`: sets style to bold
98//! - `faint`, `f`: sets style to faint
99//! - `italic`, `i`: sets style to italic
100//! - `underline`, `u`: sets style to underline
101//! - `blinking`, `blink`: sets style to blinking
102//! - `inverse`: sets style to inverse (swap background and foreground)
103//! - `invisible`, `invis`: sets the style to invisible (foreground and
104//! background are same)
105//! - `striketrough`, `strike`: sets the style to striketrough
106//! - `double_underline`, `dunderline`, `dun`: sets the style to double
107//! underline
108//! - `overline`, `ol`: sets the style to overline
109//! + `_bold`: resets bold and faint
110//! + `_italic`, `_i`: resets italic
111//! + `_underline`, `_u`: resets underline and double underline
112//! + `_blinking`, `_blink`: resets blinking
113//! + `_inverse`: resets inverse
114//! + `_invisible`, `_invis`: resets invisible
115//! + `_striketrough`, `_strike`: resets striketrough
116//! + `_overline`, `_ol`: resets overline
117//!
118//! ### Color commands
119//! - `black_fg`, `black`, `bl`: sets the foreground to black
120//! - `white_fg`, `white`, `w`: sets the foreground to white
121//! - `gray_fg`, `gray`, `gr`: sets the foreground to green
122//! - `bright_gray_fg`, `bgray`, `bgr`: sets the foreground to bright gray
123//! + `red_fg`, `red`, `r`: sets the foreground to red
124//! + `green_fg`, `green`, `g`: sets the foreground to green
125//! + `yellow_fg`, `yellow`, `y`: sets the foreground to yellow
126//! + `magenta_fg`, `magenta`, `m`: sets the foreground to magenta
127//! + `cyan_fg`, `cyan`, `c`: sets the foreground to cyan
128//! - `dark_red_fg`, `dred`, `dr`: sets the foreground to dark red
129//! - `dark_green_fg`, `dgreen`, `dg`: sets the foreground to dark green
130//! - `dark_yellow_fg`, `dyellow`, `dy`: sets the foreground to dark yellow
131//! - `dark_magenta_fg`, `dmagenta`, `dm`: sets the foreground to dark magenta
132//! - `dark_cyan_fg`, `dcyan`, `dc`: sets the foreground to dark cyan
133//! + `_fg`: resets the foreground color
134//! - `black_bg`, `blackb`, `blb`: sets the background to black
135//! - `white_bg`, `whiteb`, `wb`: sets the background to white
136//! - `gray_bg`, `grayb`, `grb`: sets the background to green
137//! - `bright_gray_bg`, `bgrayb`, `bgrb`: sets the background to bright gray
138//! + `red_bg`, `redb`, `rb`: sets the background to red
139//! + `green_bg`, `greenb`, `gb`: sets the background to green
140//! + `yellow_bg`, `yellowb`, `yb`: sets the background to yellow
141//! + `magenta_bg`, `magentab`, `mb`: sets the background to magenta
142//! + `cyan_bg`, `cyanb`, `cb`: sets the background to cyan
143//! - `dark_red_bg`, `dredb`, `drb`: sets the background to dark red
144//! - `dark_green_bg`, `dgreenb`, `dgb`: sets the background to dark green
145//! - `dark_yellow_bg`, `dyellowb`, `dyb`: sets the background to dark yellow
146//! - `dark_magenta_bg`, `dmagentab`, `dmb`: sets the background to dark
147//! magenta
148//! - `dark_cyan_bg`, `dcyanb`, `dcb`: sets the background to dark cyan
149//! + `_bg`: resets the background
150//! + `_ucolor`, `_uc`: resets the underline color
151//! - `fg`: sets the foreground color to one of the 256 colors, has one
152//! argument
153//! - `bg`: sets the background color to one of the 256 colors, has one
154//! argument
155//! - `ucolor`, `uc`: sets the underline color to one of the 256 colors, has
156//! one argument.
157//!
158//! ### Other
159//! - `line_wrap`, `wrap`: enable line wrapping
160//! - `_line_wrap`, `_wrap`: disable line wrapping
161//! + `hide_cursor`, `nocur`: hide the cursor
162//! + `show_cursor`, `_nocur`: show the cursor
163//! + `save_screen`, `sscr`: saves the screen view (single slot, not stack)
164//! + `load_screen`, `lscr`: restores the last saved screen view
165//! + `alt_buf`, `abuf`: enable alternative buffer
166//! + `_alt_buf`, `_abuf`: disable alternative buffer
167//!
168//! ### Compound
169//! - `clear`, `cls`: erases the screen and the buffer and moves the cursor to the
170//! topleft position (equivalent to `e mt,`)
171//!
172//! ## The uncoloring macros
173//! There are also macros that will skip the terminal commands. These can be
174//! useful when you need to conditionaly print with colors or without colors.
175//!
176//! The macros have the same names but they have `n` before the `c` to signify
177//! *no color*: [`formatnc`], [`printnc`], [`printncln`], [`eprintnc`],
178//! [`eprintncln`], [`writenc`] and [`writencln`].
179//!
180//! ## The conditionally coloring macros
181//! Theese are same as the normal coloring macros except they take additional
182//! first argument that tells whether the output should be colored or not.
183//!
184//! They have the same names as the uncoloring macros but they have `m` instead
185//! of the `n` to signify *maybe color*:[`formatmc`], [`printmc`],
186//! [`printmcln`], [`eprintmc`], [`eprintmcln`], [`writemc`] and [`writemcln`].
187//!
188//! ## Automatically coloring macros.
189//! Theese are same as the normal coloring macros except the will not color the
190//! output if it detects that the output stream is not terminal.
191//!
192//! They have the same name as the normal macros, but they have `a` before `c`
193//! to signify *automatic coloring*: [`printac`], [`printacln`], [`eprintac`]
194//! and [`eprintacln`].
195//!
196//! ## Examples
197//! ### With macro
198//! ```rust
199//! use termal::*;
200//!
201//! // you can use a special macro to inline the color codes, this will write
202//! // italic text with yellow foreground and reset at the end.
203//! printcln!("{'yellow italic}hello{'reset}");
204//!
205//! // the macro also supports standard formatting
206//! printcln!("{'yellow italic}{}{'reset}", "hello");
207//!
208//! // you can also use short versions of the codes
209//! printcln!("{'y i}{}{'_}", "hello");
210//!
211//! // you can also use true colors with their hex codes
212//! printcln!("{'#dd0 i}{}{'_}", "hello");
213//! ```
214//!
215//! ### Without macro
216//! ```rust
217//! // Move cursor to position column 5 on line 7 and write 'hello' in italic
218//! // yellow
219//!
220//! use termal::codes::*;
221//! use termal::*;
222//!
223//! println!("{}{YELLOW_FG}{ITALIC}hello{RESET}", move_to!(5, 7));
224//! ```
225//!
226//! ## Other macros
227//!
228//! The macros such as `move_to!` can accept either literals or dynamic values.
229//! Its main feature is that if you supply literals, it expands to a string
230//! literal with the ansi code.
231//! If you however supply dynamic values it expands to a `format!` macro:
232//! ```rust
233//! use termal::*;
234//!
235//! let a = move_to!(5, 7);
236//! // expands to:
237//! let a = "\x1b[5;7H";
238//!
239//! let b = move_to!(2 + 3, 7);
240//! // expands to:
241//! let b = format!("\x1b[{};{}H", 2 + 3, 7);
242//! ```
243//!
244//! If you know the values for the arguments you can also use the `*c` macros:
245//! ```rust
246//! use termal::formatc;
247//!
248//! // the spaces, or the lack of them is important
249//! let a = formatc!("{'move_to5,7}");
250//! ```
251//!
252//! ### Gradients
253//! Youn can create gradients with the function `termal::gradient`:
254//! ```rust
255//! use termal::*;
256//!
257//! // This will create foreground gradient from the rgb color `(250, 50, 170)`
258//! // to the rgb color `(180, 50, 240)`
259//! printcln!("{}{'_}",gradient("BonnyAD9", (250, 50, 170), (180, 50, 240)));
260//! ```
261
262#![cfg_attr(docsrs, feature(doc_cfg))]
263
264pub use termal_core::*;
265pub use termal_proc as proc;
266
267/// Works as [`println!`], in addition can generate ansi escape codes.
268/// To generate the ansi codes use `"{'...}"`.
269///
270/// # Examples
271/// ```
272/// use termal::*;
273/// // Print 'hello' in yellow:
274/// printcln!("{'yellow}hello{'reset}");
275/// ```
276#[macro_export]
277macro_rules! printcln {
278 ($l:literal $(,)?) => {
279 println!("{}", $crate::proc::colorize!($l));
280 };
281 ($l:literal, $($e:expr),+ $(,)?) => {
282 println!("{}", $crate::proc::colorize!($l, $($e),+));
283 };
284}
285
286/// Works as [`print!`], in addition can generate ansi escape codes.
287/// To generate the ansi codes use `"{'...}"`.
288///
289/// # Examples
290/// ```
291/// use termal::*;
292/// // Print 'hello' in yellow:
293/// printc!("{'yellow}hello{'reset}");
294/// ```
295#[macro_export]
296macro_rules! printc {
297 ($l:literal $(,)?) => {
298 print!("{}", $crate::proc::colorize!($l));
299 };
300 ($l:literal, $($e:expr),+ $(,)?) => {
301 print!("{}", $crate::proc::colorize!($l, $($e),+));
302 };
303}
304
305/// Works as [`eprintln!`], in addition can generate ansi escape codes.
306/// To generate the ansi codes use `"{'...}"`.
307///
308/// # Examples
309/// ```
310/// use termal::*;
311/// // Print 'hello' in yellow:
312/// eprintcln!("{'yellow}hello{'reset}");
313/// ```
314#[macro_export]
315macro_rules! eprintcln {
316 ($l:literal $(,)?) => {
317 eprintln!("{}", $crate::proc::colorize!($l));
318 };
319 ($l:literal, $($e:expr),+ $(,)?) => {
320 eprintln!("{}", $crate::proc::colorize!($l, $($e),+));
321 };
322}
323
324/// Works as [`eprint!`], in addition can generate ansi escape codes.
325/// To generate the ansi codes use `"{'...}"`.
326///
327/// # Examples
328/// ```
329/// use termal::*;
330/// // Print 'hello' in yellow:
331/// eprintc!("{'yellow}hello{'reset}");
332/// ```
333#[macro_export]
334macro_rules! eprintc {
335 ($l:literal $(,)?) => {
336 eprint!("{}", $crate::proc::colorize!($l));
337 };
338 ($l:literal, $($e:expr),+ $(,)?) => {
339 eprint!("{}", $crate::proc::colorize!($l, $($e),+));
340 };
341}
342
343/// Works as [`format!`], in addition can generate ansi escape codes.
344/// To generate the ansi codes use `"{'...}"`.
345///
346/// # Examples
347/// ```
348/// use termal::*;
349/// // Generate 'hello' in yellow:
350/// formatc!("{'yellow}hello{'reset}");
351/// ```
352#[macro_export]
353macro_rules! formatc {
354 ($l:literal $(,)?) => {
355 $crate::proc::colorize!($l)
356 };
357 ($l:literal, $($e:expr),+ $(,)?) => {
358 $crate::proc::colorize!($l, $($e),+)
359 };
360}
361
362/// Works as [`writeln!`], in addition can generate ansi escape codes.
363/// To generate the ansi codes use `"{'...}"`.
364#[macro_export]
365macro_rules! writecln {
366 ($f:expr, $l:literal $(,)?) => {
367 writeln!($f, "{}", $crate::proc::colorize!($l))
368 };
369 ($f:expr, $l:literal, $($e:expr),+ $(,)?) => {
370 writeln!($f, "{}", $crate::proc::colorize!($l, $($e),+))
371 };
372}
373
374/// Works as [`write!`], in addition can generate ansi escape codes.
375/// To generate the ansi codes use `"{'...}"`.
376#[macro_export]
377macro_rules! writec {
378 ($f:expr, $l:literal $(,)?) => {
379 write!($f, "{}", $crate::proc::colorize!($l))
380 };
381 ($f:expr, $l:literal, $($e:expr),+ $(,)?) => {
382 write!($f, "{}", $crate::proc::colorize!($l, $($e),+))
383 };
384}
385
386/// Works as [`println!`], skips terminal commands in `"{'...}"`.
387///
388/// # Examples
389/// ```
390/// use termal::*;
391/// // Print 'hello' (not in yellow, the terminal commands are skipped):
392/// printncln!("{'yellow}hello{'reset}");
393/// ```
394#[macro_export]
395macro_rules! printncln {
396 ($l:literal $(,)?) => {
397 println!("{}", $crate::proc::uncolor!($l));
398 };
399 ($l:literal, $($e:expr),+ $(,)?) => {
400 println!("{}", $crate::proc::uncolor!($l, $($e),+));
401 };
402}
403
404/// Works as [`print!`], skips terminal commands in `"{'...}"`.
405///
406/// # Examples
407/// ```
408/// use termal::*;
409/// // Print 'hello' (not in yellow, the terminal commands are skipped):
410/// printnc!("{'yellow}hello{'reset}");
411/// ```
412#[macro_export]
413macro_rules! printnc {
414 ($l:literal $(,)?) => {
415 print!("{}", $crate::proc::uncolor!($l));
416 };
417 ($l:literal, $($e:expr),+ $(,)?) => {
418 print!("{}", $crate::proc::uncolor!($l, $($e),+));
419 };
420}
421
422/// Works as [`eprintln!`], skips terminal commands in `"{'...}"`.
423///
424/// # Examples
425/// ```
426/// use termal::*;
427/// // Print 'hello' (not in yellow, the terminal commands are skipped):
428/// eprintncln!("{'yellow}hello{'reset}");
429/// ```
430#[macro_export]
431macro_rules! eprintncln {
432 ($l:literal $(,)?) => {
433 eprintln!("{}", $crate::proc::uncolor!($l));
434 };
435 ($l:literal, $($e:expr),+ $(,)?) => {
436 eprintln!("{}", $crate::proc::uncolor!($l, $($e),+));
437 };
438}
439
440/// Works as [`eprint!`], skips terminal commands in `"{'...}"`.
441///
442/// # Examples
443/// ```
444/// use termal::*;
445/// // Print 'hello' (not in yellow, the terminal commands are skipped):
446/// printnc!("{'yellow}hello{'reset}");
447/// ```
448#[macro_export]
449macro_rules! eprintnc {
450 ($l:literal $(,)?) => {
451 eprint!("{}", $crate::proc::uncolor!($l));
452 };
453 ($l:literal, $($e:expr),+ $(,)?) => {
454 eprint!("{}", $crate::proc::uncolor!($l, $($e),+));
455 };
456}
457
458/// Works as [`format!`], skips terminal commands in `"{'...}"`.
459///
460/// # Examples
461/// ```
462/// use termal::*;
463/// // Generate 'hello' (not in yellow, the terminal commands are skipped):
464/// printcln!("{'yellow}hello{'reset}");
465/// ```
466#[macro_export]
467macro_rules! formatnc {
468 ($l:literal $(,)?) => {
469 $crate::proc::uncolor!($l)
470 };
471 ($l:literal, $($e:expr),+ $(,)?) => {
472 $crate::proc::uncolor!($l, $($e),+)
473 };
474}
475
476/// Works as [`writeln!`], skips terminal commands in `"{'...}"`.
477#[macro_export]
478macro_rules! writencln {
479 ($f:expr, $l:literal $(,)?) => {
480 writeln!($f, "{}", $crate::proc::uncolor!($l))
481 };
482 ($f:expr, $l:literal, $($e:expr),+ $(,)?) => {
483 writeln!($f, "{}", $crate::proc::uncolor!($l, $($e),+))
484 };
485}
486
487/// Works as [`write!`], skips terminal commands in `"{'...}"`.
488#[macro_export]
489macro_rules! writenc {
490 ($f:expr, $l:literal $(,)?) => {
491 write!($f, "{}", $crate::proc::uncolor!($l))
492 };
493 ($f:expr, $l:literal, $($e:expr),+ $(,)?) => {
494 write!($f, "{}", $crate::proc::uncolor!($l, $($e),+))
495 };
496}
497
498/// Works as [`println!`], conditionally skips terminal commands in `"{'...}"`.
499///
500/// # Examples
501/// ```
502/// use termal::*;
503/// // Print 'hello' (not in yellow, the terminal commands are skipped):
504/// printmcln!(false, "{'yellow}hello{'reset}");
505/// ```
506#[macro_export]
507macro_rules! printmcln {
508 ($cond:expr, $l:literal $(,)?) => {
509 if $cond {
510 println!("{}", $crate::proc::colorize!($l));
511 } else {
512 println!("{}", $crate::proc::uncolor!($l));
513 }
514 };
515 ($cond:expr, $l:literal, $($e:expr),+ $(,)?) => {
516 if $cond {
517 println!("{}", $crate::proc::colorize!($l, $($e),+));
518 } else {
519 println!("{}", $crate::proc::uncolor!($l, $($e),+));
520 }
521 };
522}
523
524/// Works as [`print!`], conditionally skips terminal commands in `"{'...}"`.
525///
526/// # Examples
527/// ```
528/// use termal::*;
529/// // Print 'hello' (not in yellow, the terminal commands are skipped):
530/// printmc!(false, "{'yellow}hello{'reset}");
531/// ```
532#[macro_export]
533macro_rules! printmc {
534 ($cond:expr, $l:literal $(,)?) => {
535 if $cond {
536 print!("{}", $crate::proc::colorize!($l));
537 } else {
538 print!("{}", $crate::proc::uncolor!($l));
539 }
540 };
541 ($cond:expr, $l:literal, $($e:expr),+ $(,)?) => {
542 if $cond {
543 print!("{}", $crate::proc::colorize!($l, $($e),+));
544 } else {
545 print!("{}", $crate::proc::uncolor!($l, $($e),+));
546 }
547 };
548}
549
550/// Works as [`eprintln!`], conditionally skips terminal commands in
551/// `"{'...}"`.
552///
553/// # Examples
554/// ```
555/// use termal::*;
556/// // Print 'hello' (not in yellow, the terminal commands are skipped):
557/// eprintmcln!(false, "{'yellow}hello{'reset}");
558/// ```
559#[macro_export]
560macro_rules! eprintmcln {
561 ($cond:expr, $l:literal $(,)?) => {
562 if $cond {
563 eprintln!("{}", $crate::proc::colorize!($l));
564 } else {
565 eprintln!("{}", $crate::proc::uncolor!($l));
566 }
567 };
568 ($cond:expr, $l:literal, $($e:expr),+ $(,)?) => {
569 if $cond {
570 eprintln!("{}", $crate::proc::colorize!($l, $($e),+));
571 } else {
572 eprintln!("{}", $crate::proc::uncolor!($l, $($e),+));
573 }
574 };
575}
576
577/// Works as [`eprint!`], conditionally skips terminal commands in `"{'...}"`.
578///
579/// # Examples
580/// ```
581/// use termal::*;
582/// // Print 'hello' (not in yellow, the terminal commands are skipped):
583/// printmc!(false, "{'yellow}hello{'reset}");
584/// ```
585#[macro_export]
586macro_rules! eprintmc {
587 ($cond:expr, $l:literal $(,)?) => {
588 if $cond {
589 eprint!("{}", $crate::proc::colorize!($l));
590 } else {
591 eprint!("{}", $crate::proc::uncolor!($l));
592 }
593 };
594 ($cond:expr, $l:literal, $($e:expr),+ $(,)?) => {
595 if $cond {
596 eprint!("{}", $crate::proc::colorize!($l, $($e),+));
597 } else {
598 eprint!("{}", $crate::proc::uncolor!($l, $($e),+));
599 }
600 };
601}
602
603/// Works as [`format!`], conditionally skips terminal commands in `"{'...}"`.
604///
605/// # Examples
606/// ```
607/// use termal::*;
608/// // Generate 'hello' (not in yellow, the terminal commands are skipped):
609/// printmcln!(false, "{'yellow}hello{'reset}");
610/// ```
611#[macro_export]
612macro_rules! formatmc {
613 ($cond:expr, $l:literal $(,)?) => {
614 if $cond {
615 $crate::proc::colorize!($l)
616 } else {
617 $crate::proc::uncolor!($l)
618 }
619 };
620 ($cond:expr, $l:literal, $($e:expr),+ $(,)?) => {
621 if $cond {
622 $crate::proc::colorize!($l, $($e),+)
623 } else {
624 $crate::proc::uncolor!($l, $($e),+)
625 }
626 };
627}
628
629/// Works as [`writeln!`], conditionally skips terminal commands in `"{'...}"`.
630#[macro_export]
631macro_rules! writemcln {
632 ($f:expr, $cond:expr, $l:literal $(,)?) => {
633 if $cond {
634 writeln!($f, "{}", $crate::proc::colorize!($l))
635 } else {
636 writeln!($f, "{}", $crate::proc::uncolor!($l))
637 }
638 };
639 ($f:expr, $cond:expr, $l:literal, $($e:expr),+ $(,)?) => {
640 if $cond {
641 writeln!($f, "{}", $crate::proc::colorize!($l, $($e),+))
642 } else {
643 writeln!($f, "{}", $crate::proc::uncolor!($l, $($e),+))
644 }
645 };
646}
647
648/// Works as [`write!`], conditionally skips terminal commands in `"{'...}"`.
649#[macro_export]
650macro_rules! writemc {
651 ($f:expr, $cond:expr, $l:literal $(,)?) => {
652 if $cond {
653 write!($f, "{}", $crate::proc::colorize!($l))
654 } else {
655 write!($f, "{}", $crate::proc::uncolor!($l))
656 }
657 };
658 ($f:expr, $cond:expr, $l:literal, $($e:expr),+ $(,)?) => {
659 if $cond {
660 write!($f, "{}", $crate::proc::colorize!($l, $($e),+))
661 } else {
662 write!($f, "{}", $crate::proc::uncolor!($l, $($e),+))
663 }
664 };
665}
666
667/// Works as [`println!`], in addition can generate ansi escape codes.
668/// To generate the ansi codes use `"{'...}"`. This will not use the ansi codes
669/// if stdout is not terminal.
670///
671/// # Examples
672/// ```
673/// use termal::*;
674/// // Print 'hello' in yellow:
675/// printcln!("{'yellow}hello{'reset}");
676/// ```
677#[macro_export]
678macro_rules! printacln {
679 ($l:literal $(,)?) => {
680 $crate::printmcln!(
681 std::io::IsTerminal::is_terminal(&std::io::stdout()),
682 $l,
683 );
684 };
685 ($l:literal, $($e:expr),+ $(,)?) => {
686 $crate::printmcln!(
687 std::io::IsTerminal::is_terminal(&std::io::stdout()),
688 $l,
689 $($e),+,
690 );
691 };
692}
693
694/// Works as [`print!`], in addition can generate ansi escape codes.
695/// To generate the ansi codes use `"{'...}"`. This will not use the ansi codes
696/// if stdout is not terminal.
697///
698/// # Examples
699/// ```
700/// use termal::*;
701/// // Print 'hello' in yellow:
702/// printc!("{'yellow}hello{'reset}");
703/// ```
704#[macro_export]
705macro_rules! printac {
706 ($l:literal $(,)?) => {
707 $crate::printmc!(
708 std::io::IsTerminal::is_terminal(&std::io::stdout()),
709 $l,
710 );
711 };
712 ($l:literal, $($e:expr),+ $(,)?) => {
713 $crate::printmc!(
714 std::io::IsTerminal::is_terminal(&std::io::stdout()),
715 $l,
716 $($e),+,
717 );
718 };
719}
720
721/// Works as [`eprintln!`], in addition can generate ansi escape codes.
722/// To generate the ansi codes use `"{'...}"`. This will not use the ansi codes
723/// if stdout is not terminal.
724///
725/// # Examples
726/// ```
727/// use termal::*;
728/// // Print 'hello' in yellow:
729/// eprintcln!("{'yellow}hello{'reset}");
730/// ```
731#[macro_export]
732macro_rules! eprintacln {
733 ($l:literal $(,)?) => {
734 $crate::eprintmcln!(
735 std::io::IsTerminal::is_terminal(&std::io::stderr()),
736 $l,
737 );
738 };
739 ($l:literal, $($e:expr),+ $(,)?) => {
740 $crate::eprintmcln!(
741 std::io::IsTerminal::is_terminal(&std::io::stderr()),
742 $l,
743 $($e),+,
744 );
745 };
746}
747
748/// Works as [`eprint!`], in addition can generate ansi escape codes.
749/// To generate the ansi codes use `"{'...}"`. This will not use the ansi codes
750/// if stdout is not terminal.
751///
752/// # Examples
753/// ```
754/// use termal::*;
755/// // Print 'hello' in yellow:
756/// eprintc!("{'yellow}hello{'reset}");
757/// ```
758#[macro_export]
759macro_rules! eprintac {
760 ($l:literal $(,)?) => {
761 $crate::eprintmc!(
762 std::io::IsTerminal::is_terminal(&std::io::stderr()),
763 $l,
764 );
765 };
766 ($l:literal, $($e:expr),+ $(,)?) => {
767 $crate::eprintmc!(
768 std::io::IsTerminal::is_terminal(&std::io::stderr()),
769 $l,
770 $($e),+,
771 );
772 };
773}
774
775#[cfg(test)]
776mod tests {
777 use std::{
778 fmt::Display,
779 io::{Write, stdout},
780 };
781
782 use super::*;
783
784 #[test]
785 fn test_gradient() {
786 print!("Expect 'BonnyAD9' as pink to magenta gradient: ");
787 printcln!(
788 "{}{'_}",
789 gradient("BonnyAD9", (250, 50, 170), (180, 50, 240)),
790 );
791 _ = stdout().flush();
792 }
793
794 #[test]
795 fn test_printacln() {
796 let s = "Hello";
797 let num = 4;
798 print!("Expect 'Hello 4' in yellow: ");
799 printacln!("{'y}{s} {num}{'_}");
800 _ = stdout().flush();
801 }
802
803 #[test]
804 fn test_formatnc() {
805 let s = "Hello";
806 let num = 4;
807 let r = formatnc!("{'y}{s} {num}{'_}");
808 assert_eq!(r, "Hello 4");
809 }
810
811 #[test]
812 fn test_m() {
813 let s = "Hello";
814 let num = 4;
815 assert_eq!(
816 formatmc!(true, "{'y}{s} {num}{'_}"),
817 formatc!("{'y}{s} {num}{'_}")
818 );
819 assert_eq!(
820 formatmc!(false, "{'y}{s} {num}{'_}"),
821 formatnc!("{'y}{s} {num}{'_}")
822 );
823 }
824
825 #[cfg(feature = "term_text")]
826 #[test]
827 fn term_text() {
828 use term_text::TermText;
829
830 let txt = TermText::new(gradient("Hello", (0, 0, 0), (255, 255, 255)));
831
832 assert_eq!(5, txt.display_char_cnt());
833 assert_eq!(5, txt.display_bytes_cnt());
834 assert_eq!("Hello", txt.strip_control());
835 }
836
837 #[test]
838 fn test_write() {
839 struct Lol {}
840
841 impl Display for Lol {
842 fn fmt(
843 &self,
844 f: &mut std::fmt::Formatter<'_>,
845 ) -> std::fmt::Result {
846 writec!(f, "{'y}hello{'_}")
847 }
848 }
849
850 assert_eq!(format!("{}", Lol {}), formatc!("{'y}hello{'_}"))
851 }
852}