#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct StyledStr(String);
impl StyledStr {
pub const fn new() -> Self {
Self(String::new())
}
#[cfg(feature = "color")]
pub fn ansi(&self) -> impl std::fmt::Display + '_ {
self.0.as_str()
}
pub(crate) fn push_string(&mut self, msg: String) {
self.0.push_str(&msg);
}
pub(crate) fn push_str(&mut self, msg: &str) {
self.0.push_str(msg);
}
pub(crate) fn trim(&mut self) {
self.0 = self.0.trim().to_owned()
}
#[cfg(feature = "help")]
pub(crate) fn replace_newline_var(&mut self) {
self.0 = self.0.replace("{n}", "\n");
}
#[cfg(feature = "help")]
pub(crate) fn indent(&mut self, initial: &str, trailing: &str) {
self.0.insert_str(0, initial);
let mut line_sep = "\n".to_owned();
line_sep.push_str(trailing);
self.0 = self.0.replace('\n', &line_sep);
}
#[cfg(all(not(feature = "wrap_help"), feature = "help"))]
pub(crate) fn wrap(&mut self, _hard_width: usize) {}
#[cfg(feature = "wrap_help")]
pub(crate) fn wrap(&mut self, hard_width: usize) {
let mut new = String::with_capacity(self.0.len());
let mut last = 0;
let mut wrapper = crate::output::textwrap::wrap_algorithms::LineWrapper::new(hard_width);
for content in self.iter_text() {
let current = content.as_ptr() as usize - self.0.as_str().as_ptr() as usize;
if last != current {
new.push_str(&self.0.as_str()[last..current]);
}
last = current + content.len();
for (i, line) in content.split_inclusive('\n').enumerate() {
if 0 < i {
wrapper.reset();
}
let line = crate::output::textwrap::word_separators::find_words_ascii_space(line)
.collect::<Vec<_>>();
new.extend(wrapper.wrap(line));
}
}
if last != self.0.len() {
new.push_str(&self.0.as_str()[last..]);
}
new = new.trim_end().to_owned();
self.0 = new;
}
#[inline(never)]
#[cfg(feature = "help")]
pub(crate) fn display_width(&self) -> usize {
let mut width = 0;
for c in self.iter_text() {
width += crate::output::display_width(c);
}
width
}
#[cfg(feature = "help")]
pub(crate) fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[cfg(feature = "help")]
pub(crate) fn as_styled_str(&self) -> &str {
&self.0
}
#[cfg(feature = "color")]
pub(crate) fn iter_text(&self) -> impl Iterator<Item = &str> {
anstream::adapter::strip_str(&self.0)
}
#[cfg(not(feature = "color"))]
pub(crate) fn iter_text(&self) -> impl Iterator<Item = &str> {
[self.0.as_str()].into_iter()
}
pub(crate) fn push_styled(&mut self, other: &Self) {
self.0.push_str(&other.0);
}
pub(crate) fn write_to(&self, buffer: &mut dyn std::io::Write) -> std::io::Result<()> {
ok!(buffer.write_all(self.0.as_bytes()));
Ok(())
}
}
impl Default for &'_ StyledStr {
fn default() -> Self {
static DEFAULT: StyledStr = StyledStr::new();
&DEFAULT
}
}
impl From<std::string::String> for StyledStr {
fn from(name: std::string::String) -> Self {
StyledStr(name)
}
}
impl From<&'_ std::string::String> for StyledStr {
fn from(name: &'_ std::string::String) -> Self {
let mut styled = StyledStr::new();
styled.push_str(name);
styled
}
}
impl From<&'static str> for StyledStr {
fn from(name: &'static str) -> Self {
let mut styled = StyledStr::new();
styled.push_str(name);
styled
}
}
impl From<&'_ &'static str> for StyledStr {
fn from(name: &'_ &'static str) -> Self {
StyledStr::from(*name)
}
}
impl std::fmt::Write for StyledStr {
#[inline]
fn write_str(&mut self, s: &str) -> Result<(), std::fmt::Error> {
self.0.push_str(s);
Ok(())
}
#[inline]
fn write_char(&mut self, c: char) -> Result<(), std::fmt::Error> {
self.0.push(c);
Ok(())
}
}
impl std::fmt::Display for StyledStr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
for part in self.iter_text() {
part.fmt(f)?;
}
Ok(())
}
}