1use matchmaker_partial_macros::partial;
5
6pub use crate::config_types::*;
7pub use crate::utils::{Percentage, serde::StringOrVec};
8
9use crate::{
10 MAX_SPLITS,
11 tui::IoStream,
12 utils::serde::{escaped_opt_char, escaped_opt_string, serde_duration_ms},
13};
14
15use cba::serde::transform::{camelcase_normalized, camelcase_normalized_option};
16use ratatui::{
17 style::{Color, Modifier, Style},
18 text::Span,
19 widgets::{BorderType, Borders},
20};
21
22use serde::{Deserialize, Serialize};
23
24#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
28#[partial(recurse, path, derive(Debug, Deserialize))]
29pub struct MatcherConfig {
30 #[serde(flatten)]
31 #[partial(skip)]
32 pub matcher: NucleoMatcherConfig,
33 #[serde(flatten)]
34 pub worker: WorkerConfig,
35}
36
37#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
41#[serde(default)]
42#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
43pub struct WorkerConfig {
44 #[serde(alias = "sort")]
46 pub sort_threshold: u32,
47 #[partial(alias = "r")]
49 pub raw: bool,
50 pub track: bool,
52 pub reverse: bool, }
55
56#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
59#[serde(default, deny_unknown_fields)]
60#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
61pub struct StartConfig {
62 #[serde(deserialize_with = "escaped_opt_char")]
63 #[partial(alias = "is")]
64 pub input_separator: Option<char>,
65 #[serde(deserialize_with = "escaped_opt_string")]
66 #[partial(alias = "os")]
67 pub output_separator: Option<String>,
68
69 #[partial(alias = "ot")]
71 #[serde(alias = "output")]
72 pub output_template: Option<String>,
73
74 #[partial(alias = "cmd", alias = "x")]
76 pub command: String,
77 #[partial(alias = "ax")]
79 pub additional_commands: Vec<String>,
80 pub sync: bool,
81
82 #[partial(alias = "a")]
84 pub ansi: bool,
85 #[partial(alias = "t")]
87 pub trim: bool,
88}
89
90#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
92#[serde(default, deny_unknown_fields)]
93#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
94pub struct ExitConfig {
95 pub select_1: bool,
97 pub allow_empty: bool,
99 pub abort_empty: bool,
101 pub last_key_path: Option<std::path::PathBuf>,
104}
105
106#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
108#[serde(default, deny_unknown_fields)]
109#[partial(recurse, path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
110pub struct RenderConfig {
111 pub ui: UiConfig,
113 #[partial(alias = "i")]
115 pub input: InputConfig,
116 #[partial(alias = "r")]
118 pub results: ResultsConfig,
119
120 pub status: StatusConfig,
122 #[partial(alias = "p")]
124 pub preview: PreviewConfig,
125 #[partial(alias = "f")]
126 pub footer: DisplayConfig,
127 #[partial(alias = "h")]
128 pub header: DisplayConfig,
129}
130
131impl RenderConfig {
132 pub fn tick_rate(&self) -> u8 {
133 self.ui.tick_rate
134 }
135}
136
137#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
139#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
140#[serde(default, deny_unknown_fields)]
141pub struct TerminalConfig {
142 pub stream: IoStream, pub restore_fullscreen: bool,
144 pub redraw_on_resize: bool,
145 pub extended_keys: bool,
147 #[serde(with = "serde_duration_ms")]
148 pub sleep_ms: std::time::Duration, #[serde(flatten)]
150 #[partial(recurse)]
151 pub layout: Option<TerminalLayoutSettings>, pub clear_on_exit: bool,
153 pub move_up_on_exit: bool,
155}
156
157impl Default for TerminalConfig {
158 fn default() -> Self {
159 Self {
160 stream: IoStream::default(),
161 restore_fullscreen: true,
162 redraw_on_resize: bool::default(),
163 sleep_ms: std::time::Duration::default(),
164 layout: Option::default(),
165 extended_keys: true,
166 clear_on_exit: true,
167 move_up_on_exit: false,
168 }
169 }
170}
171
172#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
174#[serde(default, deny_unknown_fields)]
175#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
176pub struct UiConfig {
177 #[partial(recurse)]
178 pub border: BorderSetting,
179 pub tick_rate: u8, }
181
182impl Default for UiConfig {
183 fn default() -> Self {
184 Self {
185 border: Default::default(),
186 tick_rate: 60,
187 }
188 }
189}
190
191#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
193#[serde(default, deny_unknown_fields)]
194#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
195pub struct InputConfig {
196 #[partial(recurse)]
197 pub border: BorderSetting,
198
199 #[serde(deserialize_with = "camelcase_normalized")]
201 pub fg: Color,
202 pub bg: Color,
203 pub modifier: Modifier,
205
206 #[serde(deserialize_with = "camelcase_normalized")]
207 pub prompt_fg: Color,
208 pub prompt_bg: Color,
209 pub prompt_modifier: Modifier,
211
212 #[serde(deserialize_with = "deserialize_string_or_char_as_double_width")]
214 pub prompt: String,
215 pub cursor: CursorSetting,
217
218 #[partial(alias = "i")]
220 pub initial: String,
221
222 pub scroll_padding: bool,
224}
225
226impl Default for InputConfig {
227 fn default() -> Self {
228 Self {
229 border: Default::default(),
230 fg: Default::default(),
231 bg: Default::default(),
232 modifier: Default::default(),
233 prompt_fg: Default::default(),
234 prompt_bg: Default::default(),
235 prompt_modifier: Default::default(),
236 prompt: "> ".to_string(),
237 cursor: Default::default(),
238 initial: Default::default(),
239
240 scroll_padding: true,
241 }
242 }
243}
244
245impl InputConfig {
246 pub fn text_style(&self) -> Style {
247 Style::default()
248 .fg(self.fg)
249 .bg(self.bg)
250 .remove_modifier(Modifier::all())
251 .add_modifier(self.modifier)
252 }
253
254 pub fn prompt_style(&self) -> Style {
255 Style::default()
256 .fg(self.prompt_fg)
257 .bg(self.prompt_bg)
258 .add_modifier(self.prompt_modifier)
259 }
260}
261
262#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
263#[serde(default, deny_unknown_fields)]
264#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
265pub struct OverlayConfig {
266 #[partial(recurse)]
267 pub border: BorderSetting,
268 pub outer_dim: bool,
269 pub layout: OverlayLayoutSettings,
270}
271
272#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
273#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
274pub struct OverlayLayoutSettings {
275 #[partial(alias = "p")]
277 pub percentage: [Percentage; 2],
278 pub min: [u16; 2],
280 pub max: [u16; 2],
282
283 pub y_offset: Percentage,
285}
286
287impl Default for OverlayLayoutSettings {
288 fn default() -> Self {
289 Self {
290 percentage: [Percentage::new(60), Percentage::new(30)],
291 min: [10, 10],
292 max: [200, 30],
293 y_offset: Percentage::new(55),
294 }
295 }
296}
297
298#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
301#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
302#[serde(default, deny_unknown_fields)]
303pub struct AutoscrollSettings {
304 #[partial(alias = "i")]
306 pub initial_preserved: usize,
307 #[partial(alias = "a")]
309 pub enabled: bool,
310 #[partial(alias = "c")]
312 pub context: usize,
313 #[partial(alias = "e")]
315 pub end: bool,
316}
317
318impl Default for AutoscrollSettings {
319 fn default() -> Self {
320 Self {
321 initial_preserved: 0,
322 enabled: true,
323 context: 4,
324 end: false,
325 }
326 }
327}
328
329#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
330#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
331#[serde(default, deny_unknown_fields)]
332pub struct ResultsConfig {
333 #[partial(recurse)]
334 pub border: BorderSetting,
335
336 #[serde(deserialize_with = "deserialize_string_or_char_as_double_width")]
338 pub multi_prefix: String,
339 pub default_prefix: String,
340
341 pub multi: bool,
343
344 #[serde(deserialize_with = "camelcase_normalized")]
346 pub fg: Color,
347 #[serde(deserialize_with = "camelcase_normalized")]
348 pub bg: Color,
349 pub modifier: Modifier,
351
352 #[serde(deserialize_with = "camelcase_normalized")]
354 pub inactive_fg: Color,
355 #[serde(deserialize_with = "camelcase_normalized")]
356 pub inactive_bg: Color,
357 pub inactive_modifier: Modifier,
359
360 #[serde(deserialize_with = "camelcase_normalized")]
362 pub inactive_current_fg: Color,
363 #[serde(deserialize_with = "camelcase_normalized")]
364 pub inactive_current_bg: Color,
365 pub inactive_current_modifier: Modifier,
367
368 #[serde(deserialize_with = "camelcase_normalized")]
369 pub match_fg: Color,
370 pub match_modifier: Modifier,
372
373 #[serde(deserialize_with = "camelcase_normalized")]
375 pub current_fg: Color,
376 #[serde(deserialize_with = "camelcase_normalized")]
378 pub current_bg: Color,
379 pub current_modifier: Modifier,
382
383 #[serde(deserialize_with = "camelcase_normalized")]
388 pub row_connection: RowConnectionStyle,
389
390 #[partial(alias = "c")]
392 #[serde(alias = "cycle")]
393 pub scroll_wrap: bool,
394 #[partial(alias = "sp")]
395 pub scroll_padding: u16,
396 #[partial(alias = "r")]
397 pub reverse: Option<bool>,
398
399 #[partial(alias = "w")]
401 pub wrap: bool,
402 pub min_wrap_width: u16,
403
404 #[partial(recurse, alias = "a")]
406 pub autoscroll: AutoscrollSettings,
407
408 pub column_spacing: Count,
412 pub current_prefix: String,
413
414 #[partial(alias = "ra")]
416 pub right_align_last: bool,
417
418 #[partial(alias = "v")]
419 #[serde(alias = "vertical")]
420 pub stacked_columns: bool,
421
422 #[serde(alias = "hr")]
423 #[serde(deserialize_with = "camelcase_normalized")]
424 pub horizontal_separator: HorizontalSeparator,
425}
426
427impl Default for ResultsConfig {
428 fn default() -> Self {
429 ResultsConfig {
430 border: Default::default(),
431
432 multi_prefix: "▌ ".to_string(),
433 default_prefix: Default::default(),
434 multi: true,
435
436 fg: Default::default(),
437 modifier: Default::default(),
438 bg: Default::default(),
439
440 inactive_fg: Default::default(),
441 inactive_modifier: Default::default(),
442 inactive_bg: Default::default(),
443
444 inactive_current_fg: Color::DarkGray,
445 inactive_current_modifier: Default::default(),
446 inactive_current_bg: Color::Black,
447
448 match_fg: Color::Green,
449 match_modifier: Modifier::ITALIC,
450
451 current_fg: Default::default(),
452 current_bg: Color::Black,
453 current_modifier: Modifier::BOLD,
454 row_connection: RowConnectionStyle::Capped,
455
456 scroll_wrap: true,
457 scroll_padding: 2,
458 reverse: Default::default(),
459
460 wrap: Default::default(),
461 min_wrap_width: 4,
462
463 autoscroll: Default::default(),
464
465 column_spacing: Default::default(),
466 current_prefix: Default::default(),
467 right_align_last: false,
468 stacked_columns: false,
469 horizontal_separator: Default::default(),
470 }
471 }
472}
473
474#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
475#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
476#[serde(default, deny_unknown_fields)]
477pub struct StatusConfig {
478 #[serde(deserialize_with = "camelcase_normalized")]
479 pub fg: Color,
480 #[serde(deserialize_with = "camelcase_normalized")]
481 pub bg: Color,
482 pub modifier: Modifier,
484
485 pub show: bool,
487 pub match_indent: bool,
489
490 #[partial(alias = "t")]
496 pub template: String,
497
498 pub row_connection: RowConnectionStyle,
502}
503impl Default for StatusConfig {
504 fn default() -> Self {
505 Self {
506 fg: Color::Green,
507 bg: Default::default(),
508 modifier: Modifier::ITALIC,
509 show: true,
510 match_indent: true,
511 template: r#"\m/\t"#.to_string(),
512 row_connection: RowConnectionStyle::Full,
513 }
514 }
515}
516
517impl StatusConfig {
518 pub fn base_style(&self) -> Style {
519 Style::default()
520 .fg(self.fg)
521 .bg(self.bg)
522 .add_modifier(self.modifier)
523 }
524}
525
526#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
527#[serde(default, deny_unknown_fields)]
528#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
529pub struct DisplayConfig {
530 #[partial(recurse)]
531 pub border: BorderSetting,
532
533 #[serde(deserialize_with = "camelcase_normalized")]
534 pub fg: Color,
535 pub modifier: Modifier,
537
538 pub match_indent: bool,
540 pub wrap: bool,
542
543 pub content: Option<StringOrVec>,
545
546 #[serde(deserialize_with = "camelcase_normalized")]
555 pub row_connection: RowConnectionStyle,
556
557 #[partial(alias = "h")]
559 pub header_lines: usize,
560}
561
562impl Default for DisplayConfig {
563 fn default() -> Self {
564 DisplayConfig {
565 border: Default::default(),
566 match_indent: true,
567 fg: Color::Green,
568 wrap: false,
569 row_connection: Default::default(),
570 modifier: Modifier::ITALIC, content: None,
572 header_lines: 0,
573 }
574 }
575}
576
577#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
593#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
594#[serde(default, deny_unknown_fields)]
595pub struct PreviewConfig {
596 #[partial(recurse)]
597 pub border: BorderSetting,
598 #[partial(recurse, set = "recurse")]
599 #[partial(alias = "l")]
600 pub layout: Vec<PreviewSetting>,
601 #[serde(alias = "scroll")]
602 #[partial(recurse)]
603 #[partial(alias = "i")]
604 pub initial: PreviewInitialSetting,
605 #[partial(alias = "c")]
607 #[serde(alias = "cycle")]
608 pub scroll_wrap: bool,
609 pub wrap: bool,
610 pub show: ShowCondition,
613
614 pub reevaluate_show_on_resize: bool,
615}
616
617impl Default for PreviewConfig {
618 fn default() -> Self {
619 PreviewConfig {
620 border: BorderSetting {
621 padding: Padding(ratatui::widgets::Padding::left(2)),
622 ..Default::default()
623 },
624 initial: Default::default(),
625 layout: Default::default(),
626 scroll_wrap: true,
627 wrap: Default::default(),
628 show: Default::default(),
629 reevaluate_show_on_resize: false,
630 }
631 }
632}
633
634#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
636#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
637#[serde(default, deny_unknown_fields)]
638pub struct PreviewInitialSetting {
639 pub index: Option<StringValue>,
642 #[partial(alias = "o")]
644 pub offset: isize,
645 #[partial(alias = "p")]
647 pub percentage: Percentage,
648 #[partial(alias = "h")]
650 pub header_lines: usize,
651}
652
653impl Default for PreviewInitialSetting {
654 fn default() -> Self {
655 Self {
656 index: Default::default(),
657 offset: -1,
658 percentage: Default::default(),
659 header_lines: Default::default(),
660 }
661 }
662}
663
664#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
665#[serde(default, deny_unknown_fields)]
666pub struct PreviewerConfig {
667 pub try_lossy: bool,
668
669 pub cache: u8,
671
672 pub help_colors: HelpColorConfig,
673}
674
675#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
677pub struct HelpColorConfig {
678 #[serde(deserialize_with = "camelcase_normalized")]
679 pub section: Color,
680 #[serde(deserialize_with = "camelcase_normalized")]
681 pub key: Color,
682 #[serde(deserialize_with = "camelcase_normalized")]
683 pub value: Color,
684}
685
686impl Default for HelpColorConfig {
687 fn default() -> Self {
688 Self {
689 section: Color::Blue,
690 key: Color::Green,
691 value: Color::White,
692 }
693 }
694}
695
696#[derive(Default, Debug, Clone, PartialEq, Deserialize, Serialize)]
699#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
700#[serde(default, deny_unknown_fields)]
701pub struct BorderSetting {
702 #[serde(deserialize_with = "camelcase_normalized_option")]
703 pub r#type: Option<BorderType>,
704 #[serde(deserialize_with = "camelcase_normalized")]
705 pub color: Color,
706 pub sides: Option<Borders>,
715 pub padding: Padding,
723 pub title: String,
724 pub title_modifier: Modifier,
726 pub modifier: Modifier,
727 #[serde(deserialize_with = "camelcase_normalized")]
728 pub bg: Color,
729}
730
731impl BorderSetting {
732 pub fn as_block(&self) -> ratatui::widgets::Block<'_> {
733 let mut ret = ratatui::widgets::Block::default()
734 .padding(self.padding.0)
735 .style(Style::default().bg(self.bg).add_modifier(self.modifier));
736
737 if !self.title.is_empty() {
738 let title = Span::styled(
739 &self.title,
740 Style::default().add_modifier(self.title_modifier),
741 );
742
743 ret = ret.title(title)
744 };
745
746 if !self.is_empty() {
747 ret = ret
748 .borders(self.sides())
749 .border_type(self.r#type.unwrap_or_default())
750 .border_style(ratatui::style::Style::default().fg(self.color))
751 }
752
753 ret
754 }
755
756 pub fn sides(&self) -> Borders {
757 if let Some(s) = self.sides {
758 s
759 } else if self.color != Default::default() || self.r#type != Default::default() {
760 Borders::ALL
761 } else {
762 Borders::NONE
763 }
764 }
765
766 pub fn as_static_block(&self) -> ratatui::widgets::Block<'static> {
767 let mut ret = ratatui::widgets::Block::default()
768 .padding(self.padding.0)
769 .style(Style::default().bg(self.bg).add_modifier(self.modifier));
770
771 if !self.title.is_empty() {
772 let title: Span<'static> = Span::styled(
773 self.title.clone(),
774 Style::default().add_modifier(self.title_modifier),
775 );
776
777 ret = ret.title(title)
778 };
779
780 if !self.is_empty() {
781 ret = ret
782 .borders(self.sides())
783 .border_type(self.r#type.unwrap_or_default())
784 .border_style(ratatui::style::Style::default().fg(self.color))
785 }
786
787 ret
788 }
789
790 pub fn is_empty(&self) -> bool {
791 self.sides() == Borders::NONE
792 }
793
794 pub fn height(&self) -> u16 {
795 let mut height = 0;
796 height += 2 * !self.is_empty() as u16;
797 height += self.padding.top + self.padding.bottom;
798 height += (!self.title.is_empty() as u16).saturating_sub(!self.is_empty() as u16);
799
800 height
801 }
802
803 pub fn width(&self) -> u16 {
804 let mut width = 0;
805 width += 2 * !self.is_empty() as u16;
806 width += self.padding.left + self.padding.right;
807
808 width
809 }
810
811 pub fn left(&self) -> u16 {
812 let mut width = 0;
813 width += !self.is_empty() as u16;
814 width += self.padding.left;
815
816 width
817 }
818
819 pub fn top(&self) -> u16 {
820 let mut height = 0;
821 height += !self.is_empty() as u16;
822 height += self.padding.top;
823 height += (!self.title.is_empty() as u16).saturating_sub(!self.is_empty() as u16);
824
825 height
826 }
827}
828
829#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
831#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
832pub struct TerminalLayoutSettings {
833 #[partial(alias = "p")]
835 pub percentage: Percentage,
836 pub min: u16,
837 pub max: u16, }
839
840impl Default for TerminalLayoutSettings {
841 fn default() -> Self {
842 Self {
843 percentage: Percentage::new(50),
844 min: 10,
845 max: 120,
846 }
847 }
848}
849
850#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
851#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
852#[serde(default)]
853pub struct PreviewSetting {
854 #[serde(flatten)]
855 #[partial(recurse)]
856 pub layout: PreviewLayout,
857 #[partial(recurse)]
858 pub border: Option<BorderSetting>,
859 #[serde(default, alias = "cmd", alias = "x")]
860 pub command: String,
861}
862
863#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
864#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
865#[serde(default)]
866pub struct PreviewLayout {
867 pub side: Side,
868 #[serde(alias = "p")]
870 pub percentage: Percentage,
872 pub min: i16,
873 pub max: i16,
874}
875
876impl Default for PreviewLayout {
877 fn default() -> Self {
878 Self {
879 side: Side::Right,
880 percentage: Percentage::new(60),
881 min: 15,
882 max: 120,
883 }
884 }
885}
886
887use crate::utils::serde::bounded_usize;
888#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
889#[serde(default, deny_unknown_fields)]
890#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
891pub struct ColumnsConfig {
892 #[partial(alias = "s")]
894 pub split: Split,
895 #[partial(alias = "n")]
897 pub names: Vec<ColumnSetting>,
898 #[serde(deserialize_with = "bounded_usize::<_, 1, {crate::MAX_SPLITS}>")]
900 #[partial(alias = "mc")]
901 max: usize,
902 #[partial(alias = "i")]
903 pub default: Option<StringValue>,
904 pub names_from_zero: bool,
906}
907
908impl ColumnsConfig {
909 pub fn max_cols(&self) -> usize {
910 self.max.min(MAX_SPLITS).max(1)
911 }
912}
913
914impl Default for ColumnsConfig {
915 fn default() -> Self {
916 Self {
917 split: Default::default(),
918 names: Default::default(),
919 max: 6,
920 default: None,
921 names_from_zero: false,
922 }
923 }
924}
925
926#[derive(Debug, Clone, PartialEq)]
928pub struct NucleoMatcherConfig(pub nucleo::Config);
929
930impl Default for NucleoMatcherConfig {
931 fn default() -> Self {
932 Self(nucleo::Config::DEFAULT)
933 }
934}
935
936#[derive(Debug, Clone, Serialize, Deserialize)]
937#[serde(default)]
938#[derive(Default)]
939struct MatcherConfigHelper {
940 pub normalize: Option<bool>,
941 pub ignore_case: Option<bool>,
942 pub prefer_prefix: Option<bool>,
943}
944
945impl serde::Serialize for NucleoMatcherConfig {
946 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
947 where
948 S: serde::Serializer,
949 {
950 let helper = MatcherConfigHelper {
951 normalize: Some(self.0.normalize),
952 ignore_case: Some(self.0.ignore_case),
953 prefer_prefix: Some(self.0.prefer_prefix),
954 };
955 helper.serialize(serializer)
956 }
957}
958
959impl<'de> Deserialize<'de> for NucleoMatcherConfig {
960 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
961 where
962 D: serde::Deserializer<'de>,
963 {
964 let helper = MatcherConfigHelper::deserialize(deserializer)?;
965 let mut config = nucleo::Config::DEFAULT;
966
967 if let Some(norm) = helper.normalize {
968 config.normalize = norm;
969 }
970 if let Some(ic) = helper.ignore_case {
971 config.ignore_case = ic;
972 }
973 if let Some(pp) = helper.prefer_prefix {
974 config.prefer_prefix = pp;
975 }
976
977 Ok(NucleoMatcherConfig(config))
978 }
979}