1use std::collections::HashMap;
2
3use ratatui::style::{Color, Modifier, Style};
4use serde::Serialize;
5use termbg::Theme;
6
7use crate::app::App;
8use crate::{EditColorSettings, RegisterColorSettings};
9
10use super::app_settings::AppSettings;
11use super::theme_preference::ThemePreference;
12
13#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
14#[derive(EditColorSettings!)]
15#[derive(RegisterColorSettings!)]
16pub struct ColorSettings {
17 pub address_selected: Style,
18 pub address_default: Style,
19
20 pub hex_selected: Style,
21 pub hex_null: Style,
22 pub hex_alphanumeric: Style,
23 pub hex_symbol: Style,
24 pub hex_end_of_line: Style,
25 pub hex_whitespace: Style,
26 pub hex_current_instruction: Style,
27 pub hex_current_section: Style,
28 pub hex_default: Style,
29
30 pub pane_selected: Style,
31 pub pane: Style,
32
33 pub text_selected: Style,
34
35 pub assembly_symbol: Style,
36 pub assembly_selected: Style,
37 pub assembly_address: Style,
38 pub assembly_virtual_address: Style,
39 pub assembly_nop: Style,
40 pub assembly_bad: Style,
41 pub assembly_section: Style,
42 pub assembly_entry_point: Style,
43 pub assembly_comment: Style,
44 pub assembly_default: Style,
45
46 pub patch_patched_less_or_equal: Style,
47 pub patch_patched_greater: Style,
48 pub patch_old_instruction: Style,
49 pub patch_old_rest: Style,
50 pub patch_line_number: Style,
51
52 pub help_command: Style,
53 pub help_description: Style,
54
55 pub yes: Style,
56 pub yes_selected: Style,
57 pub no: Style,
58 pub no_selected: Style,
59 pub menu_text: Style,
60 pub menu_text_selected: Style,
61
62 pub insert_text_status: Style,
63
64 pub command_name: Style,
65 pub command_description: Style,
66 pub command_selected: Style,
67
68 pub path_dir: Style,
69 pub path_file: Style,
70 pub path_selected: Style,
71
72 pub log_info: Style,
73 pub log_debug: Style,
74 pub log_warning: Style,
75 pub log_error: Style,
76 pub log_message: Style,
77
78 pub status_bar: Style,
79 pub status_info: Style,
80 pub status_debug: Style,
81 pub status_warning: Style,
82 pub status_error: Style,
83
84 pub scrollbar: Style,
85 pub placeholder: Style,
86}
87
88impl ColorSettings {
89 pub fn get_default_theme(theme: Theme) -> Self {
90 match theme {
91 Theme::Light => Self::get_default_light_theme(),
92 Theme::Dark => Self::get_default_dark_theme(),
93 }
94 }
95
96 pub fn get_default_light_theme() -> Self {
97 let status_bar_bg = Color::Rgb(246, 184, 76);
98 let dark_yellow = Color::Rgb(243, 164, 27);
99 let light_brown = Color::Rgb(202, 123, 63);
100 let dark_orange = Color::Rgb(218, 152, 37);
101 let desaturated_dark_brown = Color::Rgb(98, 83, 75);
102 Self {
103 address_selected: Style::default().fg(Color::White).bg(Color::Black),
104 address_default: Style::default().fg(Color::Gray),
105
106 hex_selected: Style::default().fg(Color::White).bg(Color::Black),
107 hex_null: Style::default().fg(Color::Gray),
108 hex_alphanumeric: Style::default().fg(light_brown),
109 hex_symbol: Style::default().fg(light_brown).add_modifier(Modifier::DIM),
110 hex_end_of_line: Style::default().fg(Color::Red),
111 hex_whitespace: Style::default().fg(desaturated_dark_brown),
112 hex_current_instruction: Style::default().fg(Color::White).bg(dark_orange),
113 hex_current_section: Style::default().fg(Color::White).bg(dark_orange),
114 hex_default: Style::default(),
115
116 text_selected: Style::default().fg(Color::White).bg(Color::Black),
117 pane_selected: Style::default().fg(Color::LightGreen),
118 pane: Style::default().fg(Color::White),
119
120 assembly_symbol: Style::default().fg(Color::Green),
121 assembly_selected: Style::default().fg(Color::White).bg(Color::Black),
122 assembly_address: Style::default().fg(Color::Gray),
123 assembly_virtual_address: Style::default().fg(Color::Gray).add_modifier(Modifier::DIM),
124 assembly_nop: Style::default().fg(Color::Gray),
125 assembly_bad: Style::default().fg(Color::Red),
126 assembly_section: Style::default().fg(Color::Blue),
127 assembly_entry_point: Style::default().fg(dark_yellow),
128 assembly_comment: Style::default().fg(Color::LightGreen),
129 assembly_default: Style::default().fg(light_brown),
130
131 patch_patched_less_or_equal: Style::default().fg(Color::Green),
132 patch_patched_greater: Style::default().fg(dark_yellow),
133 patch_old_instruction: Style::default().fg(Color::Red),
134 patch_old_rest: Style::default().fg(Color::Gray),
135 patch_line_number: Style::default().fg(Color::Gray),
136
137 help_command: Style::default().fg(Color::Green),
138 help_description: Style::default().fg(Color::DarkGray),
139
140 yes: Style::default().fg(Color::Green),
141 yes_selected: Style::default().fg(Color::White).bg(Color::Green),
142 no: Style::default().fg(Color::Red),
143 no_selected: Style::default().fg(Color::White).bg(Color::Red),
144 menu_text: Style::default().fg(Color::Black),
145 menu_text_selected: Style::default().fg(Color::White).bg(Color::Black),
146
147 insert_text_status: Style::default().fg(Color::Black).bg(status_bar_bg),
148
149 command_name: Style::default().fg(Color::Green),
150 command_description: Style::default().fg(Color::DarkGray),
151 command_selected: Style::default().fg(Color::White).bg(Color::Black),
152
153 path_dir: Style::default().fg(Color::Blue),
154 path_file: Style::default().fg(dark_yellow),
155 path_selected: Style::default().fg(Color::White).bg(Color::Black),
156
157 log_info: Style::default().fg(Color::Blue),
158 log_debug: Style::default().fg(Color::Green),
159 log_warning: Style::default().fg(dark_yellow),
160 log_error: Style::default().fg(Color::Red),
161 log_message: Style::default().fg(Color::Black),
162
163 status_bar: Style::default().fg(Color::Black).bg(status_bar_bg),
164 status_info: Style::default().fg(Color::Blue).bg(status_bar_bg),
165 status_debug: Style::default().fg(Color::Green).bg(status_bar_bg),
166 status_warning: Style::default().fg(Color::Yellow).bg(status_bar_bg),
167 status_error: Style::default().fg(Color::Red).bg(status_bar_bg),
168
169 scrollbar: Style::default().fg(status_bar_bg).bg(Color::Gray),
170 placeholder: Style::default().fg(Color::Gray),
171 }
172 }
173
174 pub fn get_default_dark_theme() -> Self {
175 let status_bar_bg = Color::Rgb(255, 223, 168);
176 Self {
177 address_selected: Style::default().fg(Color::Black).bg(Color::White),
178 address_default: Style::default().fg(Color::DarkGray),
179
180 hex_selected: Style::default().fg(Color::Black).bg(Color::White),
181 hex_null: Style::default().fg(Color::DarkGray),
182 hex_alphanumeric: Style::default().fg(Color::Rgb(204, 152, 113)),
183 hex_symbol: Style::default()
184 .fg(Color::Rgb(204, 152, 113))
185 .add_modifier(Modifier::DIM),
186 hex_end_of_line: Style::default().fg(Color::LightRed),
187 hex_whitespace: Style::default().fg(Color::Rgb(244, 202, 183)),
188 hex_current_instruction: Style::default()
189 .fg(Color::Black)
190 .bg(Color::Rgb(215, 170, 92)),
191 hex_current_section: Style::default()
192 .fg(Color::Black)
193 .bg(Color::Rgb(215, 170, 92)),
194 hex_default: Style::default(),
195
196 text_selected: Style::default().fg(Color::Black).bg(Color::White),
197 pane_selected: Style::default().fg(Color::LightGreen),
198 pane: Style::default().fg(Color::White),
199
200 assembly_symbol: Style::default().fg(Color::LightGreen),
201 assembly_selected: Style::default().fg(Color::Black).bg(Color::White),
202 assembly_address: Style::default().fg(Color::DarkGray),
203 assembly_virtual_address: Style::default()
204 .fg(Color::DarkGray)
205 .add_modifier(Modifier::DIM),
206 assembly_nop: Style::default().fg(Color::DarkGray),
207 assembly_bad: Style::default().fg(Color::LightRed),
208 assembly_section: Style::default().fg(Color::LightBlue),
209 assembly_entry_point: Style::default().fg(Color::Yellow),
210 assembly_comment: Style::default().fg(Color::Green),
211 assembly_default: Style::default().fg(Color::Rgb(204, 152, 113)),
212
213 patch_patched_less_or_equal: Style::default().fg(Color::Green),
214 patch_patched_greater: Style::default().fg(Color::Yellow),
215 patch_old_instruction: Style::default().fg(Color::Red),
216 patch_old_rest: Style::default().fg(Color::DarkGray),
217 patch_line_number: Style::default().fg(Color::DarkGray),
218
219 help_command: Style::default().fg(Color::LightGreen),
220 help_description: Style::default().fg(Color::Gray),
221
222 yes: Style::default().fg(Color::Green),
223 yes_selected: Style::default().fg(Color::Black).bg(Color::Green),
224 no: Style::default().fg(Color::Red),
225 no_selected: Style::default().fg(Color::Black).bg(Color::Red),
226 menu_text: Style::default().fg(Color::White),
227 menu_text_selected: Style::default().fg(Color::Black).bg(Color::White),
228
229 insert_text_status: Style::default().fg(Color::Black).bg(status_bar_bg),
230
231 command_name: Style::default().fg(Color::LightGreen),
232 command_description: Style::default().fg(Color::Gray),
233 command_selected: Style::default().fg(Color::Black).bg(Color::White),
234
235 path_dir: Style::default().fg(Color::Blue),
236 path_file: Style::default().fg(Color::Yellow),
237 path_selected: Style::default().fg(Color::Black).bg(Color::White),
238
239 log_info: Style::default().fg(Color::LightBlue),
240 log_debug: Style::default().fg(Color::LightGreen),
241 log_warning: Style::default().fg(Color::Yellow),
242 log_error: Style::default().fg(Color::Red),
243 log_message: Style::default().fg(Color::White),
244
245 status_bar: Style::default().fg(Color::Black).bg(status_bar_bg),
246 status_info: Style::default().fg(Color::Blue).bg(status_bar_bg),
247 status_debug: Style::default().fg(Color::Green).bg(status_bar_bg),
248 status_warning: Style::default().fg(Color::Yellow).bg(status_bar_bg),
249 status_error: Style::default().fg(Color::Red).bg(status_bar_bg),
250
251 scrollbar: Style::default().fg(status_bar_bg).bg(Color::DarkGray),
252 placeholder: Style::default().fg(Color::DarkGray),
253 }
254 }
255
256 pub fn from_map(
257 map: &HashMap<String, Style>,
258 app_settings: &AppSettings,
259 terminal_theme: Theme,
260 ) -> Result<Self, String> {
261 let theme = match &app_settings.theme {
262 ThemePreference::Light => Theme::Light,
263 ThemePreference::Dark => Theme::Dark,
264 ThemePreference::Auto => terminal_theme,
265 };
266 let mut color_settings = Self::get_default_theme(theme);
267 color_settings
268 .edit_color_settings(map)
269 .map_err(|e| format!("Failed to load color settings: {}", e))?;
270 Ok(color_settings)
271 }
272}
273
274impl App {
275 pub(in crate::app) fn get_style_for_byte(color_settings: &ColorSettings, byte: u8) -> Style {
276 match byte
277 {
278 0x00 => color_settings.hex_null,
280 0x0A | 0x0C | 0x0D => color_settings.hex_end_of_line,
282 0x20 | 0x09 | 0x0B => color_settings.hex_whitespace,
284 0x30..=0x39 |
286 0x41..=0x5A |
288 0x61..=0x7A => color_settings.hex_alphanumeric,
290 0x20..=0x7E => color_settings.hex_symbol,
292 _ => color_settings.hex_default
293 }
294 }
295}