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