reedline/completion/
history.rs

1use std::ops::Deref;
2
3use crate::{
4    history::SearchQuery, menu_functions::parse_selection_char, Completer, History, Span,
5    Suggestion,
6};
7
8const SELECTION_CHAR: char = '!';
9
10// The HistoryCompleter is created just before updating the menu
11// It pulls data from the object that contains access to the History
12pub(crate) struct HistoryCompleter<'menu>(&'menu dyn History);
13
14// Safe to implement Send since the Historycompleter should only be used when
15// updating the menu and that must happen in the same thread
16unsafe impl<'menu> Send for HistoryCompleter<'menu> {}
17
18impl<'menu> Completer for HistoryCompleter<'menu> {
19    fn complete(&mut self, line: &str, pos: usize) -> Vec<Suggestion> {
20        let parsed = parse_selection_char(line, SELECTION_CHAR);
21        let values = self
22            .0
23            .search(SearchQuery::all_that_contain_rev(
24                parsed.remainder.to_string(),
25            ))
26            .expect("todo: error handling");
27
28        values
29            .into_iter()
30            .map(|value| self.create_suggestion(line, pos, value.command_line.deref()))
31            .collect()
32    }
33
34    // TODO: Implement `fn partial_complete()`
35
36    fn total_completions(&mut self, line: &str, _pos: usize) -> usize {
37        let parsed = parse_selection_char(line, SELECTION_CHAR);
38        let count = self
39            .0
40            .count(SearchQuery::all_that_contain_rev(
41                parsed.remainder.to_string(),
42            ))
43            .expect("todo: error handling");
44        count as usize
45    }
46}
47
48impl<'menu> HistoryCompleter<'menu> {
49    pub fn new(history: &'menu dyn History) -> Self {
50        Self(history)
51    }
52
53    fn create_suggestion(&self, line: &str, pos: usize, value: &str) -> Suggestion {
54        let span = Span {
55            start: pos,
56            end: pos + line.len(),
57        };
58
59        Suggestion {
60            value: value.to_string(),
61            description: None,
62            extra: None,
63            span,
64            append_whitespace: false,
65        }
66    }
67}