1use crate::theme::config::patch::ConfigFile;
13
14#[derive(Debug, Clone, PartialEq, Eq)]
17pub enum ValueKind {
18 Bool,
20 Enum {
23 choices: &'static [&'static str],
25 },
26 String,
28 Path,
31 Secret,
34 IntRange {
36 min: i64,
38 max: i64,
40 },
41 OptionalUnsignedOrAll,
44 Color,
46 MainPaneOrder,
50 KeyChord,
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub enum ReloadBehavior {
58 AutoReload,
61 AppliesOnSave,
65 RequiresRestart,
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub enum Sensitivity {
73 Normal,
75 Sensitive,
78}
79
80#[derive(Debug, Clone)]
82pub struct EditableSetting {
83 pub key: &'static str,
85 pub aliases: &'static [&'static str],
87 pub file: ConfigFile,
89 pub kind: ValueKind,
91 pub reload: ReloadBehavior,
93 pub sensitivity: Sensitivity,
95}
96
97impl EditableSetting {
98 #[must_use]
110 pub fn matches(&self, name: &str) -> bool {
111 let norm = normalize(name);
112 if normalize(self.key) == norm {
113 return true;
114 }
115 self.aliases.iter().any(|a| normalize(a) == norm)
116 }
117
118 #[must_use]
125 pub fn label_i18n_key(&self) -> String {
126 format!("app.modals.config_editor.settings.{}.label", self.key)
127 }
128
129 #[must_use]
136 pub fn summary_i18n_key(&self) -> String {
137 format!("app.modals.config_editor.settings.{}.summary", self.key)
138 }
139}
140
141fn normalize(s: &str) -> String {
149 s.trim().to_lowercase().replace(['.', '-', ' '], "_")
150}
151
152pub const EDITABLE_SETTINGS: &[EditableSetting] = &[
166 EditableSetting {
167 key: "sort_mode",
168 aliases: &["results_sort"],
169 file: ConfigFile::Settings,
170 kind: ValueKind::Enum {
171 choices: &[
172 "best_matches",
173 "alphabetical",
174 "official_first",
175 "aur_popularity",
176 ],
177 },
178 reload: ReloadBehavior::AppliesOnSave,
179 sensitivity: Sensitivity::Normal,
180 },
181 EditableSetting {
182 key: "show_install_pane",
183 aliases: &[],
184 file: ConfigFile::Settings,
185 kind: ValueKind::Bool,
186 reload: ReloadBehavior::AutoReload,
187 sensitivity: Sensitivity::Normal,
188 },
189 EditableSetting {
190 key: "show_search_history_pane",
191 aliases: &["show_recent_pane"],
192 file: ConfigFile::Settings,
193 kind: ValueKind::Bool,
194 reload: ReloadBehavior::AutoReload,
195 sensitivity: Sensitivity::Normal,
196 },
197 EditableSetting {
198 key: "mirror_count",
199 aliases: &[],
200 file: ConfigFile::Settings,
201 kind: ValueKind::IntRange { min: 1, max: 200 },
202 reload: ReloadBehavior::AppliesOnSave,
203 sensitivity: Sensitivity::Normal,
204 },
205 EditableSetting {
206 key: "news_max_age_days",
207 aliases: &[],
208 file: ConfigFile::Settings,
209 kind: ValueKind::OptionalUnsignedOrAll,
210 reload: ReloadBehavior::AppliesOnSave,
211 sensitivity: Sensitivity::Normal,
212 },
213 EditableSetting {
214 key: "clipboard_suffix",
215 aliases: &[],
216 file: ConfigFile::Settings,
217 kind: ValueKind::String,
218 reload: ReloadBehavior::AutoReload,
219 sensitivity: Sensitivity::Normal,
220 },
221 EditableSetting {
222 key: "preferred_terminal",
223 aliases: &[],
224 file: ConfigFile::Settings,
225 kind: ValueKind::String,
226 reload: ReloadBehavior::AppliesOnSave,
227 sensitivity: Sensitivity::Normal,
228 },
229 EditableSetting {
230 key: "privilege_mode",
231 aliases: &["privilege_tool", "priv_tool"],
232 file: ConfigFile::Settings,
233 kind: ValueKind::Enum {
234 choices: &["auto", "sudo", "doas"],
235 },
236 reload: ReloadBehavior::AppliesOnSave,
237 sensitivity: Sensitivity::Normal,
238 },
239 EditableSetting {
240 key: "main_pane_order",
241 aliases: &[],
242 file: ConfigFile::Settings,
243 kind: ValueKind::MainPaneOrder,
244 reload: ReloadBehavior::AppliesOnSave,
245 sensitivity: Sensitivity::Normal,
246 },
247 EditableSetting {
248 key: "virustotal_api_key",
249 aliases: &[],
250 file: ConfigFile::Settings,
251 kind: ValueKind::Secret,
252 reload: ReloadBehavior::AppliesOnSave,
253 sensitivity: Sensitivity::Sensitive,
254 },
255 EditableSetting {
257 key: "layout_left_pct",
258 aliases: &[],
259 file: ConfigFile::Settings,
260 kind: ValueKind::IntRange { min: 0, max: 100 },
261 reload: ReloadBehavior::AppliesOnSave,
262 sensitivity: Sensitivity::Normal,
263 },
264 EditableSetting {
265 key: "layout_center_pct",
266 aliases: &[],
267 file: ConfigFile::Settings,
268 kind: ValueKind::IntRange { min: 0, max: 100 },
269 reload: ReloadBehavior::AppliesOnSave,
270 sensitivity: Sensitivity::Normal,
271 },
272 EditableSetting {
273 key: "layout_right_pct",
274 aliases: &[],
275 file: ConfigFile::Settings,
276 kind: ValueKind::IntRange { min: 0, max: 100 },
277 reload: ReloadBehavior::AppliesOnSave,
278 sensitivity: Sensitivity::Normal,
279 },
280 EditableSetting {
282 key: "vertical_min_results",
283 aliases: &[],
284 file: ConfigFile::Settings,
285 kind: ValueKind::IntRange { min: 1, max: 200 },
286 reload: ReloadBehavior::AppliesOnSave,
287 sensitivity: Sensitivity::Normal,
288 },
289 EditableSetting {
290 key: "vertical_max_results",
291 aliases: &[],
292 file: ConfigFile::Settings,
293 kind: ValueKind::IntRange { min: 1, max: 200 },
294 reload: ReloadBehavior::AppliesOnSave,
295 sensitivity: Sensitivity::Normal,
296 },
297 EditableSetting {
298 key: "vertical_min_middle",
299 aliases: &[],
300 file: ConfigFile::Settings,
301 kind: ValueKind::IntRange { min: 1, max: 200 },
302 reload: ReloadBehavior::AppliesOnSave,
303 sensitivity: Sensitivity::Normal,
304 },
305 EditableSetting {
306 key: "vertical_max_middle",
307 aliases: &[],
308 file: ConfigFile::Settings,
309 kind: ValueKind::IntRange { min: 1, max: 200 },
310 reload: ReloadBehavior::AppliesOnSave,
311 sensitivity: Sensitivity::Normal,
312 },
313 EditableSetting {
314 key: "vertical_min_package_info",
315 aliases: &[],
316 file: ConfigFile::Settings,
317 kind: ValueKind::IntRange { min: 1, max: 200 },
318 reload: ReloadBehavior::AppliesOnSave,
319 sensitivity: Sensitivity::Normal,
320 },
321 EditableSetting {
323 key: "app_dry_run_default",
324 aliases: &[],
325 file: ConfigFile::Settings,
326 kind: ValueKind::Bool,
327 reload: ReloadBehavior::RequiresRestart,
328 sensitivity: Sensitivity::Normal,
329 },
330 EditableSetting {
331 key: "show_keybinds_footer",
332 aliases: &[],
333 file: ConfigFile::Settings,
334 kind: ValueKind::Bool,
335 reload: ReloadBehavior::AutoReload,
336 sensitivity: Sensitivity::Normal,
337 },
338 EditableSetting {
340 key: "search_startup_mode",
341 aliases: &[],
342 file: ConfigFile::Settings,
343 kind: ValueKind::Enum {
344 choices: &["insert_mode", "normal_mode"],
345 },
346 reload: ReloadBehavior::RequiresRestart,
347 sensitivity: Sensitivity::Normal,
348 },
349 EditableSetting {
350 key: "fuzzy_search",
351 aliases: &[],
352 file: ConfigFile::Settings,
353 kind: ValueKind::Bool,
354 reload: ReloadBehavior::AppliesOnSave,
355 sensitivity: Sensitivity::Normal,
356 },
357 EditableSetting {
358 key: "installed_packages_mode",
359 aliases: &[],
360 file: ConfigFile::Settings,
361 kind: ValueKind::Enum {
362 choices: &["leaf", "all"],
363 },
364 reload: ReloadBehavior::AppliesOnSave,
365 sensitivity: Sensitivity::Normal,
366 },
367 EditableSetting {
369 key: "skip_preflight",
370 aliases: &[],
371 file: ConfigFile::Settings,
372 kind: ValueKind::Bool,
373 reload: ReloadBehavior::AppliesOnSave,
374 sensitivity: Sensitivity::Normal,
375 },
376 EditableSetting {
377 key: "use_passwordless_sudo",
378 aliases: &[],
379 file: ConfigFile::Settings,
380 kind: ValueKind::Bool,
381 reload: ReloadBehavior::AppliesOnSave,
382 sensitivity: Sensitivity::Normal,
383 },
384 EditableSetting {
385 key: "auth_mode",
386 aliases: &[],
387 file: ConfigFile::Settings,
388 kind: ValueKind::Enum {
389 choices: &["prompt", "passwordless_only", "interactive"],
390 },
391 reload: ReloadBehavior::AppliesOnSave,
392 sensitivity: Sensitivity::Normal,
393 },
394 EditableSetting {
396 key: "selected_countries",
397 aliases: &[],
398 file: ConfigFile::Settings,
399 kind: ValueKind::String,
400 reload: ReloadBehavior::AppliesOnSave,
401 sensitivity: Sensitivity::Normal,
402 },
403 EditableSetting {
405 key: "scan_do_clamav",
406 aliases: &[],
407 file: ConfigFile::Settings,
408 kind: ValueKind::Bool,
409 reload: ReloadBehavior::AutoReload,
410 sensitivity: Sensitivity::Normal,
411 },
412 EditableSetting {
413 key: "scan_do_trivy",
414 aliases: &[],
415 file: ConfigFile::Settings,
416 kind: ValueKind::Bool,
417 reload: ReloadBehavior::AutoReload,
418 sensitivity: Sensitivity::Normal,
419 },
420 EditableSetting {
421 key: "scan_do_semgrep",
422 aliases: &[],
423 file: ConfigFile::Settings,
424 kind: ValueKind::Bool,
425 reload: ReloadBehavior::AutoReload,
426 sensitivity: Sensitivity::Normal,
427 },
428 EditableSetting {
429 key: "scan_do_shellcheck",
430 aliases: &[],
431 file: ConfigFile::Settings,
432 kind: ValueKind::Bool,
433 reload: ReloadBehavior::AutoReload,
434 sensitivity: Sensitivity::Normal,
435 },
436 EditableSetting {
437 key: "scan_do_virustotal",
438 aliases: &[],
439 file: ConfigFile::Settings,
440 kind: ValueKind::Bool,
441 reload: ReloadBehavior::AutoReload,
442 sensitivity: Sensitivity::Normal,
443 },
444 EditableSetting {
445 key: "scan_do_custom",
446 aliases: &[],
447 file: ConfigFile::Settings,
448 kind: ValueKind::Bool,
449 reload: ReloadBehavior::AutoReload,
450 sensitivity: Sensitivity::Normal,
451 },
452 EditableSetting {
453 key: "scan_do_sleuth",
454 aliases: &[],
455 file: ConfigFile::Settings,
456 kind: ValueKind::Bool,
457 reload: ReloadBehavior::AutoReload,
458 sensitivity: Sensitivity::Normal,
459 },
460 EditableSetting {
462 key: "pkgbuild_shellcheck_exclude",
463 aliases: &[],
464 file: ConfigFile::Settings,
465 kind: ValueKind::String,
466 reload: ReloadBehavior::AppliesOnSave,
467 sensitivity: Sensitivity::Normal,
468 },
469 EditableSetting {
470 key: "pkgbuild_checks_show_raw_output",
471 aliases: &[],
472 file: ConfigFile::Settings,
473 kind: ValueKind::Bool,
474 reload: ReloadBehavior::AutoReload,
475 sensitivity: Sensitivity::Normal,
476 },
477 EditableSetting {
479 key: "news_read_symbol",
480 aliases: &[],
481 file: ConfigFile::Settings,
482 kind: ValueKind::String,
483 reload: ReloadBehavior::AutoReload,
484 sensitivity: Sensitivity::Normal,
485 },
486 EditableSetting {
487 key: "news_unread_symbol",
488 aliases: &[],
489 file: ConfigFile::Settings,
490 kind: ValueKind::String,
491 reload: ReloadBehavior::AutoReload,
492 sensitivity: Sensitivity::Normal,
493 },
494 EditableSetting {
495 key: "news_filter_show_arch_news",
496 aliases: &[],
497 file: ConfigFile::Settings,
498 kind: ValueKind::Bool,
499 reload: ReloadBehavior::AppliesOnSave,
500 sensitivity: Sensitivity::Normal,
501 },
502 EditableSetting {
503 key: "news_filter_show_advisories",
504 aliases: &[],
505 file: ConfigFile::Settings,
506 kind: ValueKind::Bool,
507 reload: ReloadBehavior::AppliesOnSave,
508 sensitivity: Sensitivity::Normal,
509 },
510 EditableSetting {
511 key: "news_filter_show_pkg_updates",
512 aliases: &[],
513 file: ConfigFile::Settings,
514 kind: ValueKind::Bool,
515 reload: ReloadBehavior::AppliesOnSave,
516 sensitivity: Sensitivity::Normal,
517 },
518 EditableSetting {
519 key: "news_filter_show_aur_updates",
520 aliases: &[],
521 file: ConfigFile::Settings,
522 kind: ValueKind::Bool,
523 reload: ReloadBehavior::AppliesOnSave,
524 sensitivity: Sensitivity::Normal,
525 },
526 EditableSetting {
527 key: "news_filter_show_aur_comments",
528 aliases: &[],
529 file: ConfigFile::Settings,
530 kind: ValueKind::Bool,
531 reload: ReloadBehavior::AppliesOnSave,
532 sensitivity: Sensitivity::Normal,
533 },
534 EditableSetting {
535 key: "news_filter_installed_only",
536 aliases: &[],
537 file: ConfigFile::Settings,
538 kind: ValueKind::Bool,
539 reload: ReloadBehavior::AppliesOnSave,
540 sensitivity: Sensitivity::Normal,
541 },
542 EditableSetting {
544 key: "startup_news_configured",
545 aliases: &[],
546 file: ConfigFile::Settings,
547 kind: ValueKind::Bool,
548 reload: ReloadBehavior::AppliesOnSave,
549 sensitivity: Sensitivity::Normal,
550 },
551 EditableSetting {
552 key: "startup_news_show_arch_news",
553 aliases: &[],
554 file: ConfigFile::Settings,
555 kind: ValueKind::Bool,
556 reload: ReloadBehavior::AppliesOnSave,
557 sensitivity: Sensitivity::Normal,
558 },
559 EditableSetting {
560 key: "startup_news_show_advisories",
561 aliases: &[],
562 file: ConfigFile::Settings,
563 kind: ValueKind::Bool,
564 reload: ReloadBehavior::AppliesOnSave,
565 sensitivity: Sensitivity::Normal,
566 },
567 EditableSetting {
568 key: "startup_news_show_aur_updates",
569 aliases: &[],
570 file: ConfigFile::Settings,
571 kind: ValueKind::Bool,
572 reload: ReloadBehavior::AppliesOnSave,
573 sensitivity: Sensitivity::Normal,
574 },
575 EditableSetting {
576 key: "startup_news_show_aur_comments",
577 aliases: &[],
578 file: ConfigFile::Settings,
579 kind: ValueKind::Bool,
580 reload: ReloadBehavior::AppliesOnSave,
581 sensitivity: Sensitivity::Normal,
582 },
583 EditableSetting {
584 key: "startup_news_show_pkg_updates",
585 aliases: &[],
586 file: ConfigFile::Settings,
587 kind: ValueKind::Bool,
588 reload: ReloadBehavior::AppliesOnSave,
589 sensitivity: Sensitivity::Normal,
590 },
591 EditableSetting {
592 key: "startup_news_max_age_days",
593 aliases: &[],
594 file: ConfigFile::Settings,
595 kind: ValueKind::OptionalUnsignedOrAll,
596 reload: ReloadBehavior::AppliesOnSave,
597 sensitivity: Sensitivity::Normal,
598 },
599 EditableSetting {
601 key: "package_marker",
602 aliases: &[],
603 file: ConfigFile::Settings,
604 kind: ValueKind::Enum {
605 choices: &["full_line", "front", "end"],
606 },
607 reload: ReloadBehavior::AutoReload,
608 sensitivity: Sensitivity::Normal,
609 },
610 EditableSetting {
611 key: "locale",
612 aliases: &[],
613 file: ConfigFile::Settings,
614 kind: ValueKind::String,
615 reload: ReloadBehavior::RequiresRestart,
616 sensitivity: Sensitivity::Normal,
617 },
618 EditableSetting {
619 key: "updates_refresh_interval",
620 aliases: &[],
621 file: ConfigFile::Settings,
622 kind: ValueKind::IntRange { min: 1, max: 86400 },
623 reload: ReloadBehavior::AppliesOnSave,
624 sensitivity: Sensitivity::Normal,
625 },
626 EditableSetting {
627 key: "use_terminal_theme",
628 aliases: &[],
629 file: ConfigFile::Settings,
630 kind: ValueKind::Bool,
631 reload: ReloadBehavior::RequiresRestart,
632 sensitivity: Sensitivity::Normal,
633 },
634 EditableSetting {
636 key: "aur_vote_enabled",
637 aliases: &[],
638 file: ConfigFile::Settings,
639 kind: ValueKind::Bool,
640 reload: ReloadBehavior::AutoReload,
641 sensitivity: Sensitivity::Normal,
642 },
643 EditableSetting {
644 key: "aur_vote_ssh_timeout_seconds",
645 aliases: &[],
646 file: ConfigFile::Settings,
647 kind: ValueKind::IntRange { min: 1, max: 600 },
648 reload: ReloadBehavior::AutoReload,
649 sensitivity: Sensitivity::Normal,
650 },
651 EditableSetting {
652 key: "aur_vote_ssh_command",
653 aliases: &[],
654 file: ConfigFile::Settings,
655 kind: ValueKind::String,
656 reload: ReloadBehavior::AutoReload,
657 sensitivity: Sensitivity::Normal,
658 },
659];
660
661pub const EDITABLE_KEYBINDS: &[EditableSetting] = &[
677 keybind_entry("keybind_help", &["keybind_help_overlay"]),
679 keybind_entry(
680 "keybind_toggle_config",
681 &["keybind_config_menu", "keybind_config_lists"],
682 ),
683 keybind_entry("keybind_toggle_options", &["keybind_options_menu"]),
684 keybind_entry("keybind_toggle_panels", &["keybind_panels_menu"]),
685 keybind_entry(
686 "keybind_reload_config",
687 &["keybind_reload_theme", "keybind_reload"],
688 ),
689 keybind_entry("keybind_exit", &["keybind_quit"]),
690 keybind_entry(
691 "keybind_show_pkgbuild",
692 &["keybind_pkgbuild", "keybind_toggle_pkgbuild"],
693 ),
694 keybind_entry(
695 "keybind_comments_toggle",
696 &["keybind_show_comments", "keybind_toggle_comments"],
697 ),
698 keybind_entry(
699 "keybind_run_pkgbuild_checks",
700 &["keybind_pkgbuild_checks", "keybind_toggle_pkgbuild_checks"],
701 ),
702 keybind_entry(
703 "keybind_cycle_pkgbuild_sections",
704 &[
705 "keybind_pkgbuild_section_cycle",
706 "keybind_pkgbuild_next_section",
707 ],
708 ),
709 keybind_entry("keybind_change_sort", &["keybind_sort"]),
710 keybind_entry(
711 "keybind_pane_next",
712 &["keybind_next_pane", "keybind_switch_pane"],
713 ),
714 keybind_entry("keybind_pane_left", &[]),
715 keybind_entry("keybind_pane_right", &[]),
716 keybind_entry("keybind_toggle_fuzzy", &["keybind_fuzzy_toggle"]),
717 keybind_entry("keybind_search_move_up", &[]),
719 keybind_entry("keybind_search_move_down", &[]),
720 keybind_entry("keybind_search_page_up", &[]),
721 keybind_entry("keybind_search_page_down", &[]),
722 keybind_entry("keybind_search_add", &[]),
723 keybind_entry("keybind_search_install", &[]),
724 keybind_entry("keybind_search_focus_left", &[]),
725 keybind_entry("keybind_search_focus_right", &[]),
726 keybind_entry("keybind_search_backspace", &[]),
727 keybind_entry("keybind_search_insert_clear", &[]),
728 keybind_entry("keybind_search_normal_toggle", &[]),
730 keybind_entry("keybind_search_normal_insert", &[]),
731 keybind_entry("keybind_search_normal_select_left", &[]),
732 keybind_entry("keybind_search_normal_select_right", &[]),
733 keybind_entry("keybind_search_normal_delete", &[]),
734 keybind_entry("keybind_search_normal_clear", &[]),
735 keybind_entry(
736 "keybind_search_normal_open_status",
737 &["keybind_normal_open_status", "keybind_open_status"],
738 ),
739 keybind_entry("keybind_search_normal_import", &[]),
740 keybind_entry("keybind_search_normal_export", &[]),
741 keybind_entry("keybind_search_normal_updates", &[]),
742 keybind_entry("keybind_recent_move_up", &[]),
744 keybind_entry("keybind_recent_move_down", &[]),
745 keybind_entry("keybind_recent_find", &[]),
746 keybind_entry("keybind_recent_use", &[]),
747 keybind_entry("keybind_recent_add", &[]),
748 keybind_entry("keybind_recent_to_search", &[]),
749 keybind_entry("keybind_recent_focus_right", &[]),
750 keybind_entry("keybind_recent_remove", &[]),
751 keybind_entry("keybind_recent_clear", &[]),
752 keybind_entry("keybind_install_move_up", &[]),
754 keybind_entry("keybind_install_move_down", &[]),
755 keybind_entry("keybind_install_confirm", &[]),
756 keybind_entry("keybind_install_remove", &[]),
757 keybind_entry("keybind_install_clear", &[]),
758 keybind_entry("keybind_install_find", &[]),
759 keybind_entry("keybind_install_to_search", &[]),
760 keybind_entry("keybind_install_focus_left", &[]),
761 keybind_entry("keybind_news_mark_read", &[]),
763 keybind_entry("keybind_news_mark_all_read", &[]),
764 keybind_entry("keybind_news_feed_mark_read", &[]),
765 keybind_entry("keybind_news_feed_mark_unread", &[]),
766 keybind_entry("keybind_news_feed_toggle_read", &[]),
767];
768
769pub const EDITABLE_THEME: &[EditableSetting] = &[
786 theme_entry("background_base", &["base", "background"]),
787 theme_entry("background_mantle", &["mantle"]),
788 theme_entry("background_crust", &["crust"]),
789 theme_entry("surface_level1", &["surface1", "surface_1"]),
790 theme_entry("surface_level2", &["surface2", "surface_2"]),
791 theme_entry("overlay_primary", &["overlay1", "border_primary"]),
792 theme_entry("overlay_secondary", &["overlay2", "border_secondary"]),
793 theme_entry("text_primary", &["text"]),
794 theme_entry("text_secondary", &["subtext0"]),
795 theme_entry("text_tertiary", &["subtext1"]),
796 theme_entry("accent_interactive", &["sapphire", "accent_info"]),
797 theme_entry("accent_heading", &["mauve", "accent_primary"]),
798 theme_entry("semantic_success", &["green"]),
799 theme_entry("semantic_warning", &["yellow"]),
800 theme_entry("semantic_error", &["red"]),
801 theme_entry("accent_emphasis", &["lavender", "accent_border"]),
802];
803
804const fn theme_entry(key: &'static str, aliases: &'static [&'static str]) -> EditableSetting {
814 EditableSetting {
815 key,
816 aliases,
817 file: ConfigFile::Theme,
818 kind: ValueKind::Color,
819 reload: ReloadBehavior::AppliesOnSave,
820 sensitivity: Sensitivity::Normal,
821 }
822}
823
824const fn keybind_entry(key: &'static str, aliases: &'static [&'static str]) -> EditableSetting {
835 EditableSetting {
836 key,
837 aliases,
838 file: ConfigFile::Keybinds,
839 kind: ValueKind::KeyChord,
840 reload: ReloadBehavior::AppliesOnSave,
841 sensitivity: Sensitivity::Normal,
842 }
843}
844
845#[must_use]
853pub fn find_setting(name: &str) -> Option<&'static EditableSetting> {
854 EDITABLE_SETTINGS
855 .iter()
856 .chain(EDITABLE_KEYBINDS.iter())
857 .chain(EDITABLE_THEME.iter())
858 .find(|s| s.matches(name))
859}
860
861#[must_use]
869pub fn settings_for(file: ConfigFile) -> Vec<&'static EditableSetting> {
870 EDITABLE_SETTINGS
871 .iter()
872 .chain(EDITABLE_KEYBINDS.iter())
873 .chain(EDITABLE_THEME.iter())
874 .filter(|s| s.file == file)
875 .collect()
876}
877
878#[must_use]
892pub fn keybind_scope(key: &str) -> &'static str {
893 if key.starts_with("keybind_search_normal_") {
894 "search_normal"
895 } else if key.starts_with("keybind_search_") {
896 "search"
897 } else if key.starts_with("keybind_recent_") {
898 "recent"
899 } else if key.starts_with("keybind_install_") {
900 "install"
901 } else if key.starts_with("keybind_news_") {
902 "news"
903 } else {
904 "global"
905 }
906}
907
908#[cfg(test)]
909mod tests {
910 use super::*;
911
912 #[test]
913 fn keys_are_unique_after_normalization() {
914 let mut seen = std::collections::HashSet::new();
915 for entry in EDITABLE_SETTINGS {
916 let norm = normalize(entry.key);
917 assert!(
918 seen.insert(norm.clone()),
919 "duplicate key in EDITABLE_SETTINGS: {norm}"
920 );
921 }
922 }
923
924 #[test]
925 fn aliases_resolve_to_primary() {
926 let s = find_setting("show_recent_pane").expect("alias should resolve");
927 assert_eq!(s.key, "show_search_history_pane");
928
929 let s = find_setting("Results.Sort").expect("alias is normalized");
930 assert_eq!(s.key, "sort_mode");
931 }
932
933 #[test]
934 fn enum_choices_are_non_empty() {
935 for entry in EDITABLE_SETTINGS {
936 if let ValueKind::Enum { choices } = entry.kind {
937 assert!(
938 !choices.is_empty(),
939 "{} declares Enum without choices",
940 entry.key
941 );
942 }
943 }
944 }
945
946 #[test]
947 fn int_range_is_well_formed() {
948 for entry in EDITABLE_SETTINGS {
949 if let ValueKind::IntRange { min, max } = entry.kind {
950 assert!(
951 min <= max,
952 "{} declares inverted IntRange: {min}..{max}",
953 entry.key
954 );
955 }
956 }
957 }
958
959 #[test]
960 fn settings_for_filters_by_file() {
961 let only_settings = settings_for(ConfigFile::Settings);
962 assert!(!only_settings.is_empty());
963 for s in only_settings {
964 assert_eq!(s.file, ConfigFile::Settings);
965 }
966 let only_keybinds = settings_for(ConfigFile::Keybinds);
968 assert!(!only_keybinds.is_empty());
969 for s in only_keybinds {
970 assert_eq!(s.file, ConfigFile::Keybinds);
971 assert!(matches!(s.kind, ValueKind::KeyChord));
972 }
973 let only_theme = settings_for(ConfigFile::Theme);
974 assert_eq!(only_theme.len(), 16, "one row per required canonical color");
975 for s in only_theme {
976 assert_eq!(s.file, ConfigFile::Theme);
977 assert!(matches!(s.kind, ValueKind::Color));
978 }
979 assert!(settings_for(ConfigFile::Repos).is_empty());
980 }
981
982 #[test]
983 fn theme_keys_are_unique_and_aliases_resolve() {
984 let mut seen = std::collections::HashSet::new();
985 for entry in EDITABLE_THEME {
986 let norm = normalize(entry.key);
987 assert!(
988 seen.insert(norm.clone()),
989 "duplicate key in EDITABLE_THEME: {norm}"
990 );
991 }
992 let s = find_setting("base").expect("canonical alias should resolve");
993 assert_eq!(s.key, "background_base");
994 let s = find_setting("mauve").expect("canonical alias should resolve");
995 assert_eq!(s.key, "accent_heading");
996 }
997
998 #[test]
999 fn keybind_keys_are_unique_after_normalization() {
1000 let mut seen = std::collections::HashSet::new();
1001 for entry in EDITABLE_KEYBINDS {
1002 let norm = normalize(entry.key);
1003 assert!(
1004 seen.insert(norm.clone()),
1005 "duplicate key in EDITABLE_KEYBINDS: {norm}"
1006 );
1007 }
1008 }
1009
1010 #[test]
1011 fn keybind_aliases_resolve_to_primary() {
1012 let s = find_setting("keybind_help_overlay").expect("alias should resolve");
1013 assert_eq!(s.key, "keybind_help");
1014 let s = find_setting("keybind_open_status").expect("alias should resolve");
1015 assert_eq!(s.key, "keybind_search_normal_open_status");
1016 }
1017
1018 #[test]
1019 fn keybind_scope_groups_by_prefix() {
1020 assert_eq!(keybind_scope("keybind_help"), "global");
1021 assert_eq!(keybind_scope("keybind_pane_next"), "global");
1022 assert_eq!(keybind_scope("keybind_search_move_up"), "search");
1023 assert_eq!(
1024 keybind_scope("keybind_search_normal_toggle"),
1025 "search_normal"
1026 );
1027 assert_eq!(keybind_scope("keybind_recent_remove"), "recent");
1028 assert_eq!(keybind_scope("keybind_install_remove"), "install");
1029 assert_eq!(keybind_scope("keybind_news_mark_read"), "news");
1030 }
1031}