termdiff/themes/
theme.rs

1use std::{borrow::Cow, fmt::Debug};
2
3/// A [`Theme`] for customizing the appearance of diffs
4///
5/// This trait allows you to control how diffs are displayed without having
6/// to parse the diff output yourself. You can customize prefixes, highlighting,
7/// and formatting for different types of changes.
8///
9/// # Implementing a Custom Theme
10///
11/// To create a custom theme, you must implement at minimum:
12/// - `equal_prefix`: Prefix for unchanged lines
13/// - `delete_prefix`: Prefix for removed lines
14/// - `insert_prefix`: Prefix for added lines
15/// - `header`: Header text displayed at the top of the diff
16///
17/// All other methods have default implementations that you can override as needed.
18///
19/// # Example
20///
21/// ```rust
22/// use std::borrow::Cow;
23/// use termdiff::Theme;
24///
25/// #[derive(Debug)]
26/// struct MyCustomTheme {}
27///
28/// impl Theme for MyCustomTheme {
29///     // Required methods
30///     fn equal_prefix<'this>(&self) -> Cow<'this, str> {
31///         " ".into()  // Space for unchanged lines
32///     }
33///
34///     fn delete_prefix<'this>(&self) -> Cow<'this, str> {
35///         "[-]".into()  // Custom prefix for removed lines
36///     }
37///
38///     fn insert_prefix<'this>(&self) -> Cow<'this, str> {
39///         "[+]".into()  // Custom prefix for added lines
40///     }
41///
42///     fn header<'this>(&self) -> Cow<'this, str> {
43///         "=== DIFF RESULTS ===\n".into()  // Custom header
44///     }
45///
46///     // Optional overrides for customizing content formatting
47///     fn delete_content<'this>(&self, input: &'this str) -> Cow<'this, str> {
48///         format!("REMOVED: {}", input).into()  // Custom formatting for removed content
49///     }
50///
51///     fn insert_line<'this>(&self, input: &'this str) -> Cow<'this, str> {
52///         format!("ADDED: {}", input).into()  // Custom formatting for added content
53///     }
54/// }
55/// ```
56pub trait Theme: Debug {
57    /// How to format the text when highlighting specific changes in inserted lines
58    ///
59    /// This is used to highlight the specific parts of text that have changed within
60    /// an inserted line. By default, it returns the input unchanged.
61    ///
62    /// # Example
63    ///
64    /// ```
65    /// # use std::borrow::Cow;
66    /// # use termdiff::Theme;
67    /// # #[derive(Debug)]
68    /// # struct MyTheme;
69    /// # impl Theme for MyTheme {
70    /// #     fn equal_prefix<'a>(&self) -> Cow<'a, str> { " ".into() }
71    /// #     fn delete_prefix<'a>(&self) -> Cow<'a, str> { "-".into() }
72    /// #     fn insert_prefix<'a>(&self) -> Cow<'a, str> { "+".into() }
73    /// #     fn header<'a>(&self) -> Cow<'a, str> { "".into() }
74    /// fn highlight_insert<'this>(&self, input: &'this str) -> Cow<'this, str> {
75    ///     format!("**{}**", input).into()  // Bold the inserted text
76    /// }
77    /// # }
78    /// ```
79    fn highlight_insert<'this>(&self, input: &'this str) -> Cow<'this, str> {
80        input.into()
81    }
82
83    /// How to format the text when highlighting specific changes in deleted lines
84    ///
85    /// This is used to highlight the specific parts of text that have changed within
86    /// a deleted line. By default, it returns the input unchanged.
87    fn highlight_delete<'this>(&self, input: &'this str) -> Cow<'this, str> {
88        input.into()
89    }
90
91    /// How to format unchanged content
92    ///
93    /// This method is called for content that exists in both the old and new text.
94    /// By default, it returns the input unchanged.
95    fn equal_content<'this>(&self, input: &'this str) -> Cow<'this, str> {
96        input.into()
97    }
98
99    /// How to format content that is being removed
100    ///
101    /// This method is called for content that exists only in the old text.
102    /// By default, it returns the input unchanged.
103    fn delete_content<'this>(&self, input: &'this str) -> Cow<'this, str> {
104        input.into()
105    }
106
107    /// The prefix to display before lines that are unchanged
108    ///
109    /// This is typically a space or other character that indicates the line is unchanged.
110    /// This method is required for all theme implementations.
111    fn equal_prefix<'this>(&self) -> Cow<'this, str>;
112
113    /// The prefix to display before lines that are being removed
114    ///
115    /// This is typically a character like '-' that indicates the line is being removed.
116    /// This method is required for all theme implementations.
117    fn delete_prefix<'this>(&self) -> Cow<'this, str>;
118
119    /// How to format content that is being added
120    ///
121    /// This method is called for content that exists only in the new text.
122    /// By default, it returns the input unchanged.
123    fn insert_line<'this>(&self, input: &'this str) -> Cow<'this, str> {
124        input.into()
125    }
126
127    /// The prefix to display before lines that are being added
128    ///
129    /// This is typically a character like '+' that indicates the line is being added.
130    /// This method is required for all theme implementations.
131    fn insert_prefix<'this>(&self) -> Cow<'this, str>;
132
133    /// The string to append when a diff line doesn't end with a newline
134    ///
135    /// By default, this adds a newline character.
136    fn line_end<'this>(&self) -> Cow<'this, str> {
137        "\n".into()
138    }
139
140    /// The marker to show when one string has a trailing newline and the other doesn't
141    ///
142    /// When one of the two strings ends with a newline and the other doesn't,
143    /// this character is inserted before the newline to make the difference visible.
144    /// By default, this uses the Unicode character '␊' (U+240A).
145    fn trailing_lf_marker<'this>(&self) -> Cow<'this, str> {
146        "␊".into()
147    }
148
149    /// The header text to display at the top of the diff
150    ///
151    /// This is typically a line explaining the diff format.
152    /// This method is required for all theme implementations.
153    fn header<'this>(&self) -> Cow<'this, str>;
154}