1use std::{fmt, ops::Deref};
5
6use crate::MAX_SPLITS;
7use crate::{Result, action::Count, tui::IoStream};
8
9use ratatui::style::Style;
10use ratatui::text::Span;
11use ratatui::{
12 style::{Color, Modifier},
13 widgets::{BorderType, Borders, Padding},
14};
15use regex::Regex;
16use serde::de::IntoDeserializer;
17use serde::ser::SerializeSeq;
18use serde::{
19 Deserialize, Deserializer,
20 de::{self, Visitor},
21};
22use serde::{Serialize, Serializer};
23
24pub use crate::utils::{
25 Percentage,
26 serde::{StringOrVec, escaped_opt_char, escaped_opt_string, serde_duration_ms},
27};
28
29#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
33pub struct MatcherConfig {
34 #[serde(flatten)]
35 pub matcher: NucleoMatcherConfig,
36 #[serde(flatten)]
37 pub worker: WorkerConfig,
38 #[serde(flatten)]
40 pub start: StartConfig,
41}
42
43#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
47#[serde(default)]
48pub struct WorkerConfig {
49 pub columns: ColumnsConfig,
50 #[serde(flatten)]
51 pub exit: ExitConfig,
52 pub trim: bool, pub format: FormatString, }
55
56#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
60#[serde(default)]
61pub struct StartConfig {
62 #[serde(default, deserialize_with = "escaped_opt_char")]
63 pub input_separator: Option<char>,
64 #[serde(default, deserialize_with = "escaped_opt_string")]
65 pub output_separator: Option<String>,
66 pub default_command: String,
67 pub sync: bool,
68}
69
70#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
74#[serde(default)]
75pub struct ExitConfig {
76 pub select_1: bool,
77 pub allow_empty: bool,
78}
79
80#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
82#[serde(default, deny_unknown_fields)]
83pub struct RenderConfig {
84 pub ui: UiConfig,
85 pub input: InputConfig,
86 pub results: ResultsConfig,
87 pub preview: PreviewConfig,
88 pub footer: DisplayConfig,
89 pub header: DisplayConfig,
90 pub overlay: Option<OverlayConfig>, }
92
93impl RenderConfig {
94 pub fn tick_rate(&self) -> u8 {
95 self.ui.tick_rate
96 }
97}
98
99#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
101#[serde(default, deny_unknown_fields)]
102pub struct TerminalConfig {
103 pub stream: IoStream, pub restore_fullscreen: bool,
105 pub redraw_on_resize: bool,
106 #[serde(with = "serde_duration_ms")]
107 pub sleep_ms: std::time::Duration, #[serde(flatten)]
110 pub layout: Option<TerminalLayoutSettings>, }
112
113impl Default for TerminalConfig {
114 fn default() -> Self {
115 Self {
116 stream: IoStream::default(),
117 restore_fullscreen: true,
118 redraw_on_resize: bool::default(),
119 sleep_ms: std::time::Duration::default(),
120 layout: Option::default(),
121 }
122 }
123}
124#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
125#[serde(default, deny_unknown_fields)]
126pub struct TerminalSettings {}
127
128#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
130#[serde(default, deny_unknown_fields)]
131pub struct UiConfig {
132 pub border: BorderSetting,
133 pub tick_rate: u8, }
135
136impl Default for UiConfig {
137 fn default() -> Self {
138 Self {
139 border: Default::default(),
140 tick_rate: 60,
141 }
142 }
143}
144
145#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
147#[serde(default, deny_unknown_fields)]
148pub struct InputConfig {
149 pub border: BorderSetting,
150
151 pub fg: Color,
153 #[serde(
154 deserialize_with = "deserialize_modifier",
155 serialize_with = "serialize_modifier"
156 )]
157 pub modifier: Modifier,
158
159 pub prompt_fg: Color,
160 #[serde(
161 deserialize_with = "deserialize_modifier",
162 serialize_with = "serialize_modifier"
163 )]
164 pub prompt_modifier: Modifier,
165
166 #[serde(deserialize_with = "deserialize_string_or_char_as_double_width")]
167 pub prompt: String,
168 pub cursor: CursorSetting,
169 pub initial: String,
170}
171
172impl Default for InputConfig {
173 fn default() -> Self {
174 Self {
175 border: Default::default(),
176 fg: Default::default(),
177 modifier: Default::default(),
178 prompt_fg: Default::default(),
179 prompt_modifier: Default::default(),
180 prompt: "> ".to_string(),
181 cursor: Default::default(),
182 initial: Default::default(),
183 }
184 }
185}
186
187#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
188#[serde(default, deny_unknown_fields)]
189pub struct OverlayConfig {
190 pub border: BorderSetting,
191 pub outer_dim: bool,
192 pub layout: OverlayLayoutSettings,
193}
194
195#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
196pub struct OverlayLayoutSettings {
197 pub percentage: [Percentage; 2],
199 pub min: [u16; 2],
201 pub max: [u16; 2],
203}
204
205impl Default for OverlayLayoutSettings {
206 fn default() -> Self {
207 Self {
208 percentage: [Percentage::new(60), Percentage::new(30)],
209 min: [10, 5],
210 max: [200, 30],
211 }
212 }
213}
214
215#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
218#[serde(default, deny_unknown_fields)]
219pub struct ResultsConfig {
220 pub border: BorderSetting,
221
222 #[serde(deserialize_with = "deserialize_string_or_char_as_double_width")]
224 pub multi_prefix: String,
225 pub default_prefix: String,
226
227 pub fg: Color,
229 #[serde(
230 deserialize_with = "deserialize_modifier",
231 serialize_with = "serialize_modifier"
232 )]
233 pub modifier: Modifier,
234
235 #[serde(default = "default_green")]
236 pub match_fg: Color,
237 #[serde(
238 deserialize_with = "deserialize_modifier",
239 serialize_with = "serialize_modifier"
240 )]
241 pub match_modifier: Modifier,
242
243 pub current_fg: Color,
244 #[serde(default = "default_black")]
245 pub current_bg: Color,
246 #[serde(
247 deserialize_with = "deserialize_modifier",
248 serialize_with = "serialize_modifier",
249 default = "default_bold"
250 )]
251 pub current_modifier: Modifier,
252
253 #[serde(default = "default_green")]
255 pub count_fg: Color,
256 #[serde(
257 deserialize_with = "deserialize_modifier",
258 serialize_with = "serialize_modifier",
259 default = "default_italic"
260 )]
261 pub count_modifier: Modifier,
262
263 #[serde(default = "default_true")]
270 pub scroll_wrap: bool,
271 pub scroll_padding: u16,
272 #[serde(deserialize_with = "deserialize_option_auto")]
273 pub reverse: Option<bool>,
274
275 pub wrap: bool,
277 pub wrap_scaling_min_width: u8,
278
279 pub column_spacing: Count,
281 pub current_prefix: String,
282 pub right_align_last: bool,
283}
284
285impl Default for ResultsConfig {
286 fn default() -> Self {
287 ResultsConfig {
288 border: Default::default(),
289
290 multi_prefix: "▌ ".to_string(),
291 default_prefix: Default::default(),
292
293 fg: Default::default(),
294 modifier: Default::default(), match_fg: default_green(),
296 match_modifier: default_italic(),
297
298 current_fg: Default::default(),
299 current_bg: default_black(),
300 current_modifier: default_bold(),
301
302 count_fg: default_green(),
303 count_modifier: default_italic(),
304
305 scroll_wrap: default_true(),
306 scroll_padding: 2,
307 reverse: None,
308
309 wrap: Default::default(),
310 wrap_scaling_min_width: 5,
311
312 column_spacing: Default::default(),
313 current_prefix: Default::default(),
314 right_align_last: true,
315 }
316 }
317}
318
319#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
320#[serde(default, deny_unknown_fields)]
321pub struct DisplayConfig {
322 pub border: BorderSetting,
323
324 #[serde(default = "default_green")]
325 pub fg: Color,
326 #[serde(
327 deserialize_with = "deserialize_modifier",
328 serialize_with = "serialize_modifier",
329 default = "default_italic"
330 )]
331 pub modifier: Modifier,
332
333 #[serde(default = "default_true")]
334 pub match_indent: bool,
335 pub wrap: bool,
336 #[serde(deserialize_with = "deserialize_option_auto")]
337 pub content: Option<StringOrVec>,
338}
339
340impl Default for DisplayConfig {
341 fn default() -> Self {
342 DisplayConfig {
343 border: Default::default(),
344 match_indent: true,
345 fg: default_green(),
346 wrap: false,
347 modifier: default_italic(), content: None,
349 }
350 }
351}
352
353#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
354#[serde(default, deny_unknown_fields)]
355pub struct PreviewConfig {
356 pub border: BorderSetting,
357
358 pub layout: Vec<PreviewSetting>,
359 #[serde(default = "default_true")]
360 pub scroll_wrap: bool,
361 pub wrap: bool,
362 pub show: bool,
363}
364
365impl Default for PreviewConfig {
366 fn default() -> Self {
367 PreviewConfig {
368 border: Default::default(),
369 layout: Default::default(),
376 scroll_wrap: default_true(),
377 wrap: Default::default(),
378 show: Default::default(),
379 }
380 }
381}
382
383#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
384#[serde(default, deny_unknown_fields)]
385pub struct PreviewerConfig {
386 pub try_lossy: bool,
387
388 pub cache: u8,
390
391 #[serde(default)]
392 pub help_colors: TomlColorConfig,
393}
394
395#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
397pub struct TomlColorConfig {
398 pub section: Color,
399 pub key: Color,
400 pub string: Color,
401 pub number: Color,
402 pub section_bold: bool,
403}
404
405impl Default for TomlColorConfig {
406 fn default() -> Self {
407 Self {
408 section: Color::Blue,
409 key: Color::Yellow,
410 string: Color::Green,
411 number: Color::Cyan,
412 section_bold: true,
413 }
414 }
415}
416
417#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
421#[serde(transparent)]
422pub struct FormatString(String);
423
424impl Deref for FormatString {
425 type Target = str;
426
427 fn deref(&self) -> &Self::Target {
428 &self.0
429 }
430}
431
432#[derive(Default, Debug, Clone, PartialEq, Serialize)]
433#[serde(default, deny_unknown_fields)]
434pub struct BorderSetting {
435 #[serde(with = "crate::utils::serde::fromstr")]
436 pub r#type: BorderType,
437 pub color: Color,
438 #[serde(
439 serialize_with = "serialize_borders",
440 deserialize_with = "deserialize_borders"
441 )]
442 pub sides: Borders,
443 #[serde(
444 serialize_with = "serialize_padding",
445 deserialize_with = "deserialize_padding"
446 )]
447 pub padding: Padding,
448 pub title: String,
449 #[serde(
450 deserialize_with = "deserialize_modifier",
451 serialize_with = "serialize_modifier"
452 )]
453 pub title_modifier: Modifier,
454 pub bg: Color,
455}
456
457impl BorderSetting {
458 pub fn as_block(&self) -> ratatui::widgets::Block<'_> {
459 let mut ret = ratatui::widgets::Block::default()
460 .padding(self.padding)
461 .style(Style::default().bg(self.bg));
462
463 if !self.title.is_empty() {
464 let title = Span::styled(
465 &self.title,
466 Style::default().add_modifier(self.title_modifier),
467 );
468
469 ret = ret.title(title)
470 };
471
472 if self.sides != Borders::NONE {
473 ret = ret
474 .borders(self.sides)
475 .border_type(self.r#type)
476 .border_style(ratatui::style::Style::default().fg(self.color))
477 }
478
479 ret
480 }
481
482 pub fn as_static_block(&self) -> ratatui::widgets::Block<'static> {
483 let mut ret = ratatui::widgets::Block::default()
484 .padding(self.padding)
485 .style(Style::default().bg(self.bg));
486
487 if !self.title.is_empty() {
488 let title: Span<'static> = Span::styled(
489 self.title.clone(),
490 Style::default().add_modifier(self.title_modifier),
491 );
492
493 ret = ret.title(title)
494 };
495
496 if self.sides != Borders::NONE {
497 ret = ret
498 .borders(self.sides)
499 .border_type(self.r#type)
500 .border_style(ratatui::style::Style::default().fg(self.color))
501 }
502
503 ret
504 }
505
506 pub fn height(&self) -> u16 {
507 let mut height = 0;
508 height += 2 * !self.sides.is_empty() as u16;
509 height += self.padding.top + self.padding.bottom;
510 height += (!self.title.is_empty() as u16).saturating_sub(!self.sides.is_empty() as u16);
511
512 height
513 }
514
515 pub fn width(&self) -> u16 {
516 let mut width = 0;
517 width += 2 * !self.sides.is_empty() as u16;
518 width += self.padding.left + self.padding.right;
519
520 width
521 }
522
523 pub fn left(&self) -> u16 {
524 let mut width = 0;
525 width += !self.sides.is_empty() as u16;
526 width += self.padding.left;
527
528 width
529 }
530
531 pub fn top(&self) -> u16 {
532 let mut height = 0;
533 height += !self.sides.is_empty() as u16;
534 height += self.padding.top;
535 height += (!self.title.is_empty() as u16).saturating_sub(!self.sides.is_empty() as u16);
536
537 height
538 }
539}
540
541#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
543pub struct TerminalLayoutSettings {
544 pub percentage: Percentage,
545 pub min: u16,
546 pub max: u16, }
548
549impl Default for TerminalLayoutSettings {
550 fn default() -> Self {
551 Self {
552 percentage: Percentage::new(50),
553 min: 10,
554 max: 120,
555 }
556 }
557}
558
559#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
560#[serde(rename_all = "lowercase")]
561pub enum Side {
562 Top,
563 Bottom,
564 Left,
565 #[default]
566 Right,
567}
568
569#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
570pub struct PreviewSetting {
571 #[serde(flatten)]
572 pub layout: PreviewLayoutSetting,
573 #[serde(default)]
574 pub command: String,
575}
576
577#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
578pub struct PreviewLayoutSetting {
579 pub side: Side,
580 pub percentage: Percentage,
581 pub min: i16,
582 pub max: i16,
583}
584
585impl Default for PreviewLayoutSetting {
586 fn default() -> Self {
587 Self {
588 side: Side::Right,
589 percentage: Percentage::new(60),
590 min: 30,
591 max: 120,
592 }
593 }
594}
595
596#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
597#[serde(rename_all = "lowercase")]
598pub enum CursorSetting {
599 None,
600 #[default]
601 Default,
602}
603
604use crate::utils::serde::bounded_usize;
605#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
607#[serde(default, deny_unknown_fields)]
608pub struct ColumnsConfig {
609 pub split: Split,
610 pub names: Vec<ColumnSetting>,
611 #[serde(deserialize_with = "bounded_usize::<{crate::MAX_SPLITS},_>")]
612 max_columns: usize,
613}
614
615impl ColumnsConfig {
616 pub fn max_cols(&self) -> usize {
617 self.max_columns.min(MAX_SPLITS)
618 }
619}
620
621#[derive(Default, Debug, Clone, PartialEq)]
622pub struct ColumnSetting {
623 pub filter: bool,
624 pub hidden: bool,
625 pub name: String,
626}
627
628#[derive(Default, Debug, Clone)]
629pub enum Split {
630 Delimiter(Regex),
631 Regexes(Vec<Regex>),
632 #[default]
633 None,
634}
635
636impl PartialEq for Split {
637 fn eq(&self, other: &Self) -> bool {
638 match (self, other) {
639 (Split::Delimiter(r1), Split::Delimiter(r2)) => r1.as_str() == r2.as_str(),
640 (Split::Regexes(v1), Split::Regexes(v2)) => {
641 if v1.len() != v2.len() {
642 return false;
643 }
644 v1.iter()
645 .zip(v2.iter())
646 .all(|(r1, r2)| r1.as_str() == r2.as_str())
647 }
648 (Split::None, Split::None) => true,
649 _ => false,
650 }
651 }
652}
653
654pub fn serialize_borders<S>(borders: &Borders, serializer: S) -> Result<S::Ok, S::Error>
656where
657 S: serde::Serializer,
658{
659 use serde::ser::SerializeSeq;
660 let mut seq = serializer.serialize_seq(None)?;
661 if borders.contains(Borders::TOP) {
662 seq.serialize_element("top")?;
663 }
664 if borders.contains(Borders::BOTTOM) {
665 seq.serialize_element("bottom")?;
666 }
667 if borders.contains(Borders::LEFT) {
668 seq.serialize_element("left")?;
669 }
670 if borders.contains(Borders::RIGHT) {
671 seq.serialize_element("right")?;
672 }
673 seq.end()
674}
675
676pub fn deserialize_borders<'de, D>(deserializer: D) -> Result<Borders, D::Error>
677where
678 D: Deserializer<'de>,
679{
680 let input = StringOrVec::deserialize(deserializer)?;
681 let mut borders = Borders::NONE;
682
683 let borders = match input {
684 StringOrVec::String(s) => match s.as_str() {
685 "none" => Borders::NONE,
686 "all" => Borders::ALL,
687 other => {
688 return Err(de::Error::custom(format!(
689 "invalid border value '{}'",
690 other
691 )));
692 }
693 },
694 StringOrVec::Vec(list) => {
695 for item in list {
696 match item.as_str() {
697 "top" => borders |= Borders::TOP,
698 "bottom" => borders |= Borders::BOTTOM,
699 "left" => borders |= Borders::LEFT,
700 "right" => borders |= Borders::RIGHT,
701 "all" => borders |= Borders::ALL,
702 "none" => borders = Borders::NONE,
703 other => return Err(de::Error::custom(format!("invalid side '{}'", other))),
704 }
705 }
706 borders
707 }
708 };
709
710 Ok(borders)
711}
712
713pub fn deserialize_borders_option<'de, D>(deserializer: D) -> Result<Option<Borders>, D::Error>
714where
715 D: Deserializer<'de>,
716{
717 let input = Option::<StringOrVec>::deserialize(deserializer)?;
718 match input {
719 Some(input) => {
720 let mut borders = Borders::NONE;
721
722 let borders = match input {
723 StringOrVec::String(s) => match s.as_str() {
724 "none" => Borders::NONE,
725 "all" => Borders::ALL,
726 other => {
727 return Err(de::Error::custom(format!(
728 "invalid border value '{}'",
729 other
730 )));
731 }
732 },
733 StringOrVec::Vec(list) => {
734 for item in list {
735 match item.as_str() {
736 "top" => borders |= Borders::TOP,
737 "bottom" => borders |= Borders::BOTTOM,
738 "left" => borders |= Borders::LEFT,
739 "right" => borders |= Borders::RIGHT,
740 "all" => borders |= Borders::ALL,
741 "none" => borders = Borders::NONE,
742 other => {
743 return Err(de::Error::custom(format!("invalid side '{}'", other)));
744 }
745 }
746 }
747 borders
748 }
749 };
750
751 Ok(Some(borders))
752 }
753 None => Ok(None),
754 }
755}
756
757pub fn deserialize_modifier<'de, D>(deserializer: D) -> Result<Modifier, D::Error>
758where
759 D: Deserializer<'de>,
760{
761 let input = StringOrVec::deserialize(deserializer)?;
762 let mut modifier = Modifier::empty();
763
764 let add_modifier = |name: &str, m: &mut Modifier| -> Result<(), D::Error> {
765 match name.to_lowercase().as_str() {
766 "bold" => {
767 *m |= Modifier::BOLD;
768 Ok(())
769 }
770 "italic" => {
771 *m |= Modifier::ITALIC;
772 Ok(())
773 }
774 "underlined" => {
775 *m |= Modifier::UNDERLINED;
776 Ok(())
777 }
778 "none" => {
799 *m = Modifier::empty();
800 Ok(())
801 } other => Err(de::Error::custom(format!("invalid modifier '{}'", other))),
803 }
804 };
805
806 match input {
807 StringOrVec::String(s) => add_modifier(&s, &mut modifier)?,
808 StringOrVec::Vec(list) => {
809 for item in list {
810 add_modifier(&item, &mut modifier)?;
811 }
812 }
813 }
814
815 Ok(modifier)
816}
817
818pub fn serialize_modifier<S>(modifier: &Modifier, serializer: S) -> Result<S::Ok, S::Error>
819where
820 S: Serializer,
821{
822 let mut mods = Vec::new();
823
824 if modifier.contains(Modifier::BOLD) {
825 mods.push("bold");
826 }
827 if modifier.contains(Modifier::ITALIC) {
828 mods.push("italic");
829 }
830 if modifier.contains(Modifier::UNDERLINED) {
831 mods.push("underlined");
832 }
833 match mods.len() {
837 0 => serializer.serialize_str("none"),
838 1 => serializer.serialize_str(mods[0]),
839 _ => mods.serialize(serializer),
840 }
841}
842
843pub fn deserialize_string_or_char_as_double_width<'de, D, T>(deserializer: D) -> Result<T, D::Error>
844where
845 D: Deserializer<'de>,
846 T: From<String>,
847{
848 struct GenericVisitor<T> {
849 _marker: std::marker::PhantomData<T>,
850 }
851
852 impl<'de, T> Visitor<'de> for GenericVisitor<T>
853 where
854 T: From<String>,
855 {
856 type Value = T;
857
858 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
859 formatter.write_str("a string or single character")
860 }
861
862 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
863 where
864 E: de::Error,
865 {
866 let s = if v.chars().count() == 1 {
867 let mut s = String::with_capacity(2);
868 s.push(v.chars().next().unwrap());
869 s.push(' ');
870 s
871 } else {
872 v.to_string()
873 };
874 Ok(T::from(s))
875 }
876
877 fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
878 where
879 E: de::Error,
880 {
881 self.visit_str(&v)
882 }
883 }
884
885 deserializer.deserialize_string(GenericVisitor {
886 _marker: std::marker::PhantomData,
887 })
888}
889
890#[derive(Debug, Clone, PartialEq)]
892pub struct NucleoMatcherConfig(pub nucleo::Config);
893
894impl Default for NucleoMatcherConfig {
895 fn default() -> Self {
896 Self(nucleo::Config::DEFAULT)
897 }
898}
899
900#[derive(Debug, Clone, Serialize, Deserialize)]
901#[serde(default)]
902#[derive(Default)]
903struct MatcherConfigHelper {
904 pub normalize: Option<bool>,
905 pub ignore_case: Option<bool>,
906 pub prefer_prefix: Option<bool>,
907}
908
909impl serde::Serialize for NucleoMatcherConfig {
910 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
911 where
912 S: serde::Serializer,
913 {
914 let helper = MatcherConfigHelper {
915 normalize: Some(self.0.normalize),
916 ignore_case: Some(self.0.ignore_case),
917 prefer_prefix: Some(self.0.prefer_prefix),
918 };
919 helper.serialize(serializer)
920 }
921}
922
923impl<'de> Deserialize<'de> for NucleoMatcherConfig {
924 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
925 where
926 D: serde::Deserializer<'de>,
927 {
928 let helper = MatcherConfigHelper::deserialize(deserializer)?;
929 let mut config = nucleo::Config::DEFAULT;
930
931 if let Some(norm) = helper.normalize {
932 config.normalize = norm;
933 }
934 if let Some(ic) = helper.ignore_case {
935 config.ignore_case = ic;
936 }
937 if let Some(pp) = helper.prefer_prefix {
938 config.prefer_prefix = pp;
939 }
940
941 Ok(NucleoMatcherConfig(config))
942 }
943}
944
945impl serde::Serialize for Split {
946 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
947 where
948 S: serde::Serializer,
949 {
950 match self {
951 Split::Delimiter(r) => serializer.serialize_str(r.as_str()),
952 Split::Regexes(rs) => {
953 let mut seq = serializer.serialize_seq(Some(rs.len()))?;
954 for r in rs {
955 seq.serialize_element(r.as_str())?;
956 }
957 seq.end()
958 }
959 Split::None => serializer.serialize_none(),
960 }
961 }
962}
963
964impl<'de> Deserialize<'de> for Split {
965 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
966 where
967 D: Deserializer<'de>,
968 {
969 struct SplitVisitor;
970
971 impl<'de> Visitor<'de> for SplitVisitor {
972 type Value = Split;
973
974 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
975 formatter.write_str("string for delimiter or array of strings for regexes")
976 }
977
978 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
979 where
980 E: de::Error,
981 {
982 Regex::new(value)
984 .map(Split::Delimiter)
985 .map_err(|e| E::custom(format!("Invalid regex: {}", e)))
986 }
987
988 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
989 where
990 A: serde::de::SeqAccess<'de>,
991 {
992 let mut regexes = Vec::new();
993 while let Some(s) = seq.next_element::<String>()? {
994 let r = Regex::new(&s)
995 .map_err(|e| de::Error::custom(format!("Invalid regex: {}", e)))?;
996 regexes.push(r);
997 }
998 Ok(Split::Regexes(regexes))
999 }
1000 }
1001
1002 deserializer.deserialize_any(SplitVisitor)
1003 }
1004}
1005
1006impl serde::Serialize for ColumnSetting {
1007 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1008 where
1009 S: serde::Serializer,
1010 {
1011 use serde::ser::SerializeStruct;
1012 let mut state = serializer.serialize_struct("ColumnSetting", 3)?;
1013 state.serialize_field("filter", &self.filter)?;
1014 state.serialize_field("hidden", &self.hidden)?;
1015 state.serialize_field("name", &self.name)?;
1016 state.end()
1017 }
1018}
1019
1020impl<'de> Deserialize<'de> for ColumnSetting {
1021 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1022 where
1023 D: Deserializer<'de>,
1024 {
1025 #[derive(Deserialize)]
1026 #[serde(deny_unknown_fields)]
1027 struct ColumnStruct {
1028 #[serde(default = "default_true")]
1029 filter: bool,
1030 #[serde(default)]
1031 hidden: bool,
1032 name: String,
1033 }
1034
1035 fn default_true() -> bool {
1036 true
1037 }
1038
1039 #[derive(Deserialize)]
1040 #[serde(untagged)]
1041 enum Input {
1042 Str(String),
1043 Obj(ColumnStruct),
1044 }
1045
1046 match Input::deserialize(deserializer)? {
1047 Input::Str(name) => Ok(ColumnSetting {
1048 filter: true,
1049 hidden: false,
1050 name,
1051 }),
1052 Input::Obj(obj) => Ok(ColumnSetting {
1053 filter: obj.filter,
1054 hidden: obj.hidden,
1055 name: obj.name,
1056 }),
1057 }
1058 }
1059}
1060
1061pub fn serialize_padding<S>(padding: &Padding, serializer: S) -> Result<S::Ok, S::Error>
1062where
1063 S: serde::Serializer,
1064{
1065 use serde::ser::SerializeSeq;
1066 if padding.top == padding.bottom && padding.left == padding.right && padding.top == padding.left
1067 {
1068 serializer.serialize_u16(padding.top)
1069 } else if padding.top == padding.bottom && padding.left == padding.right {
1070 let mut seq = serializer.serialize_seq(Some(2))?;
1071 seq.serialize_element(&padding.left)?;
1072 seq.serialize_element(&padding.top)?;
1073 seq.end()
1074 } else {
1075 let mut seq = serializer.serialize_seq(Some(4))?;
1076 seq.serialize_element(&padding.top)?;
1077 seq.serialize_element(&padding.right)?;
1078 seq.serialize_element(&padding.bottom)?;
1079 seq.serialize_element(&padding.left)?;
1080 seq.end()
1081 }
1082}
1083
1084pub fn deserialize_padding<'de, D>(deserializer: D) -> Result<Padding, D::Error>
1085where
1086 D: Deserializer<'de>,
1087{
1088 struct PaddingVisitor;
1089
1090 impl<'de> Visitor<'de> for PaddingVisitor {
1091 type Value = Padding;
1092
1093 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1094 formatter.write_str("a number or an array of 1, 2, or 4 numbers")
1095 }
1096
1097 fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
1098 where
1099 E: de::Error,
1100 {
1101 let v = u16::try_from(value).map_err(|_| {
1102 E::custom(format!("padding value {} is out of range for u16", value))
1103 })?;
1104
1105 Ok(Padding {
1106 top: v,
1107 right: v,
1108 bottom: v,
1109 left: v,
1110 })
1111 }
1112
1113 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
1114 where
1115 E: de::Error,
1116 {
1117 let v = u16::try_from(value).map_err(|_| {
1118 E::custom(format!("padding value {} is out of range for u16", value))
1119 })?;
1120
1121 Ok(Padding {
1122 top: v,
1123 right: v,
1124 bottom: v,
1125 left: v,
1126 })
1127 }
1128
1129 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
1131 where
1132 A: de::SeqAccess<'de>,
1133 {
1134 let first: u16 = seq
1135 .next_element()?
1136 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
1137
1138 let second: Option<u16> = seq.next_element()?;
1139 let third: Option<u16> = seq.next_element()?;
1140 let fourth: Option<u16> = seq.next_element()?;
1141
1142 match (second, third, fourth) {
1143 (None, None, None) => Ok(Padding {
1144 top: first,
1145 right: first,
1146 bottom: first,
1147 left: first,
1148 }),
1149 (Some(v2), None, None) => Ok(Padding {
1150 top: first,
1151 bottom: first,
1152 left: v2,
1153 right: v2,
1154 }),
1155 (Some(v2), Some(v3), Some(v4)) => Ok(Padding {
1156 top: first,
1157 right: v2,
1158 bottom: v3,
1159 left: v4,
1160 }),
1161 _ => Err(de::Error::invalid_length(3, &self)),
1162 }
1163 }
1164 }
1165
1166 deserializer.deserialize_any(PaddingVisitor)
1167}
1168
1169pub fn deserialize_option_auto<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
1170where
1171 D: serde::Deserializer<'de>,
1172 T: Deserialize<'de>,
1173{
1174 let opt = Option::<String>::deserialize(deserializer)?;
1175 match opt.as_deref() {
1176 Some("auto") => Ok(None),
1177 Some(s) => Ok(Some(T::deserialize(s.into_deserializer())?)),
1178 None => Ok(None),
1179 }
1180}
1181
1182impl<'de> Deserialize<'de> for BorderSetting {
1183 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1184 where
1185 D: Deserializer<'de>,
1186 {
1187 #[derive(Deserialize)]
1188 struct Helper {
1189 #[serde(default)]
1190 r#type: Option<String>,
1191 #[serde(default)]
1192 color: Option<Color>,
1193 #[serde(default, deserialize_with = "deserialize_borders_option")]
1194 sides: Option<Borders>, #[serde(default, deserialize_with = "deserialize_padding")]
1196 padding: Padding,
1197 #[serde(default)]
1198 title: String,
1199 #[serde(
1200 default,
1201 deserialize_with = "deserialize_modifier",
1202 serialize_with = "serialize_modifier"
1203 )]
1204 title_modifier: Modifier,
1205 #[serde(default)]
1206 bg: Color,
1207 }
1208
1209 let h = Helper::deserialize(deserializer)?;
1210
1211 let r#type = match h.r#type {
1213 Some(ref s) => s.parse::<BorderType>().map_err(serde::de::Error::custom)?,
1214 None => BorderType::default(),
1215 };
1216
1217 let sides = if let Some(sides) = h.sides {
1219 sides
1220 } else if h.r#type.is_some() || h.color.is_some() {
1221 Borders::ALL
1222 } else {
1223 Borders::NONE
1224 };
1225
1226 Ok(BorderSetting {
1227 r#type,
1228 color: h.color.unwrap_or_default(),
1229 sides,
1230 padding: h.padding,
1231 title: h.title,
1232 title_modifier: h.title_modifier,
1233 bg: h.bg,
1234 })
1235 }
1236}
1237
1238fn default_true() -> bool {
1241 true
1242}
1243
1244fn default_black() -> Color {
1245 Color::Black
1246}
1247
1248fn default_green() -> Color {
1249 Color::Green
1250}
1251
1252fn default_bold() -> Modifier {
1253 Modifier::BOLD
1254}
1255
1256fn default_italic() -> Modifier {
1257 Modifier::ITALIC
1258}