1use improv_core_model::functions::{self, FnDef};
6
7pub struct FnHelp {
9 pub query: String,
11 pub results: Vec<&'static FnDef>,
13 pub selected: usize,
15 pub top: usize,
17 pub page: usize,
19}
20
21impl FnHelp {
22 pub fn new() -> FnHelp {
24 let mut h = FnHelp {
25 query: String::new(),
26 results: Vec::new(),
27 selected: 0,
28 top: 0,
29 page: 10,
30 };
31 h.refilter();
32 h
33 }
34
35 pub fn push(&mut self, c: char) {
37 self.query.push(c);
38 self.refilter();
39 }
40
41 pub fn pop(&mut self) {
43 self.query.pop();
44 self.refilter();
45 }
46
47 fn refilter(&mut self) {
48 self.results = functions::search(&self.query);
49 self.selected = 0;
50 self.top = 0;
51 }
52
53 pub fn step(&mut self, delta: isize) {
55 let max = self.results.len().saturating_sub(1) as isize;
56 self.selected = (self.selected as isize + delta).clamp(0, max) as usize;
57 }
58
59 pub fn page_by(&mut self, dir: isize) {
61 self.step(dir * self.page.max(1) as isize);
62 }
63
64 pub fn current(&self) -> Option<&'static FnDef> {
66 self.results.get(self.selected).copied()
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn search_filters_and_ranks() {
76 let mut h = FnHelp::new();
77 assert!(h.results.len() > 100, "empty query lists everything");
78 h.page = 5;
79 h.page_by(1);
80 assert_eq!(h.selected, 5);
81 for c in "pmt".chars() {
82 h.push(c);
83 }
84 assert_eq!(h.selected, 0, "typing resets the selection");
85 assert_eq!(h.current().unwrap().name, "PMT", "exact name first");
86 h.pop();
87 assert_eq!(h.query, "pm");
88 h.query.clear();
89 h.push('z');
90 h.push('z');
91 h.push('z');
92 h.push('q');
93 assert!(h.results.is_empty());
94 assert!(h.current().is_none());
95 h.step(1);
96 assert_eq!(h.selected, 0, "no results: nothing to move to");
97 }
98
99 #[test]
100 fn selection_clamps_to_the_list() {
101 let mut h = FnHelp::new();
102 h.step(-3);
103 assert_eq!(h.selected, 0);
104 h.page = 0; h.page_by(1);
106 assert_eq!(h.selected, 1);
107 h.step(isize::MAX / 2);
108 assert_eq!(h.selected, h.results.len() - 1);
109 }
110}