termdiff/themes/
signs_color.rs

1use std::borrow::Cow;
2
3use crate::themes::Theme;
4use crossterm::style::Stylize;
5
6/// A simple colorful theme using signs
7///
8/// ```
9/// use termdiff::{diff, SignsColorTheme};
10/// let old = "The quick brown fox and\njumps over the sleepy dog";
11/// let new = "The quick red fox and\njumps over the lazy dog";
12/// let mut buffer: Vec<u8> = Vec::new();
13/// let  theme = SignsColorTheme::default();
14/// diff(&mut buffer, old, new, &theme).unwrap();
15/// let actual: String = String::from_utf8(buffer).expect("Not valid UTF-8");
16///
17/// assert_eq!(
18///     actual,
19///     "\u{1b}[38;5;9m--- remove\u{1b}[39m | \u{1b}[38;5;10minsert +++\u{1b}[39m\n\u{1b}[38;5;9m-\u{1b}[39m\u{1b}[38;5;9mThe quick brown fox and\n\u{1b}[39m\u{1b}[38;5;9m-\u{1b}[39m\u{1b}[38;5;9mjumps over the sleepy dog\u{1b}[39m\n\u{1b}[38;5;10m+\u{1b}[39m\u{1b}[38;5;10mThe quick red fox and\n\u{1b}[39m\u{1b}[38;5;10m+\u{1b}[39m\u{1b}[38;5;10mjumps over the lazy dog\u{1b}[39m\n"
20/// );
21/// ```
22#[derive(Default, Clone, Copy, Debug)]
23pub struct SignsColorTheme {}
24
25impl Theme for SignsColorTheme {
26    fn highlight_insert<'this>(&self, input: &'this str) -> Cow<'this, str> {
27        input.underlined().green().to_string().into()
28    }
29
30    fn highlight_delete<'this>(&self, input: &'this str) -> Cow<'this, str> {
31        input.underlined().red().to_string().into()
32    }
33
34    fn equal_content<'this>(&self, input: &'this str) -> Cow<'this, str> {
35        input.into()
36    }
37
38    fn delete_content<'this>(&self, input: &'this str) -> Cow<'this, str> {
39        input.red().to_string().into()
40    }
41
42    fn equal_prefix<'this>(&self) -> Cow<'this, str> {
43        " ".into()
44    }
45
46    fn delete_prefix<'this>(&self) -> Cow<'this, str> {
47        "-".red().to_string().into()
48    }
49
50    fn insert_line<'this>(&self, input: &'this str) -> Cow<'this, str> {
51        input.green().to_string().into()
52    }
53
54    fn insert_prefix<'this>(&self) -> Cow<'this, str> {
55        "+".green().to_string().into()
56    }
57
58    fn line_end<'this>(&self) -> Cow<'this, str> {
59        "\n".into()
60    }
61
62    fn header<'this>(&self) -> Cow<'this, str> {
63        format!("{} | {}\n", "--- remove".red(), "insert +++".green()).into()
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70    use std::borrow::Cow;
71
72    /// Test that `SignsColorTheme` returns the expected prefixes
73    #[test]
74    fn test_signs_color_theme_prefixes() {
75        let theme = SignsColorTheme::default();
76        assert_eq!(theme.equal_prefix(), Cow::Borrowed(" "));
77        // Can't directly compare colored strings, so check they contain the expected characters
78        assert!(theme.delete_prefix().contains('-'));
79        assert!(theme.insert_prefix().contains('+'));
80    }
81
82    /// Test that `SignsColorTheme` applies highlighting to content
83    #[test]
84    fn test_signs_color_theme_highlighting() {
85        let theme = SignsColorTheme::default();
86        let input = "test";
87        // Highlighting should modify the input
88        assert_ne!(theme.highlight_insert(input), Cow::Borrowed(input));
89        assert_ne!(theme.highlight_delete(input), Cow::Borrowed(input));
90        assert_ne!(theme.delete_content(input), Cow::Borrowed(input));
91        assert_ne!(theme.insert_line(input), Cow::Borrowed(input));
92    }
93}