Skip to main content

matchmaker/nucleo/
mod.rs

1pub mod injector;
2pub mod query;
3pub mod variants;
4mod worker;
5
6use std::{
7    borrow::Cow,
8    fmt::{self, Display, Formatter},
9    hash::{Hash, Hasher},
10    ops::Range,
11};
12
13use arrayvec::ArrayVec;
14pub use variants::*;
15pub use worker::*;
16
17pub use nucleo;
18pub use ratatui::prelude::*;
19
20use crate::{MAX_SPLITS, SSS};
21
22// ------------- Wrapper structs
23pub trait SegmentableItem: SSS {
24    fn slice(&self, range: Range<usize>) -> ratatui::text::Text<'_>;
25}
26
27impl SegmentableItem for String {
28    fn slice(&self, range: Range<usize>) -> ratatui::text::Text<'_> {
29        ratatui::text::Text::from(&self[range])
30    }
31}
32
33/// This struct implements ColumnIndexable, and can instantiate a worker with columns.
34#[derive(Debug, Clone, Hash, Eq, PartialEq)]
35pub struct Segmented<T> {
36    pub inner: T,
37    ranges: ArrayVec<(usize, usize), MAX_SPLITS>,
38}
39
40impl<T: SegmentableItem> ColumnIndexable for Segmented<T> {
41    // fn get_str(&self, index: usize) -> Cow<'_, str> {
42    //     if let Some((start, end)) = self.ranges.get(index) {
43    //         &self.inner[*start..*end]
44    //     } else {
45    //         ""
46    //     }
47    //     .into()
48    // }
49
50    fn get_text(&self, i: usize) -> Text<'_> {
51        if let Some((start, end)) = self.ranges.get(i) {
52            self.inner.slice(*start..*end)
53        } else {
54            Text::default()
55        }
56    }
57}
58
59impl<T: SegmentableItem> Segmented<T> {
60    pub fn len(&self) -> usize {
61        // Find the last range that is nonempty (start != end)
62        self.ranges
63            .iter()
64            .rposition(|&(start, end)| start != end)
65            .map_or(0, |idx| idx + 1)
66    }
67
68    pub fn is_empty(&self) -> bool {
69        self.len() == 0
70    }
71
72    pub fn map_to_vec<U, F>(&self, f: F) -> ArrayVec<U, MAX_SPLITS>
73    where
74        F: Fn(&T, usize, usize) -> U,
75    {
76        self.ranges
77            .iter()
78            .take(self.len()) // only map the "active" ranges
79            .map(|&(start, end)| f(&self.inner, start, end))
80            .collect()
81    }
82}
83
84impl<T> std::ops::Deref for Segmented<T> {
85    type Target = T;
86
87    fn deref(&self) -> &Self::Target {
88        &self.inner
89    }
90}
91
92// ------------------------------------------------
93
94#[derive(Debug, Clone)]
95pub struct Indexed<T> {
96    pub index: u32,
97    pub inner: T,
98}
99
100impl<T: Clone> Indexed<T> {
101    /// Matchmaker requires a way to identify and store selected items from their references in the nucleo matcher. This method simply identifies them by their insertion index and stores the clones of the items.
102    pub fn identifier(&self) -> (u32, T) {
103        (self.index, self.inner.clone())
104    }
105}
106
107impl<T> Indexed<T> {
108    /// Matchmaker requires a way to identify and store selected items from their references in the nucleo matcher. This method simply identifies them by their insertion index and is intended when the output type is not needed (i.e. externally managed).
109    pub fn dummy_identifier(&self) -> (u32, ()) {
110        (self.index, ())
111    }
112}
113
114impl<T: ColumnIndexable> ColumnIndexable for Indexed<T> {
115    fn get_str(&self, index: usize) -> Cow<'_, str> {
116        self.inner.get_str(index)
117    }
118
119    fn get_text(&self, i: usize) -> Text<'_> {
120        self.inner.get_text(i)
121    }
122}
123
124impl<T: Render> Render for Indexed<T> {
125    fn as_str(&self) -> Cow<'_, str> {
126        self.inner.as_str()
127    }
128    fn as_text(&self) -> Text<'_> {
129        self.inner.as_text()
130    }
131}
132
133impl<T> std::ops::Deref for Indexed<T> {
134    type Target = T;
135
136    fn deref(&self) -> &Self::Target {
137        &self.inner
138    }
139}
140
141// ------------------------------------------
142impl<T: Display + SegmentableItem> Display for Segmented<T> {
143    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
144        write!(f, "{}", self.inner)
145    }
146}
147
148impl<T: Display> Display for Indexed<T> {
149    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
150        write!(f, "{}", self.inner)
151    }
152}
153
154impl<T> PartialEq for Indexed<T> {
155    fn eq(&self, other: &Self) -> bool {
156        self.index == other.index
157    }
158}
159
160impl<T> Eq for Indexed<T> {}
161
162impl<T> Hash for Indexed<T> {
163    fn hash<H: Hasher>(&self, state: &mut H) {
164        self.index.hash(state)
165    }
166}