matchmaker/nucleo/
variants.rs1use std::{borrow::Cow, sync::Arc};
2
3use crate::{
4 PickerItem,
5};
6
7use super::{injector::{self, Indexed}, Text, worker::{Column, Worker}};
8
9impl<T: PickerItem> Worker<T> {
11 pub fn make_format_fn<const QUOTE: bool>(
13 &self,
14 blank_format: impl Fn(&T) -> &str + Send + Sync + 'static,
15 ) -> Box<dyn Fn(&T, &str) -> String + Send + Sync> {
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 mut 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 while let Some(c) = chars.next() {
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 + PickerItem> Worker<Indexed<T>> {
87 pub fn new_single() -> Self {
88 Self::new(
89 vec![Column::new("_", |item: &Indexed<T>, _context: &()| {
90 Text::from(item.inner.as_str())
91 })],
92 0,
93 (),
94 )
95 }
96
97 pub fn append(&self, items: impl IntoIterator<Item = T>) -> u32 {
99 let mut index = self.nucleo.snapshot().item_count();
100 for inner in items {
101 injector::push_impl(
102 &self.nucleo.injector(),
103 &self.columns,
104 Indexed { index, inner },
105 &(),
106 );
107 index += 1;
108 }
109 index
110 }
111
112 pub fn clone_identifier(item: &Indexed<T>) -> (u32, T)
113 where T: Clone {
114 (item.index, item.inner.clone())
115 }
116}
117
118pub trait ColumnIndexable {
119 fn index(&self, i: usize) -> &str;
120}
121
122impl<T> Worker<T>
123where
124T: ColumnIndexable + PickerItem,
125{
126 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}