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