matchmaker/nucleo/
variants.rs1use std::{borrow::Cow, sync::Arc};
2
3use crate::{
4 MMItem, RenderFn, nucleo::Indexed,
5};
6
7use super::{injector::{self}, Text, worker::{Column, Worker}};
8
9impl<T: MMItem> Worker<T> {
11 pub fn make_format_fn<const QUOTE: bool>(
13 &self,
14 blank_format: impl Fn(&T) -> &str + Send + Sync + 'static,
15 ) -> RenderFn<T> {
16 let columns = self.columns.clone();
17
18 Box::new(move |item: &T, template: &str| {
19 let mut result = String::with_capacity(template.len());
20 let chars = template.chars().peekable();
21 let mut state = State::Normal;
22 let mut key = String::new();
23
24 enum State {
25 Normal,
26 InKey,
27 Escape,
28 }
29
30 for c in chars {
31 match state {
32 State::Normal => match c {
33 '\\' => state = State::Escape,
34 '{' => state = State::InKey,
35 _ => result.push(c),
36 },
37 State::Escape => {
38 result.push(c);
39 state = State::Normal;
40 }
41 State::InKey => match c {
42 '}' => {
43 let replacement = match key.as_str() {
44 "" => Cow::Borrowed(blank_format(item)),
45 _ => columns
46 .iter()
47 .find(|col| &*col.name == key.as_str())
48 .map(|col| col.format_text(item, &()))
49 .unwrap_or_else(|| Cow::Borrowed("")),
50 };
51
52 if QUOTE {
53 result.push('\'');
54 result.push_str(&replacement);
55 result.push('\'');
56 } else {
57 result.push_str(&replacement);
58 }
59 key.clear();
60 state = State::Normal;
61 }
62 _ => key.push(c),
63 },
64 }
65 }
66
67 if !key.is_empty() {
68 result.push('{');
69 result.push_str(&key);
70 }
71
72 result
73 })
74 }
75}
76
77pub trait Render {
78 fn as_str(&self) -> &str;
79}
80impl<T: AsRef<str>> Render for T {
81 fn as_str(&self) -> &str {
82 self.as_ref()
83 }
84}
85
86impl<T: Render + MMItem> Worker<Indexed<T>> {
87 pub fn new_single_column() -> Self {
89 Self::new(
90 vec![Column::new("_", |item: &Indexed<T>, _context: &()| {
91 Text::from(item.inner.as_str())
92 })],
93 0,
94 (),
95 )
96 }
97
98 pub fn append(&self, items: impl IntoIterator<Item = T>) -> u32 {
100 let mut index = self.nucleo.snapshot().item_count();
101 for inner in items {
102 injector::push_impl(
103 &self.nucleo.injector(),
104 &self.columns,
105 Indexed { index, inner },
106 &(),
107 );
108 index += 1;
109 }
110 index
111 }
112}
113
114pub trait ColumnIndexable {
115 fn index(&self, i: usize) -> &str;
116}
117
118impl<T> Worker<T>
119where
120T: ColumnIndexable + MMItem,
121{
122 pub fn new_indexable<I, S>(column_names: I) -> Self
124 where
125 I: IntoIterator<Item = S>,
126 S: Into<Arc<str>>,
127 {
128 let columns = column_names.into_iter().enumerate().map(|(i, name)| {
129 let name = name.into();
130
131 Column::new(name, move |item: &T, _| {
132 let text = item.index(i);
133 Text::from(text)
134 })
135 });
136
137 Self::new(columns, 0, ())
138 }
139}