1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! Inline autosuggestions (fish/`zsh-autosuggestions`-style ghost text) for
//! [`EditLine`](crate::EditLine).
//!
//! A [`Suggester`] proposes a completion of the *current line* -- for example
//! the most recent matching history entry, or the single command that extends
//! what's been typed. The suggested suffix is shown, dimmed, immediately after
//! the cursor as the user types, and can be accepted with a key (by default
//! Ctrl-F or Right-arrow at end of line).
//!
//! # How this differs from a [`Hinter`](crate::hint::Hinter)
//!
//! A [`Hinter`](crate::hint::Hinter) renders through libedit's right-hand prompt
//! (`EL_RPROMPT`), so its text sits at the right edge of the line -- good for
//! a persistent status or help string, but visually detached from the cursor.
//! A [`Suggester`] instead renders **ghost text right after the cursor**, like
//! fish shell, by printing dimmed output past the caret on each keystroke and
//! moving the cursor back. Crucially the suggestion is *never* part of the
//! edit buffer, so pressing Enter, End, or a kill-line binding won't capture
//! it -- only the explicit accept key commits it.
//!
//! This mirrors the design used by LLDB's libedit integration.
//!
//! Register one with
//! [`EditLine::set_suggester`](crate::EditLine::set_suggester).
//!
//! # Example
//!
//! ```no_run
//! use libedit::{EditLine, LineContext};
//! use libedit::suggestion::Suggestion;
//!
//! let mut el = EditLine::new("cli").unwrap();
//! let history = ["show interfaces", "show version"];
//! el.set_suggester(move |ctx: &LineContext| {
//! let line = ctx.line();
//! if line.is_empty() {
//! return None;
//! }
//! // Suggest the remainder of the first history entry that starts with
//! // the current line.
//! history
//! .iter()
//! .find(|h| h.starts_with(line) && h.len() > line.len())
//! .map(|h| Suggestion::new(&h[line.len()..]))
//! }).unwrap();
//! ```
use crateLineContext;
/// A proposed inline completion of the current line.
///
/// The text is the **suffix** to display after the cursor (the part the user
/// has not yet typed), not the whole line.
/// A source of inline autosuggestions for an [`EditLine`](crate::EditLine).
///
/// Implement this (or pass a closure) and register it with
/// [`EditLine::set_suggester`](crate::EditLine::set_suggester). It is invoked
/// on every keystroke during [`readline`](crate::EditLine::readline); keep it
/// fast and non-blocking. Returning `None` shows no suggestion.
// Allow a plain closure to be used as a suggester for convenience.