clap_builder/builder/
styled_str.rs1#![cfg_attr(not(feature = "usage"), allow(dead_code))]
2
3#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
24pub struct StyledStr(String);
25
26impl StyledStr {
27 pub const fn new() -> Self {
29 Self(String::new())
30 }
31
32 #[cfg(feature = "color")]
34 pub fn ansi(&self) -> impl std::fmt::Display + '_ {
35 self.0.as_str()
36 }
37
38 pub(crate) fn push_string(&mut self, msg: String) {
41 self.0.push_str(&msg);
42 }
43
44 pub fn push_str(&mut self, msg: &str) {
46 self.0.push_str(msg);
47 }
48
49 pub(crate) fn trim_start_lines(&mut self) {
50 if let Some(pos) = self.0.find('\n') {
51 let (leading, help) = self.0.split_at(pos + 1);
52 if leading.trim().is_empty() {
53 self.0 = help.to_owned();
54 }
55 }
56 }
57
58 pub(crate) fn trim_end(&mut self) {
59 self.0 = self.0.trim_end().to_owned();
60 }
61
62 #[cfg(feature = "help")]
63 pub(crate) fn replace_newline_var(&mut self) {
64 self.0 = self.0.replace("{n}", "\n");
65 }
66
67 #[cfg(feature = "help")]
68 pub(crate) fn indent(&mut self, initial: &str, trailing: &str) {
69 self.0.insert_str(0, initial);
70
71 let mut line_sep = "\n".to_owned();
72 line_sep.push_str(trailing);
73 self.0 = self.0.replace('\n', &line_sep);
74 }
75
76 #[cfg(all(not(feature = "wrap_help"), feature = "help"))]
77 pub(crate) fn wrap(&mut self, _hard_width: usize) {}
78
79 #[cfg(feature = "wrap_help")]
80 pub(crate) fn wrap(&mut self, hard_width: usize) {
81 let mut new = String::with_capacity(self.0.len());
82
83 let mut last = 0;
84 let mut wrapper = crate::output::textwrap::wrap_algorithms::LineWrapper::new(hard_width);
85 for content in self.iter_text() {
86 let current = content.as_ptr() as usize - self.0.as_str().as_ptr() as usize;
88 if last != current {
89 new.push_str(&self.0.as_str()[last..current]);
90 }
91 last = current + content.len();
92
93 for (i, line) in content.split_inclusive('\n').enumerate() {
94 if 0 < i {
95 wrapper.reset();
98 }
99 let line = crate::output::textwrap::word_separators::find_words_ascii_space(line)
100 .collect::<Vec<_>>();
101 new.extend(wrapper.wrap(line));
102 }
103 }
104 if last != self.0.len() {
105 new.push_str(&self.0.as_str()[last..]);
106 }
107 new = new.trim_end().to_owned();
108
109 self.0 = new;
110 }
111
112 #[inline(never)]
113 #[cfg(feature = "help")]
114 pub(crate) fn display_width(&self) -> usize {
115 let mut width = 0;
116 for c in self.iter_text() {
117 width += crate::output::display_width(c);
118 }
119 width
120 }
121
122 #[cfg(feature = "help")]
123 pub(crate) fn is_empty(&self) -> bool {
124 self.0.is_empty()
125 }
126
127 #[cfg(feature = "help")]
128 pub(crate) fn as_styled_str(&self) -> &str {
129 &self.0
130 }
131
132 #[cfg(feature = "color")]
133 pub(crate) fn iter_text(&self) -> impl Iterator<Item = &str> {
134 anstream::adapter::strip_str(&self.0)
135 }
136
137 #[cfg(not(feature = "color"))]
138 pub(crate) fn iter_text(&self) -> impl Iterator<Item = &str> {
139 [self.0.as_str()].into_iter()
140 }
141
142 pub(crate) fn push_styled(&mut self, other: &Self) {
143 self.0.push_str(&other.0);
144 }
145
146 pub(crate) fn write_to(&self, buffer: &mut dyn std::io::Write) -> std::io::Result<()> {
147 ok!(buffer.write_all(self.0.as_bytes()));
148
149 Ok(())
150 }
151}
152
153impl Default for &'_ StyledStr {
154 fn default() -> Self {
155 static DEFAULT: StyledStr = StyledStr::new();
156 &DEFAULT
157 }
158}
159
160impl From<String> for StyledStr {
161 fn from(name: String) -> Self {
162 StyledStr(name)
163 }
164}
165
166impl From<&'_ String> for StyledStr {
167 fn from(name: &'_ String) -> Self {
168 let mut styled = StyledStr::new();
169 styled.push_str(name);
170 styled
171 }
172}
173
174impl From<&'static str> for StyledStr {
175 fn from(name: &'static str) -> Self {
176 let mut styled = StyledStr::new();
177 styled.push_str(name);
178 styled
179 }
180}
181
182impl From<&'_ &'static str> for StyledStr {
183 fn from(name: &'_ &'static str) -> Self {
184 StyledStr::from(*name)
185 }
186}
187
188impl std::fmt::Write for StyledStr {
189 #[inline]
190 fn write_str(&mut self, s: &str) -> Result<(), std::fmt::Error> {
191 self.0.push_str(s);
192 Ok(())
193 }
194
195 #[inline]
196 fn write_char(&mut self, c: char) -> Result<(), std::fmt::Error> {
197 self.0.push(c);
198 Ok(())
199 }
200}
201
202impl std::fmt::Display for StyledStr {
204 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205 for part in self.iter_text() {
206 part.fmt(f)?;
207 }
208
209 Ok(())
210 }
211}