1use anstyle::{Color as AnstyleColor, Effects, Style as AnstyleStyle};
7use ratatui::style::{Modifier, Style};
8
9use crate::color::anstyle_to_ratatui_color;
10
11pub fn anstyle_to_ratatui_style(style: AnstyleStyle) -> Style {
15 let mut ratatui_style = Style::default();
16
17 if let Some(fg) = style.get_fg_color() {
18 ratatui_style = ratatui_style.fg(anstyle_to_ratatui_color(fg));
19 }
20
21 if let Some(bg) = style.get_bg_color() {
22 ratatui_style = ratatui_style.bg(anstyle_to_ratatui_color(bg));
23 }
24
25 ratatui_style = ratatui_style.add_modifier(effects_to_modifiers(style.get_effects()));
26 ratatui_style
27}
28
29pub fn inline_text_style_to_ratatui(
37 color: Option<AnstyleColor>,
38 bg_color: Option<AnstyleColor>,
39 effects: Effects,
40 fallback: Option<AnstyleColor>,
41) -> Style {
42 let mut resolved = Style::default();
43
44 if let Some(c) = color.or(fallback) {
45 resolved = resolved.fg(anstyle_to_ratatui_color(c));
46 }
47
48 if let Some(c) = bg_color {
49 resolved = resolved.bg(anstyle_to_ratatui_color(c));
50 }
51
52 resolved = resolved.add_modifier(effects_to_modifiers(effects));
53 resolved
54}
55
56pub fn effects_to_modifiers(effects: Effects) -> Modifier {
58 let mut modifier = Modifier::empty();
59
60 if effects.contains(Effects::BOLD) {
61 modifier.insert(Modifier::BOLD);
62 }
63 if effects.contains(Effects::DIMMED) {
64 modifier.insert(Modifier::DIM);
65 }
66 if effects.contains(Effects::ITALIC) {
67 modifier.insert(Modifier::ITALIC);
68 }
69 if effects.contains(Effects::UNDERLINE) {
70 modifier.insert(Modifier::UNDERLINED);
71 }
72 if effects.contains(Effects::BLINK) {
73 modifier.insert(Modifier::SLOW_BLINK);
74 }
75 if effects.contains(Effects::INVERT) {
76 modifier.insert(Modifier::REVERSED);
77 }
78 if effects.contains(Effects::STRIKETHROUGH) {
79 modifier.insert(Modifier::CROSSED_OUT);
80 }
81
82 modifier
83}
84
85pub fn fg_style(color: AnstyleColor) -> Style {
87 Style::default().fg(anstyle_to_ratatui_color(color))
88}
89
90pub fn bg_style(color: AnstyleColor) -> Style {
92 Style::default().bg(anstyle_to_ratatui_color(color))
93}
94
95pub fn fg_bg_style(fg: AnstyleColor, bg: AnstyleColor) -> Style {
97 Style::default()
98 .fg(anstyle_to_ratatui_color(fg))
99 .bg(anstyle_to_ratatui_color(bg))
100}
101
102pub fn with_effects(effects: Effects) -> Style {
104 Style::default().add_modifier(effects_to_modifiers(effects))
105}
106
107pub fn colored_with_effects(color: AnstyleColor, effects: Effects) -> Style {
109 Style::default()
110 .fg(anstyle_to_ratatui_color(color))
111 .add_modifier(effects_to_modifiers(effects))
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[test]
119 fn anstyle_style_with_fg() {
120 let input =
121 AnstyleStyle::new().fg_color(Some(AnstyleColor::Ansi(anstyle::AnsiColor::Green)));
122 let result = anstyle_to_ratatui_style(input);
123 assert_eq!(result.fg, Some(ratatui::style::Color::Green));
124 }
125
126 #[test]
127 fn anstyle_style_with_magenta_fg() {
128 let input =
130 AnstyleStyle::new().fg_color(Some(AnstyleColor::Ansi(anstyle::AnsiColor::Magenta)));
131 let result = anstyle_to_ratatui_style(input);
132 assert_eq!(result.fg, Some(ratatui::style::Color::Magenta));
133 }
134
135 #[test]
136 fn anstyle_style_with_bg() {
137 let input = AnstyleStyle::new().bg_color(Some(AnstyleColor::Ansi(anstyle::AnsiColor::Red)));
138 let result = anstyle_to_ratatui_style(input);
139 assert_eq!(result.bg, Some(ratatui::style::Color::Red));
140 }
141
142 #[test]
143 fn anstyle_style_with_effects() {
144 let input = AnstyleStyle::new().bold().italic();
145 let result = anstyle_to_ratatui_style(input);
146 assert!(result.add_modifier.contains(Modifier::BOLD));
147 assert!(result.add_modifier.contains(Modifier::ITALIC));
148 }
149
150 #[test]
151 fn inline_text_style_with_fallback() {
152 let result = inline_text_style_to_ratatui(
153 None,
154 None,
155 Effects::BOLD,
156 Some(AnstyleColor::Ansi(anstyle::AnsiColor::Cyan)),
157 );
158 assert_eq!(result.fg, Some(ratatui::style::Color::Cyan));
159 assert!(result.add_modifier.contains(Modifier::BOLD));
160 }
161
162 #[test]
163 fn inline_text_style_color_overrides_fallback() {
164 let result = inline_text_style_to_ratatui(
165 Some(AnstyleColor::Ansi(anstyle::AnsiColor::Red)),
166 None,
167 Effects::new(),
168 Some(AnstyleColor::Ansi(anstyle::AnsiColor::Cyan)),
169 );
170 assert_eq!(result.fg, Some(ratatui::style::Color::Red));
171 }
172
173 #[test]
174 fn effects_to_modifiers_all() {
175 let effects = Effects::BOLD
176 | Effects::DIMMED
177 | Effects::ITALIC
178 | Effects::UNDERLINE
179 | Effects::BLINK
180 | Effects::INVERT
181 | Effects::STRIKETHROUGH;
182 let modifier = effects_to_modifiers(effects);
183 assert!(modifier.contains(Modifier::BOLD));
184 assert!(modifier.contains(Modifier::DIM));
185 assert!(modifier.contains(Modifier::ITALIC));
186 assert!(modifier.contains(Modifier::UNDERLINED));
187 assert!(modifier.contains(Modifier::SLOW_BLINK));
188 assert!(modifier.contains(Modifier::REVERSED));
189 assert!(modifier.contains(Modifier::CROSSED_OUT));
190 }
191
192 #[test]
193 fn convenience_fg_style() {
194 let s = fg_style(AnstyleColor::Ansi(anstyle::AnsiColor::Blue));
195 assert_eq!(s.fg, Some(ratatui::style::Color::Blue));
196 }
197
198 #[test]
199 fn convenience_bg_style() {
200 let s = bg_style(AnstyleColor::Ansi(anstyle::AnsiColor::Red));
201 assert_eq!(s.bg, Some(ratatui::style::Color::Red));
202 }
203
204 #[test]
205 fn convenience_fg_bg_style() {
206 let s = fg_bg_style(
207 AnstyleColor::Ansi(anstyle::AnsiColor::Green),
208 AnstyleColor::Ansi(anstyle::AnsiColor::Black),
209 );
210 assert_eq!(s.fg, Some(ratatui::style::Color::Green));
211 assert_eq!(s.bg, Some(ratatui::style::Color::Black));
212 }
213
214 #[test]
215 fn convenience_colored_with_effects() {
216 let s = colored_with_effects(
217 AnstyleColor::Ansi(anstyle::AnsiColor::Yellow),
218 Effects::BOLD | Effects::ITALIC,
219 );
220 assert_eq!(s.fg, Some(ratatui::style::Color::Yellow));
221 assert!(s.add_modifier.contains(Modifier::BOLD));
222 assert!(s.add_modifier.contains(Modifier::ITALIC));
223 }
224}