mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-10 15:14:27 +00:00
fix(stylize)!: add Stylize impl for String (#466)
Although the `Stylize` trait is already implemented for `&str` which extends to `String`, it is not implemented for `String` itself. This commit adds an impl of Stylize that returns a Span<'static> for `String` so that code can call Stylize methods on temporary `String`s. E.g. the following now compiles instead of failing with a compile error about referencing a temporary value: let s = format!("hello {name}!", "world").red(); BREAKING CHANGE: This may break some code that expects to call Stylize methods on `String` values and then use the String value later. This will now fail to compile because the String is consumed by set_style instead of a slice being created and consumed. This can be fixed by cloning the `String`. E.g.: let s = String::from("hello world"); let line = Line::from(vec![s.red(), s.green()]); // fails to compile let line = Line::from(vec![s.clone().red(), s.green()]); // works
This commit is contained in:
parent
74c5244be1
commit
ebd3680a47
2 changed files with 134 additions and 5 deletions
|
@ -124,7 +124,7 @@ fn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) {
|
||||||
Line::from("This is a line ".red()),
|
Line::from("This is a line ".red()),
|
||||||
Line::from("This is a line".on_dark_gray()),
|
Line::from("This is a line".on_dark_gray()),
|
||||||
Line::from("This is a longer line".crossed_out()),
|
Line::from("This is a longer line".crossed_out()),
|
||||||
Line::from(long_line.reset()),
|
Line::from(long_line.clone()),
|
||||||
Line::from("This is a line".reset()),
|
Line::from("This is a line".reset()),
|
||||||
Line::from(vec![
|
Line::from(vec![
|
||||||
Span::raw("Masked text: "),
|
Span::raw("Masked text: "),
|
||||||
|
@ -137,7 +137,7 @@ fn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) {
|
||||||
Line::from("This is a line ".red()),
|
Line::from("This is a line ".red()),
|
||||||
Line::from("This is a line".on_dark_gray()),
|
Line::from("This is a line".on_dark_gray()),
|
||||||
Line::from("This is a longer line".crossed_out()),
|
Line::from("This is a longer line".crossed_out()),
|
||||||
Line::from(long_line.reset()),
|
Line::from(long_line.clone()),
|
||||||
Line::from("This is a line".reset()),
|
Line::from("This is a line".reset()),
|
||||||
Line::from(vec![
|
Line::from(vec![
|
||||||
Span::raw("Masked text: "),
|
Span::raw("Masked text: "),
|
||||||
|
|
|
@ -179,16 +179,145 @@ impl<'a> Styled for &'a str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Styled for String {
|
||||||
|
type Item = Span<'static>;
|
||||||
|
|
||||||
|
fn style(&self) -> Style {
|
||||||
|
Style::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_style(self, style: Style) -> Self::Item {
|
||||||
|
Span::styled(self, style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn str_styled() {
|
||||||
|
assert_eq!("hello".style(), Style::default());
|
||||||
|
assert_eq!(
|
||||||
|
"hello".set_style(Style::new().cyan()),
|
||||||
|
Span::styled("hello", Style::new().cyan())
|
||||||
|
);
|
||||||
|
assert_eq!("hello".black(), Span::from("hello").black());
|
||||||
|
assert_eq!("hello".red(), Span::from("hello").red());
|
||||||
|
assert_eq!("hello".green(), Span::from("hello").green());
|
||||||
|
assert_eq!("hello".yellow(), Span::from("hello").yellow());
|
||||||
|
assert_eq!("hello".blue(), Span::from("hello").blue());
|
||||||
|
assert_eq!("hello".magenta(), Span::from("hello").magenta());
|
||||||
|
assert_eq!("hello".cyan(), Span::from("hello").cyan());
|
||||||
|
assert_eq!("hello".gray(), Span::from("hello").gray());
|
||||||
|
assert_eq!("hello".dark_gray(), Span::from("hello").dark_gray());
|
||||||
|
assert_eq!("hello".light_red(), Span::from("hello").light_red());
|
||||||
|
assert_eq!("hello".light_green(), Span::from("hello").light_green());
|
||||||
|
assert_eq!("hello".light_yellow(), Span::from("hello").light_yellow());
|
||||||
|
assert_eq!("hello".light_blue(), Span::from("hello").light_blue());
|
||||||
|
assert_eq!("hello".light_magenta(), Span::from("hello").light_magenta());
|
||||||
|
assert_eq!("hello".light_cyan(), Span::from("hello").light_cyan());
|
||||||
|
assert_eq!("hello".white(), Span::from("hello").white());
|
||||||
|
|
||||||
|
assert_eq!("hello".on_black(), Span::from("hello").on_black());
|
||||||
|
assert_eq!("hello".on_red(), Span::from("hello").on_red());
|
||||||
|
assert_eq!("hello".on_green(), Span::from("hello").on_green());
|
||||||
|
assert_eq!("hello".on_yellow(), Span::from("hello").on_yellow());
|
||||||
|
assert_eq!("hello".on_blue(), Span::from("hello").on_blue());
|
||||||
|
assert_eq!("hello".on_magenta(), Span::from("hello").on_magenta());
|
||||||
|
assert_eq!("hello".on_cyan(), Span::from("hello").on_cyan());
|
||||||
|
assert_eq!("hello".on_gray(), Span::from("hello").on_gray());
|
||||||
|
assert_eq!("hello".on_dark_gray(), Span::from("hello").on_dark_gray());
|
||||||
|
assert_eq!("hello".on_light_red(), Span::from("hello").on_light_red());
|
||||||
|
assert_eq!(
|
||||||
|
"hello".on_light_green(),
|
||||||
|
Span::from("hello").on_light_green()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
"hello".on_light_yellow(),
|
||||||
|
Span::from("hello").on_light_yellow()
|
||||||
|
);
|
||||||
|
assert_eq!("hello".on_light_blue(), Span::from("hello").on_light_blue());
|
||||||
|
assert_eq!(
|
||||||
|
"hello".on_light_magenta(),
|
||||||
|
Span::from("hello").on_light_magenta()
|
||||||
|
);
|
||||||
|
assert_eq!("hello".on_light_cyan(), Span::from("hello").on_light_cyan());
|
||||||
|
assert_eq!("hello".on_white(), Span::from("hello").on_white());
|
||||||
|
|
||||||
|
assert_eq!("hello".bold(), Span::from("hello").bold());
|
||||||
|
assert_eq!("hello".dim(), Span::from("hello").dim());
|
||||||
|
assert_eq!("hello".italic(), Span::from("hello").italic());
|
||||||
|
assert_eq!("hello".underlined(), Span::from("hello").underlined());
|
||||||
|
assert_eq!("hello".slow_blink(), Span::from("hello").slow_blink());
|
||||||
|
assert_eq!("hello".rapid_blink(), Span::from("hello").rapid_blink());
|
||||||
|
assert_eq!("hello".reversed(), Span::from("hello").reversed());
|
||||||
|
assert_eq!("hello".hidden(), Span::from("hello").hidden());
|
||||||
|
assert_eq!("hello".crossed_out(), Span::from("hello").crossed_out());
|
||||||
|
|
||||||
|
assert_eq!("hello".not_bold(), Span::from("hello").not_bold());
|
||||||
|
assert_eq!("hello".not_dim(), Span::from("hello").not_dim());
|
||||||
|
assert_eq!("hello".not_italic(), Span::from("hello").not_italic());
|
||||||
|
assert_eq!(
|
||||||
|
"hello".not_underlined(),
|
||||||
|
Span::from("hello").not_underlined()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
"hello".not_slow_blink(),
|
||||||
|
Span::from("hello").not_slow_blink()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
"hello".not_rapid_blink(),
|
||||||
|
Span::from("hello").not_rapid_blink()
|
||||||
|
);
|
||||||
|
assert_eq!("hello".not_reversed(), Span::from("hello").not_reversed());
|
||||||
|
assert_eq!("hello".not_hidden(), Span::from("hello").not_hidden());
|
||||||
|
assert_eq!(
|
||||||
|
"hello".not_crossed_out(),
|
||||||
|
Span::from("hello").not_crossed_out()
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!("hello".reset(), Span::from("hello").reset());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn string_styled() {
|
||||||
|
let s = String::from("hello");
|
||||||
|
assert_eq!(s.style(), Style::default());
|
||||||
|
assert_eq!(
|
||||||
|
s.clone().set_style(Style::new().cyan()),
|
||||||
|
Span::styled("hello", Style::new().cyan())
|
||||||
|
);
|
||||||
|
assert_eq!(s.clone().black(), Span::from("hello").black());
|
||||||
|
assert_eq!(s.clone().on_black(), Span::from("hello").on_black());
|
||||||
|
assert_eq!(s.clone().bold(), Span::from("hello").bold());
|
||||||
|
assert_eq!(s.clone().not_bold(), Span::from("hello").not_bold());
|
||||||
|
assert_eq!(s.clone().reset(), Span::from("hello").reset());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn temporary_string_styled() {
|
||||||
|
// to_string() is used to create a temporary String, which is then styled. Without the
|
||||||
|
// `Styled` trait impl for `String`, this would fail to compile with the error: "temporary
|
||||||
|
// value dropped while borrowed"
|
||||||
|
let s = "hello".to_string().red();
|
||||||
|
assert_eq!(s, Span::from("hello").red());
|
||||||
|
|
||||||
|
// format!() is used to create a temporary String inside a closure, which suffers the same
|
||||||
|
// issue as above without the `Styled` trait impl for `String`
|
||||||
|
let items = vec![String::from("a"), String::from("b")];
|
||||||
|
let sss = items.iter().map(|s| format!("{s}{s}").red()).collect_vec();
|
||||||
|
assert_eq!(sss, vec![Span::from("aa").red(), Span::from("bb").red()]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reset() {
|
fn reset() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"hello".on_cyan().light_red().bold().underlined().reset(),
|
"hello".on_cyan().light_red().bold().underlined().reset(),
|
||||||
Span::styled("hello", Style::reset())
|
Span::styled("hello", Style::reset())
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -211,14 +340,14 @@ mod tests {
|
||||||
.fg(Color::Cyan)
|
.fg(Color::Cyan)
|
||||||
.add_modifier(Modifier::BOLD);
|
.add_modifier(Modifier::BOLD);
|
||||||
|
|
||||||
assert_eq!("hello".cyan().bold(), Span::styled("hello", cyan_bold))
|
assert_eq!("hello".cyan().bold(), Span::styled("hello", cyan_bold));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fg_bg() {
|
fn fg_bg() {
|
||||||
let cyan_fg_bg = Style::default().bg(Color::Cyan).fg(Color::Cyan);
|
let cyan_fg_bg = Style::default().bg(Color::Cyan).fg(Color::Cyan);
|
||||||
|
|
||||||
assert_eq!("hello".cyan().on_cyan(), Span::styled("hello", cyan_fg_bg))
|
assert_eq!("hello".cyan().on_cyan(), Span::styled("hello", cyan_fg_bg));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue