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(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
106impl Default for ExitConfig {
107 fn default() -> Self {
108 Self {
109 select_1: false,
110 allow_empty: false,
111 abort_empty: true,
112 last_key_path: None,
113 }
114 }
115}
116
117#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
119#[serde(default, deny_unknown_fields)]
120#[partial(recurse, path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
121pub struct RenderConfig {
122 pub ui: UiConfig,
124 #[partial(alias = "q")]
126 pub query: QueryConfig,
127 #[partial(alias = "r")]
129 pub results: ResultsConfig,
130
131 pub status: StatusConfig,
133 #[partial(alias = "p")]
135 pub preview: PreviewConfig,
136 #[partial(alias = "f")]
137 pub footer: DisplayConfig,
138 #[partial(alias = "h")]
139 pub header: DisplayConfig,
140}
141
142impl RenderConfig {
143 pub fn tick_rate(&self) -> u8 {
144 self.ui.tick_rate
145 }
146}
147
148#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
150#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
151#[serde(default, deny_unknown_fields)]
152pub struct TerminalConfig {
153 pub stream: IoStream, pub restore_fullscreen: bool,
155 pub redraw_on_resize: bool,
156 pub extended_keys: bool,
158 #[serde(with = "serde_duration_ms")]
159 pub sleep_ms: std::time::Duration, #[serde(flatten)]
161 #[partial(recurse)]
162 pub layout: Option<TerminalLayoutSettings>, pub clear_on_exit: bool,
164 pub move_up_on_exit: bool,
166}
167
168impl Default for TerminalConfig {
169 fn default() -> Self {
170 Self {
171 stream: IoStream::default(),
172 restore_fullscreen: true,
173 redraw_on_resize: bool::default(),
174 sleep_ms: std::time::Duration::default(),
175 layout: Option::default(),
176 extended_keys: true,
177 clear_on_exit: true,
178 move_up_on_exit: false,
179 }
180 }
181}
182
183#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
185#[serde(default, deny_unknown_fields)]
186#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
187pub struct UiConfig {
188 #[partial(recurse)]
189 #[partial(alias = "b")]
190 pub border: BorderSetting,
191 pub tick_rate: u8, }
193
194impl Default for UiConfig {
195 fn default() -> Self {
196 Self {
197 border: Default::default(),
198 tick_rate: 60,
199 }
200 }
201}
202
203#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
205#[serde(default, deny_unknown_fields)]
206#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
207pub struct QueryConfig {
208 #[partial(recurse)]
209 #[partial(alias = "b")]
210 pub border: BorderSetting,
211
212 #[partial(recurse)]
214 pub style: StyleSetting,
215
216 #[partial(recurse)]
217 pub prompt_style: StyleSetting,
218
219 #[serde(deserialize_with = "deserialize_string_or_char_as_double_width")]
221 pub prompt: String,
222 pub cursor: CursorSetting,
224
225 #[partial(alias = "i")]
227 pub initial: String,
228
229 pub scroll_padding: bool,
231}
232
233impl Default for QueryConfig {
234 fn default() -> Self {
235 Self {
236 border: Default::default(),
237 style: Default::default(),
238 prompt_style: Default::default(),
239 prompt: "> ".to_string(),
240 cursor: Default::default(),
241 initial: Default::default(),
242
243 scroll_padding: true,
244 }
245 }
246}
247
248impl QueryConfig {}
249
250#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
251#[serde(default, deny_unknown_fields)]
252#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
253pub struct OverlayConfig {
254 #[partial(recurse)]
255 #[partial(alias = "b")]
256 pub border: BorderSetting,
257 pub outer_dim: bool,
258 pub layout: OverlayLayoutSettings,
259}
260
261#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
262#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
263pub struct OverlayLayoutSettings {
264 #[partial(alias = "p")]
266 pub percentage: [Percentage; 2],
267 pub min: [u16; 2],
269 pub max: [u16; 2],
271
272 pub y_offset: Percentage,
274}
275
276impl Default for OverlayLayoutSettings {
277 fn default() -> Self {
278 Self {
279 percentage: [Percentage::new(60), Percentage::new(30)],
280 min: [10, 10],
281 max: [200, 30],
282 y_offset: Percentage::new(55),
283 }
284 }
285}
286
287#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
290#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
291#[serde(default, deny_unknown_fields)]
292pub struct AutoscrollSettings {
293 #[partial(alias = "i")]
295 pub initial_preserved: usize,
296 #[partial(alias = "a")]
298 pub enabled: bool,
299 #[partial(alias = "c")]
301 pub context: usize,
302 #[partial(alias = "e")]
304 pub end: bool,
305}
306
307impl Default for AutoscrollSettings {
308 fn default() -> Self {
309 Self {
310 initial_preserved: 0,
311 enabled: true,
312 context: 4,
313 end: false,
314 }
315 }
316}
317
318#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
319#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
320#[serde(default, deny_unknown_fields)]
321pub struct ResultsConfig {
322 #[partial(recurse)]
323 #[partial(alias = "b")]
324 pub border: BorderSetting,
325
326 #[serde(deserialize_with = "deserialize_string_or_char_as_double_width")]
328 pub multi_prefix: String,
329 pub default_prefix: String,
330
331 pub multi: bool,
333
334 #[partial(recurse)]
336 pub style: StyleSetting,
337
338 #[partial(recurse)]
340 pub inactive: StyleSetting,
341
342 #[partial(recurse)]
344 pub inactive_current: StyleSetting,
345
346 #[partial(recurse)]
347 pub match_style: StyleSetting,
348
349 #[partial(recurse)]
351 pub current: StyleSetting,
352
353 #[serde(deserialize_with = "camelcase_normalized")]
358 pub row_connection: RowConnectionStyle,
359
360 #[partial(alias = "c")]
362 #[serde(alias = "cycle")]
363 pub scroll_wrap: bool,
364 #[partial(alias = "sp")]
365 pub scroll_padding: u16,
366 #[partial(alias = "r")]
367 pub reverse: Option<bool>,
368
369 #[partial(alias = "w")]
371 pub wrap: bool,
372 pub min_wrap_width: u16,
373
374 #[partial(recurse, alias = "a")]
376 pub autoscroll: AutoscrollSettings,
377
378 pub column_spacing: Count,
382 pub current_prefix: String,
383
384 pub max_height: usize,
387 pub show_skipped: bool,
388 pub vscroll_current_only: bool,
390
391 #[partial(alias = "ra")]
393 pub right_align_last: bool,
394 #[partial(alias = "v")]
395 #[serde(alias = "vertical")]
396 pub stacked_columns: bool,
397
398 #[serde(alias = "hr")]
399 #[serde(deserialize_with = "camelcase_normalized")]
400 pub separator: HorizontalSeparator,
401 pub separator_style: StyleSetting,
402}
403
404impl Default for ResultsConfig {
405 fn default() -> Self {
406 ResultsConfig {
407 border: Default::default(),
408
409 multi_prefix: "▌ ".to_string(),
410 default_prefix: Default::default(),
411 multi: true,
412
413 style: Default::default(),
414 inactive: Default::default(),
415 inactive_current: StyleSetting {
416 fg: Color::DarkGray,
417 bg: Color::Black,
418 ..Default::default()
419 },
420
421 match_style: StyleSetting {
422 fg: Color::Green,
423 modifier: Modifier::ITALIC,
424 ..Default::default()
425 },
426
427 current: StyleSetting {
428 bg: Color::Black,
429 modifier: Modifier::BOLD,
430 ..Default::default()
431 },
432
433 row_connection: RowConnectionStyle::Capped,
434
435 scroll_wrap: true,
436 scroll_padding: 2,
437 reverse: Default::default(),
438
439 wrap: Default::default(),
440 min_wrap_width: 4,
441 max_height: 0,
442
443 autoscroll: Default::default(),
444
445 column_spacing: Default::default(),
446 current_prefix: Default::default(),
447 right_align_last: false,
448 stacked_columns: false,
449 separator: Default::default(),
450 separator_style: Default::default(),
451 show_skipped: true,
452 vscroll_current_only: true,
453 }
454 }
455}
456
457#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
458#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
459#[serde(default, deny_unknown_fields)]
460pub struct StatusConfig {
461 #[partial(recurse)]
462 pub style: StyleSetting,
463
464 pub show: bool,
466 pub match_indent: bool,
468
469 #[partial(alias = "t")]
478 pub template: String,
479
480 pub row_connection: RowConnectionStyle,
484}
485impl Default for StatusConfig {
486 fn default() -> Self {
487 Self {
488 style: StyleSetting {
489 fg: Color::Green,
490 modifier: Modifier::ITALIC,
491 ..Default::default()
492 },
493 show: true,
494 match_indent: true,
495 template: String::new(),
496 row_connection: RowConnectionStyle::Full,
497 }
498 }
499}
500
501impl StatusConfig {}
502
503#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
504#[serde(default, deny_unknown_fields)]
505#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
506pub struct DisplayConfig {
507 #[partial(recurse)]
508 #[partial(alias = "b")]
509 pub border: BorderSetting,
510
511 #[partial(recurse)]
512 pub style: StyleSetting,
513
514 pub match_indent: bool,
516 pub wrap: bool,
518
519 pub content: Option<StringOrVec>,
521
522 #[serde(deserialize_with = "camelcase_normalized")]
532 pub row_connection: RowConnectionStyle,
533
534 #[partial(alias = "h")]
536 pub header_lines: usize,
537}
538
539impl Default for DisplayConfig {
540 fn default() -> Self {
541 DisplayConfig {
542 border: Default::default(),
543 match_indent: true,
544 style: StyleSetting {
545 fg: Color::Green,
546 modifier: Modifier::ITALIC,
547 ..Default::default()
548 },
549 wrap: false,
550 row_connection: Default::default(),
551 content: None,
552 header_lines: 0,
553 }
554 }
555}
556
557#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
573#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
574#[serde(default, deny_unknown_fields)]
575pub struct PreviewConfig {
576 #[partial(recurse)]
577 #[partial(alias = "b")]
578 pub border: BorderSetting,
579 #[partial(recurse, set = "recurse")]
580 #[partial(alias = "l")]
581 pub layout: Vec<PreviewSetting>,
582 #[serde(alias = "scroll")]
583 #[partial(recurse)]
584 #[partial(alias = "i")]
585 pub initial: PreviewInitialSetting,
586 #[partial(alias = "c")]
588 #[serde(alias = "cycle")]
589 pub scroll_wrap: bool,
590 pub wrap: bool,
591 pub show: ShowCondition,
594
595 pub reevaluate_show_on_resize: bool,
596}
597
598impl Default for PreviewConfig {
599 fn default() -> Self {
600 PreviewConfig {
601 border: BorderSetting {
602 padding: Padding(ratatui::widgets::Padding::left(2)),
603 ..Default::default()
604 },
605 initial: Default::default(),
606 layout: Default::default(),
607 scroll_wrap: true,
608 wrap: Default::default(),
609 show: Default::default(),
610 reevaluate_show_on_resize: false,
611 }
612 }
613}
614
615#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
617#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
618#[serde(default, deny_unknown_fields)]
619pub struct PreviewInitialSetting {
620 pub index: Option<StringValue>,
623 #[partial(alias = "o")]
625 pub offset: isize,
626 #[partial(alias = "p")]
628 pub percentage: Percentage,
629 #[partial(alias = "h")]
631 pub header_lines: usize,
632}
633
634impl Default for PreviewInitialSetting {
635 fn default() -> Self {
636 Self {
637 index: Default::default(),
638 offset: -1,
639 percentage: Default::default(),
640 header_lines: Default::default(),
641 }
642 }
643}
644
645#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
646#[serde(default, deny_unknown_fields)]
647pub struct PreviewerConfig {
648 pub try_lossy: bool,
649
650 pub cache: u8,
652
653 pub help_colors: HelpColorConfig,
654}
655
656#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
658pub struct HelpColorConfig {
659 #[serde(deserialize_with = "camelcase_normalized")]
660 pub section: Color,
661 #[serde(deserialize_with = "camelcase_normalized")]
662 pub key: Color,
663 #[serde(deserialize_with = "camelcase_normalized")]
664 pub value: Color,
665}
666
667impl Default for HelpColorConfig {
668 fn default() -> Self {
669 Self {
670 section: Color::Blue,
671 key: Color::Green,
672 value: Color::White,
673 }
674 }
675}
676
677#[derive(Default, Debug, Clone, PartialEq, Deserialize, Serialize)]
680#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
681#[serde(default, deny_unknown_fields)]
682pub struct BorderSetting {
683 #[serde(deserialize_with = "camelcase_normalized_option")]
684 pub r#type: Option<BorderType>,
685 #[serde(deserialize_with = "camelcase_normalized")]
686 pub color: Color,
687 pub sides: Option<Borders>,
696 pub padding: Padding,
704 pub title: String,
705 pub title_modifier: Modifier,
707 pub modifier: Modifier,
708 #[serde(deserialize_with = "camelcase_normalized")]
709 pub bg: Color,
710}
711
712impl BorderSetting {
713 pub fn as_block(&self) -> ratatui::widgets::Block<'_> {
714 let mut ret = ratatui::widgets::Block::default()
715 .padding(self.padding.0)
716 .style(Style::default().bg(self.bg).add_modifier(self.modifier));
717
718 if !self.title.is_empty() {
719 let title = Span::styled(
720 &self.title,
721 Style::default().add_modifier(self.title_modifier),
722 );
723
724 ret = ret.title(title)
725 };
726
727 if !self.is_empty() {
728 ret = ret
729 .borders(self.sides())
730 .border_type(self.r#type.unwrap_or_default())
731 .border_style(ratatui::style::Style::default().fg(self.color))
732 }
733
734 ret
735 }
736
737 pub fn sides(&self) -> Borders {
738 if let Some(s) = self.sides {
739 s
740 } else if self.color != Default::default() || self.r#type != Default::default() {
741 Borders::ALL
742 } else {
743 Borders::NONE
744 }
745 }
746
747 pub fn as_static_block(&self) -> ratatui::widgets::Block<'static> {
748 let mut ret = ratatui::widgets::Block::default()
749 .padding(self.padding.0)
750 .style(Style::default().bg(self.bg).add_modifier(self.modifier));
751
752 if !self.title.is_empty() {
753 let title: Span<'static> = Span::styled(
754 self.title.clone(),
755 Style::default().add_modifier(self.title_modifier),
756 );
757
758 ret = ret.title(title)
759 };
760
761 if !self.is_empty() {
762 ret = ret
763 .borders(self.sides())
764 .border_type(self.r#type.unwrap_or_default())
765 .border_style(ratatui::style::Style::default().fg(self.color))
766 }
767
768 ret
769 }
770
771 pub fn is_empty(&self) -> bool {
772 self.sides() == Borders::NONE
773 }
774
775 pub fn height(&self) -> u16 {
776 let mut height = 0;
777 height += 2 * !self.is_empty() as u16;
778 height += self.padding.top + self.padding.bottom;
779 height += (!self.title.is_empty() as u16).saturating_sub(!self.is_empty() as u16);
780
781 height
782 }
783
784 pub fn width(&self) -> u16 {
785 let mut width = 0;
786 width += 2 * !self.is_empty() as u16;
787 width += self.padding.left + self.padding.right;
788
789 width
790 }
791
792 pub fn left(&self) -> u16 {
793 let mut width = 0;
794 width += !self.is_empty() as u16;
795 width += self.padding.left;
796
797 width
798 }
799
800 pub fn top(&self) -> u16 {
801 let mut height = 0;
802 height += !self.is_empty() as u16;
803 height += self.padding.top;
804 height += (!self.title.is_empty() as u16).saturating_sub(!self.is_empty() as u16);
805
806 height
807 }
808}
809
810#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
812#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
813pub struct TerminalLayoutSettings {
814 #[partial(alias = "p")]
816 pub percentage: Percentage,
817 pub min: u16,
818 pub max: u16, }
820
821impl Default for TerminalLayoutSettings {
822 fn default() -> Self {
823 Self {
824 percentage: Percentage::new(50),
825 min: 10,
826 max: 120,
827 }
828 }
829}
830
831#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
832#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
833#[serde(default)]
834pub struct PreviewSetting {
835 #[serde(flatten)]
836 #[partial(recurse)]
837 pub layout: PreviewLayout,
838 #[partial(recurse)]
839 pub border: Option<BorderSetting>,
840 #[serde(default, alias = "cmd", alias = "x")]
841 pub command: String,
842}
843
844#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
845#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
846#[serde(default)]
847pub struct PreviewLayout {
848 pub side: Side,
849 #[serde(alias = "p")]
851 pub percentage: Percentage,
853 pub min: i16,
854 pub max: i16,
855}
856
857impl Default for PreviewLayout {
858 fn default() -> Self {
859 Self {
860 side: Side::Right,
861 percentage: Percentage::new(60),
862 min: 15,
863 max: 120,
864 }
865 }
866}
867
868use crate::utils::serde::bounded_usize;
869#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
870#[serde(default, deny_unknown_fields)]
871#[partial(path, derive(Debug, Clone, PartialEq, Deserialize, Serialize))]
872pub struct ColumnsConfig {
873 #[partial(alias = "s")]
875 pub split: Split,
876 #[partial(alias = "n")]
878 pub names: Vec<ColumnSetting>,
879 #[serde(deserialize_with = "bounded_usize::<_, 1, {crate::MAX_SPLITS}>")]
881 #[partial(alias = "mc")]
882 max: usize,
883 #[partial(alias = "i")]
884 pub default: Option<StringValue>,
885 pub names_from_zero: bool,
887}
888
889impl ColumnsConfig {
890 pub fn max_cols(&self) -> usize {
891 self.max.min(MAX_SPLITS).max(1)
892 }
893}
894
895impl Default for ColumnsConfig {
896 fn default() -> Self {
897 Self {
898 split: Default::default(),
899 names: Default::default(),
900 max: 6,
901 default: None,
902 names_from_zero: false,
903 }
904 }
905}
906
907#[derive(Debug, Clone, PartialEq)]
909pub struct NucleoMatcherConfig(pub nucleo::Config);
910
911impl Default for NucleoMatcherConfig {
912 fn default() -> Self {
913 Self(nucleo::Config::DEFAULT)
914 }
915}
916
917#[derive(Debug, Clone, Serialize, Deserialize)]
918#[serde(default)]
919#[derive(Default)]
920struct MatcherConfigHelper {
921 pub normalize: Option<bool>,
922 pub ignore_case: Option<bool>,
923 pub prefer_prefix: Option<bool>,
924}
925
926impl serde::Serialize for NucleoMatcherConfig {
927 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
928 where
929 S: serde::Serializer,
930 {
931 let helper = MatcherConfigHelper {
932 normalize: Some(self.0.normalize),
933 ignore_case: Some(self.0.ignore_case),
934 prefer_prefix: Some(self.0.prefer_prefix),
935 };
936 helper.serialize(serializer)
937 }
938}
939
940impl<'de> Deserialize<'de> for NucleoMatcherConfig {
941 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
942 where
943 D: serde::Deserializer<'de>,
944 {
945 let helper = MatcherConfigHelper::deserialize(deserializer)?;
946 let mut config = nucleo::Config::DEFAULT;
947
948 if let Some(norm) = helper.normalize {
949 config.normalize = norm;
950 }
951 if let Some(ic) = helper.ignore_case {
952 config.ignore_case = ic;
953 }
954 if let Some(pp) = helper.prefer_prefix {
955 config.prefer_prefix = pp;
956 }
957
958 Ok(NucleoMatcherConfig(config))
959 }
960}