1/// A style is a collection of properties that can format a string
2/// using ANSI escape codes.
3///
4/// # Examples
5///
6/// ```
7/// use nu_ansi_term::{Style, Color};
8///
9/// let style = Style::new().bold().on(Color::Black);
10/// println!("{}", style.paint("Bold on black"));
11/// ```
12#[derive(Eq, PartialEq, Clone, Copy)]
13#[cfg_attr(
14 feature = "derive_serde_style",
15 derive(serde::Deserialize, serde::Serialize)
16)]
17pub struct Style {
18 /// The style's foreground color, if it has one.
19 pub foreground: Option<Color>,
20
21 /// The style's background color, if it has one.
22 pub background: Option<Color>,
23
24 /// Whether this style is bold.
25 pub is_bold: bool,
26
27 /// Whether this style is dimmed.
28 pub is_dimmed: bool,
29
30 /// Whether this style is italic.
31 pub is_italic: bool,
32
33 /// Whether this style is underlined.
34 pub is_underline: bool,
35
36 /// Whether this style is blinking.
37 pub is_blink: bool,
38
39 /// Whether this style has reverse colors.
40 pub is_reverse: bool,
41
42 /// Whether this style is hidden.
43 pub is_hidden: bool,
44
45 /// Whether this style is struckthrough.
46 pub is_strikethrough: bool,
47
48 /// Wether this style is always displayed starting with a reset code to clear any remaining style artifacts
49 pub prefix_with_reset: bool,
50}
51
52impl Style {
53 /// Creates a new Style with no properties set.
54 ///
55 /// # Examples
56 ///
57 /// ```
58 /// use nu_ansi_term::Style;
59 ///
60 /// let style = Style::new();
61 /// println!("{}", style.paint("hi"));
62 /// ```
63 pub fn new() -> Style {
64 Style::default()
65 }
66
67 /// Returns a [`Style`] with the `Style.prefix_with_reset` property set.
68 ///
69 /// # Examples
70 ///
71 /// ```
72 /// use nu_ansi_term::Style;
73 ///
74 /// let style = Style::new().reset_before_style();
75 /// println!("{}", style.paint("hey"));
76 /// ```
77 pub const fn reset_before_style(&self) -> Style {
78 Style {
79 prefix_with_reset: true,
80 ..*self
81 }
82 }
83
84 /// Returns a `Style` with the bold property set.
85 ///
86 /// # Examples
87 ///
88 /// ```
89 /// use nu_ansi_term::Style;
90 ///
91 /// let style = Style::new().bold();
92 /// println!("{}", style.paint("hey"));
93 /// ```
94 pub const fn bold(&self) -> Style {
95 Style {
96 is_bold: true,
97 ..*self
98 }
99 }
100
101 /// Returns a `Style` with the dimmed property set.
102 ///
103 /// # Examples
104 ///
105 /// ```
106 /// use nu_ansi_term::Style;
107 ///
108 /// let style = Style::new().dimmed();
109 /// println!("{}", style.paint("sup"));
110 /// ```
111 pub const fn dimmed(&self) -> Style {
112 Style {
113 is_dimmed: true,
114 ..*self
115 }
116 }
117
118 /// Returns a `Style` with the italic property set.
119 ///
120 /// # Examples
121 ///
122 /// ```
123 /// use nu_ansi_term::Style;
124 ///
125 /// let style = Style::new().italic();
126 /// println!("{}", style.paint("greetings"));
127 /// ```
128 pub const fn italic(&self) -> Style {
129 Style {
130 is_italic: true,
131 ..*self
132 }
133 }
134
135 /// Returns a `Style` with the underline property set.
136 ///
137 /// # Examples
138 ///
139 /// ```
140 /// use nu_ansi_term::Style;
141 ///
142 /// let style = Style::new().underline();
143 /// println!("{}", style.paint("salutations"));
144 /// ```
145 pub const fn underline(&self) -> Style {
146 Style {
147 is_underline: true,
148 ..*self
149 }
150 }
151
152 /// Returns a `Style` with the blink property set.
153 /// # Examples
154 ///
155 /// ```
156 /// use nu_ansi_term::Style;
157 ///
158 /// let style = Style::new().blink();
159 /// println!("{}", style.paint("wazzup"));
160 /// ```
161 pub const fn blink(&self) -> Style {
162 Style {
163 is_blink: true,
164 ..*self
165 }
166 }
167
168 /// Returns a `Style` with the reverse property set.
169 ///
170 /// # Examples
171 ///
172 /// ```
173 /// use nu_ansi_term::Style;
174 ///
175 /// let style = Style::new().reverse();
176 /// println!("{}", style.paint("aloha"));
177 /// ```
178 pub const fn reverse(&self) -> Style {
179 Style {
180 is_reverse: true,
181 ..*self
182 }
183 }
184
185 /// Returns a `Style` with the hidden property set.
186 ///
187 /// # Examples
188 ///
189 /// ```
190 /// use nu_ansi_term::Style;
191 ///
192 /// let style = Style::new().hidden();
193 /// println!("{}", style.paint("ahoy"));
194 /// ```
195 pub const fn hidden(&self) -> Style {
196 Style {
197 is_hidden: true,
198 ..*self
199 }
200 }
201
202 /// Returns a `Style` with the strikethrough property set.
203 ///
204 /// # Examples
205 ///
206 /// ```
207 /// use nu_ansi_term::Style;
208 ///
209 /// let style = Style::new().strikethrough();
210 /// println!("{}", style.paint("yo"));
211 /// ```
212 pub const fn strikethrough(&self) -> Style {
213 Style {
214 is_strikethrough: true,
215 ..*self
216 }
217 }
218
219 /// Returns a `Style` with the foreground color property set.
220 ///
221 /// # Examples
222 ///
223 /// ```
224 /// use nu_ansi_term::{Style, Color};
225 ///
226 /// let style = Style::new().fg(Color::Yellow);
227 /// println!("{}", style.paint("hi"));
228 /// ```
229 pub const fn fg(&self, foreground: Color) -> Style {
230 Style {
231 foreground: Some(foreground),
232 ..*self
233 }
234 }
235
236 /// Returns a `Style` with the background color property set.
237 ///
238 /// # Examples
239 ///
240 /// ```
241 /// use nu_ansi_term::{Style, Color};
242 ///
243 /// let style = Style::new().on(Color::Blue);
244 /// println!("{}", style.paint("eyyyy"));
245 /// ```
246 pub const fn on(&self, background: Color) -> Style {
247 Style {
248 background: Some(background),
249 ..*self
250 }
251 }
252
253 /// Return true if this `Style` has no actual styles, and can be written
254 /// without any control characters.
255 ///
256 /// # Examples
257 ///
258 /// ```
259 /// use nu_ansi_term::Style;
260 ///
261 /// assert_eq!(true, Style::default().is_plain());
262 /// assert_eq!(false, Style::default().bold().is_plain());
263 /// ```
264 pub fn is_plain(self) -> bool {
265 self == Style::default()
266 }
267}
268
269impl Default for Style {
270 /// Returns a style with *no* properties set. Formatting text using this
271 /// style returns the exact same text.
272 ///
273 /// ```
274 /// use nu_ansi_term::Style;
275 /// assert_eq!(None, Style::default().foreground);
276 /// assert_eq!(None, Style::default().background);
277 /// assert_eq!(false, Style::default().is_bold);
278 /// assert_eq!("txt", Style::default().paint("txt").to_string());
279 /// ```
280 fn default() -> Style {
281 Style {
282 foreground: None,
283 background: None,
284 is_bold: false,
285 is_dimmed: false,
286 is_italic: false,
287 is_underline: false,
288 is_blink: false,
289 is_reverse: false,
290 is_hidden: false,
291 is_strikethrough: false,
292 prefix_with_reset: false,
293 }
294 }
295}
296
297// ---- colors ----
298
299/// A color is one specific type of ANSI escape code, and can refer
300/// to either the foreground or background color.
301///
302/// These use the standard numeric sequences.
303/// See <http://invisible-island.net/xterm/ctlseqs/ctlseqs.html>
304#[derive(Eq, PartialEq, Clone, Copy, Debug, Default)]
305#[cfg_attr(
306 feature = "derive_serde_style",
307 derive(serde::Deserialize, serde::Serialize)
308)]
309pub enum Color {
310 /// Color #0 (foreground code `30`, background code `40`).
311 ///
312 /// This is not necessarily the background color, and using it as one may
313 /// render the text hard to read on terminals with dark backgrounds.
314 Black,
315
316 /// Color #0 (foreground code `90`, background code `100`).
317 DarkGray,
318
319 /// Color #1 (foreground code `31`, background code `41`).
320 Red,
321
322 /// Color #1 (foreground code `91`, background code `101`).
323 LightRed,
324
325 /// Color #2 (foreground code `32`, background code `42`).
326 Green,
327
328 /// Color #2 (foreground code `92`, background code `102`).
329 LightGreen,
330
331 /// Color #3 (foreground code `33`, background code `43`).
332 Yellow,
333
334 /// Color #3 (foreground code `93`, background code `103`).
335 LightYellow,
336
337 /// Color #4 (foreground code `34`, background code `44`).
338 Blue,
339
340 /// Color #4 (foreground code `94`, background code `104`).
341 LightBlue,
342
343 /// Color #5 (foreground code `35`, background code `45`).
344 Purple,
345
346 /// Color #5 (foreground code `95`, background code `105`).
347 LightPurple,
348
349 /// Color #5 (foreground code `35`, background code `45`).
350 Magenta,
351
352 /// Color #5 (foreground code `95`, background code `105`).
353 LightMagenta,
354
355 /// Color #6 (foreground code `36`, background code `46`).
356 Cyan,
357
358 /// Color #6 (foreground code `96`, background code `106`).
359 LightCyan,
360
361 /// Color #7 (foreground code `37`, background code `47`).
362 ///
363 /// As above, this is not necessarily the foreground color, and may be
364 /// hard to read on terminals with light backgrounds.
365 White,
366
367 /// Color #7 (foreground code `97`, background code `107`).
368 LightGray,
369
370 /// A color number from 0 to 255, for use in 256-color terminal
371 /// environments.
372 ///
373 /// - colors 0 to 7 are the `Black` to `White` variants respectively.
374 /// These colors can usually be changed in the terminal emulator.
375 /// - colors 8 to 15 are brighter versions of the eight colors above.
376 /// These can also usually be changed in the terminal emulator, or it
377 /// could be configured to use the original colors and show the text in
378 /// bold instead. It varies depending on the program.
379 /// - colors 16 to 231 contain several palettes of bright colors,
380 /// arranged in six squares measuring six by six each.
381 /// - colors 232 to 255 are shades of grey from black to white.
382 ///
383 /// It might make more sense to look at a [color chart][cc].
384 ///
385 /// [cc]: https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg
386 Fixed(u8),
387
388 /// A 24-bit Rgb color, as specified by ISO-8613-3.
389 Rgb(u8, u8, u8),
390
391 /// The default color (foreground code `39`, background codr `49`).
392 #[default]
393 Default,
394}
395
396impl Color {
397 /// Returns a `Style` with the foreground color set to this color.
398 ///
399 /// # Examples
400 ///
401 /// ```
402 /// use nu_ansi_term::Color;
403 ///
404 /// let style = Color::Red.normal();
405 /// println!("{}", style.paint("hi"));
406 /// ```
407 pub fn normal(self) -> Style {
408 Style {
409 foreground: Some(self),
410 ..Style::default()
411 }
412 }
413
414 /// Returns a `Style` with the foreground color set to this color and the
415 /// bold property set.
416 ///
417 /// # Examples
418 ///
419 /// ```
420 /// use nu_ansi_term::Color;
421 ///
422 /// let style = Color::Green.bold();
423 /// println!("{}", style.paint("hey"));
424 /// ```
425 pub fn bold(self) -> Style {
426 Style {
427 foreground: Some(self),
428 is_bold: true,
429 ..Style::default()
430 }
431 }
432
433 /// Returns a `Style` with the foreground color set to this color and the
434 /// dimmed property set.
435 ///
436 /// # Examples
437 ///
438 /// ```
439 /// use nu_ansi_term::Color;
440 ///
441 /// let style = Color::Yellow.dimmed();
442 /// println!("{}", style.paint("sup"));
443 /// ```
444 pub fn dimmed(self) -> Style {
445 Style {
446 foreground: Some(self),
447 is_dimmed: true,
448 ..Style::default()
449 }
450 }
451
452 /// Returns a `Style` with the foreground color set to this color and the
453 /// italic property set.
454 ///
455 /// # Examples
456 ///
457 /// ```
458 /// use nu_ansi_term::Color;
459 ///
460 /// let style = Color::Blue.italic();
461 /// println!("{}", style.paint("greetings"));
462 /// ```
463 pub fn italic(self) -> Style {
464 Style {
465 foreground: Some(self),
466 is_italic: true,
467 ..Style::default()
468 }
469 }
470
471 /// Returns a `Style` with the foreground color set to this color and the
472 /// underline property set.
473 ///
474 /// # Examples
475 ///
476 /// ```
477 /// use nu_ansi_term::Color;
478 ///
479 /// let style = Color::Purple.underline();
480 /// println!("{}", style.paint("salutations"));
481 /// ```
482 pub fn underline(self) -> Style {
483 Style {
484 foreground: Some(self),
485 is_underline: true,
486 ..Style::default()
487 }
488 }
489
490 /// Returns a `Style` with the foreground color set to this color and the
491 /// blink property set.
492 ///
493 /// # Examples
494 ///
495 /// ```
496 /// use nu_ansi_term::Color;
497 ///
498 /// let style = Color::Cyan.blink();
499 /// println!("{}", style.paint("wazzup"));
500 /// ```
501 pub fn blink(self) -> Style {
502 Style {
503 foreground: Some(self),
504 is_blink: true,
505 ..Style::default()
506 }
507 }
508
509 /// Returns a `Style` with the foreground color set to this color and the
510 /// reverse property set.
511 ///
512 /// # Examples
513 ///
514 /// ```
515 /// use nu_ansi_term::Color;
516 ///
517 /// let style = Color::Black.reverse();
518 /// println!("{}", style.paint("aloha"));
519 /// ```
520 pub fn reverse(self) -> Style {
521 Style {
522 foreground: Some(self),
523 is_reverse: true,
524 ..Style::default()
525 }
526 }
527
528 /// Returns a `Style` with the foreground color set to this color and the
529 /// hidden property set.
530 ///
531 /// # Examples
532 ///
533 /// ```
534 /// use nu_ansi_term::Color;
535 ///
536 /// let style = Color::White.hidden();
537 /// println!("{}", style.paint("ahoy"));
538 /// ```
539 pub fn hidden(self) -> Style {
540 Style {
541 foreground: Some(self),
542 is_hidden: true,
543 ..Style::default()
544 }
545 }
546
547 /// Returns a `Style` with the foreground color set to this color and the
548 /// strikethrough property set.
549 ///
550 /// # Examples
551 ///
552 /// ```
553 /// use nu_ansi_term::Color;
554 ///
555 /// let style = Color::Fixed(244).strikethrough();
556 /// println!("{}", style.paint("yo"));
557 /// ```
558 pub fn strikethrough(self) -> Style {
559 Style {
560 foreground: Some(self),
561 is_strikethrough: true,
562 ..Style::default()
563 }
564 }
565
566 /// Returns a `Style` thats resets all styling before applying
567 /// the foreground color set to this color.
568 ///
569 /// # Examples
570 ///
571 /// ```
572 /// use nu_ansi_term::Color;
573 ///
574 /// let style = Color::Fixed(244).reset_before_style();
575 /// println!("{}", style.paint("yo"));
576 /// ```
577 pub fn reset_before_style(self) -> Style {
578 Style {
579 foreground: Some(self),
580 prefix_with_reset: true,
581 ..Style::default()
582 }
583 }
584
585 /// Returns a `Style` with the foreground color set to this color and the
586 /// background color property set to the given color.
587 ///
588 /// # Examples
589 ///
590 /// ```
591 /// use nu_ansi_term::Color;
592 ///
593 /// let style = Color::Rgb(31, 31, 31).on(Color::White);
594 /// println!("{}", style.paint("eyyyy"));
595 /// ```
596 pub fn on(self, background: Color) -> Style {
597 Style {
598 foreground: Some(self),
599 background: Some(background),
600 ..Style::default()
601 }
602 }
603}
604
605impl From<Color> for Style {
606 /// You can turn a `Color` into a `Style` with the foreground color set
607 /// with the `From` trait.
608 ///
609 /// ```
610 /// use nu_ansi_term::{Style, Color};
611 /// let green_foreground = Style::default().fg(Color::Green);
612 /// assert_eq!(green_foreground, Color::Green.normal());
613 /// assert_eq!(green_foreground, Color::Green.into());
614 /// assert_eq!(green_foreground, Style::from(Color::Green));
615 /// ```
616 fn from(color: Color) -> Style {
617 color.normal()
618 }
619}
620
621#[cfg(test)]
622#[cfg(feature = "derive_serde_style")]
623mod serde_json_tests {
624 use super::{Color, Style};
625
626 #[test]
627 fn color_serialization() {
628 let colors = &[
629 Color::Red,
630 Color::Blue,
631 Color::Rgb(123, 123, 123),
632 Color::Fixed(255),
633 ];
634
635 assert_eq!(
636 serde_json::to_string(&colors).unwrap(),
637 "[\"Red\",\"Blue\",{\"Rgb\":[123,123,123]},{\"Fixed\":255}]"
638 );
639 }
640
641 #[test]
642 fn color_deserialization() {
643 let colors = [
644 Color::Red,
645 Color::Blue,
646 Color::Rgb(123, 123, 123),
647 Color::Fixed(255),
648 ];
649
650 for color in colors {
651 let serialized = serde_json::to_string(&color).unwrap();
652 let deserialized: Color = serde_json::from_str(&serialized).unwrap();
653
654 assert_eq!(color, deserialized);
655 }
656 }
657
658 #[test]
659 fn style_serialization() {
660 let style = Style::default();
661
662 assert_eq!(serde_json::to_string(&style).unwrap(), "{\"foreground\":null,\"background\":null,\"is_bold\":false,\"is_dimmed\":false,\"is_italic\":false,\"is_underline\":false,\"is_blink\":false,\"is_reverse\":false,\"is_hidden\":false,\"is_strikethrough\":false,\"prefix_with_reset\":false}".to_string());
663 }
664}
665

Provided by KDAB

Privacy Policy
Learn Rust with the experts
Find out more