1//! Hints (suggestions at the right of the prompt as you type).
23use crate::history::SearchDirection;
4use crate::Context;
56/// A hint returned by Hinter
7pub trait Hint {
8/// Text to display when hint is active
9fn display(&self) -> &str;
10/// Text to insert in line when right arrow is pressed
11fn completion(&self) -> Option<&str>;
12}
1314impl Hint for String {
15fn display(&self) -> &str {
16self.as_str()
17 }
1819fn completion(&self) -> Option<&str> {
20Some(self.as_str())
21 }
22}
2324/// Hints provider
25pub trait Hinter {
26/// Specific hint type
27type Hint: Hint + 'static;
2829/// Takes the currently edited `line` with the cursor `pos`ition and
30 /// returns the string that should be displayed or `None`
31 /// if no hint is available for the text the user currently typed.
32// TODO Validate: called while editing line but not while moving cursor.
33fn hint(&self, line: &str, pos: usize, ctx: &Context<'_>) -> Option<Self::Hint> {
34let _ = (line, pos, ctx);
35None
36}
37}
3839impl Hinter for () {
40type Hint = String;
41}
4243/// Add suggestion based on previous history entries matching current user
44/// input.
45#[derive(Default)]
46pub struct HistoryHinter {}
4748impl HistoryHinter {
49/// Create a new `HistoryHinter`
50pub fn new() -> Self {
51Self::default()
52 }
53}
5455impl Hinter for HistoryHinter {
56type Hint = String;
5758fn hint(&self, line: &str, pos: usize, ctx: &Context<'_>) -> Option<String> {
59if line.is_empty() || pos < line.len() {
60return None;
61 }
62let start = if ctx.history_index() == ctx.history().len() {
63 ctx.history_index().saturating_sub(1)
64 } else {
65 ctx.history_index()
66 };
67if let Some(sr) = ctx
68 .history
69 .starts_with(line, start, SearchDirection::Reverse)
70 .unwrap_or(None)
71 {
72if sr.entry == line {
73return None;
74 }
75return Some(sr.entry[pos..].to_owned());
76 }
77None
78}
79}
8081#[cfg(test)]
82mod test {
83use super::{Hinter, HistoryHinter};
84use crate::history::DefaultHistory;
85use crate::Context;
8687#[test]
88pub fn empty_history() {
89let history = DefaultHistory::new();
90let ctx = Context::new(&history);
91let hinter = HistoryHinter {};
92let hint = hinter.hint("test", 4, &ctx);
93assert_eq!(None, hint);
94 }
95}