1use std::fmt::{self, Write};
2
3use super::{ANSIFmt, ANSIStr};
4
5/// The structure represents a ANSI color by suffix and prefix.
6#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub struct ANSIBuf {
8 prefix: String,
9 suffix: String,
10}
11
12impl ANSIBuf {
13 /// Constructs a new instance with suffix and prefix.
14 ///
15 /// They are not checked so you should make sure you provide correct ANSI.
16 /// Otherwise you may want to use [`TryFrom`].
17 ///
18 /// [`TryFrom`]: std::convert::TryFrom
19 pub fn new<P, S>(prefix: P, suffix: S) -> Self
20 where
21 P: Into<String>,
22 S: Into<String>,
23 {
24 let prefix = prefix.into();
25 let suffix = suffix.into();
26
27 Self { prefix, suffix }
28 }
29
30 /// Checks whether the color is not actually set.
31 pub fn is_empty(&self) -> bool {
32 self.prefix.is_empty() && self.suffix.is_empty()
33 }
34
35 /// Gets a reference to a prefix.
36 pub fn get_prefix(&self) -> &str {
37 &self.prefix
38 }
39
40 /// Gets a reference to a suffix.
41 pub fn get_suffix(&self) -> &str {
42 &self.suffix
43 }
44
45 /// Gets a reference as a color.
46 pub fn as_ref(&self) -> ANSIStr<'_> {
47 ANSIStr::new(&self.prefix, &self.suffix)
48 }
49}
50
51impl ANSIFmt for ANSIBuf {
52 fn fmt_ansi_prefix<W: Write>(&self, f: &mut W) -> fmt::Result {
53 f.write_str(&self.prefix)
54 }
55
56 fn fmt_ansi_suffix<W: Write>(&self, f: &mut W) -> fmt::Result {
57 f.write_str(&self.suffix)
58 }
59}
60
61#[cfg(feature = "ansi")]
62impl std::convert::TryFrom<&str> for ANSIBuf {
63 type Error = ();
64
65 fn try_from(value: &str) -> Result<Self, Self::Error> {
66 parse_ansi_color(value).ok_or(())
67 }
68}
69
70#[cfg(feature = "ansi")]
71impl std::convert::TryFrom<String> for ANSIBuf {
72 type Error = ();
73
74 fn try_from(value: String) -> Result<Self, Self::Error> {
75 Self::try_from(value.as_str())
76 }
77}
78
79#[cfg(feature = "ansi")]
80fn parse_ansi_color(s: &str) -> Option<ANSIBuf> {
81 let mut blocks = ansi_str::get_blocks(s);
82 let block = blocks.next()?;
83 let style = block.style();
84
85 let start = style.start().to_string();
86 let end = style.end().to_string();
87
88 Some(ANSIBuf::new(start, end))
89}
90
91impl From<ANSIStr<'_>> for ANSIBuf {
92 fn from(value: ANSIStr<'_>) -> Self {
93 Self::new(value.get_prefix(), value.get_suffix())
94 }
95}
96