mirror of
https://github.com/nushell/reedline.git
synced 2024-09-11 15:55:50 +03:00
[API] Allow the Completer
impl to be stateful (#379)
Changes the completer trait to take a mutable reference of itself on calling `Completer::complete` This enables the `Completer` to do caching or other smart things on the fly.
This commit is contained in:
parent
698190c534
commit
6332747730
@ -30,13 +30,13 @@ impl Span {
|
||||
pub trait Completer: Send {
|
||||
/// the action that will take the line and position and convert it to a vector of completions, which include the
|
||||
/// span to replace and the contents of that replacement
|
||||
fn complete(&self, line: &str, pos: usize) -> Vec<Suggestion>;
|
||||
fn complete(&mut self, line: &str, pos: usize) -> Vec<Suggestion>;
|
||||
|
||||
/// action that will return a partial section of available completions
|
||||
/// this command comes handy when trying to avoid to pull all the data at once
|
||||
/// from the completer
|
||||
fn partial_complete(
|
||||
&self,
|
||||
&mut self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
start: usize,
|
||||
@ -50,7 +50,7 @@ pub trait Completer: Send {
|
||||
}
|
||||
|
||||
/// number of available completions
|
||||
fn total_completions(&self, line: &str, pos: usize) -> usize {
|
||||
fn total_completions(&mut self, line: &str, pos: usize) -> usize {
|
||||
self.complete(line, pos).len()
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,11 @@ impl CircularCompletionHandler {
|
||||
// in the line_buffer only the specified range of characters.
|
||||
// If internal index is 0 it means that is the first tab event pressed.
|
||||
// If internal index is greater than completions vector, we bring it back to 0.
|
||||
pub(crate) fn handle(&mut self, completer: &dyn Completer, present_buffer: &mut LineBuffer) {
|
||||
pub(crate) fn handle(
|
||||
&mut self,
|
||||
completer: &mut dyn Completer,
|
||||
present_buffer: &mut LineBuffer,
|
||||
) {
|
||||
if let Some(last_buffer) = &self.last_buffer {
|
||||
if last_buffer != present_buffer {
|
||||
self.reset_index();
|
||||
@ -93,58 +97,58 @@ mod test {
|
||||
#[test]
|
||||
fn repetitive_calls_to_handle_works() {
|
||||
let mut tab = CircularCompletionHandler::default();
|
||||
let comp = get_completer(vec!["login", "logout"]);
|
||||
let mut comp = get_completer(vec!["login", "logout"]);
|
||||
let mut buf = buffer_with("lo");
|
||||
tab.handle(&comp, &mut buf);
|
||||
tab.handle(&mut comp, &mut buf);
|
||||
|
||||
assert_eq!(buf, buffer_with("login"));
|
||||
tab.handle(&comp, &mut buf);
|
||||
tab.handle(&mut comp, &mut buf);
|
||||
assert_eq!(buf, buffer_with("logout"));
|
||||
tab.handle(&comp, &mut buf);
|
||||
tab.handle(&mut comp, &mut buf);
|
||||
assert_eq!(buf, buffer_with("lo"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn behaviour_with_hyphens_and_underscores() {
|
||||
let mut tab = CircularCompletionHandler::default();
|
||||
let comp = get_completer(vec!["test-hyphen", "test_underscore"]);
|
||||
let mut comp = get_completer(vec!["test-hyphen", "test_underscore"]);
|
||||
let mut buf = buffer_with("te");
|
||||
tab.handle(&comp, &mut buf);
|
||||
tab.handle(&mut comp, &mut buf);
|
||||
|
||||
assert_eq!(buf, buffer_with("test"));
|
||||
tab.handle(&comp, &mut buf);
|
||||
tab.handle(&mut comp, &mut buf);
|
||||
assert_eq!(buf, buffer_with("te"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_resets_on_new_query() {
|
||||
let mut tab = CircularCompletionHandler::default();
|
||||
let comp = get_completer(vec!["login", "logout", "exit"]);
|
||||
let mut comp = get_completer(vec!["login", "logout", "exit"]);
|
||||
let mut buf = buffer_with("log");
|
||||
tab.handle(&comp, &mut buf);
|
||||
tab.handle(&mut comp, &mut buf);
|
||||
|
||||
assert_eq!(buf, buffer_with("login"));
|
||||
let mut new_buf = buffer_with("ex");
|
||||
tab.handle(&comp, &mut new_buf);
|
||||
tab.handle(&mut comp, &mut new_buf);
|
||||
assert_eq!(new_buf, buffer_with("exit"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_string_different_places() {
|
||||
let mut tab = CircularCompletionHandler::default();
|
||||
let comp = get_completer(vec!["that", "this"]);
|
||||
let mut comp = get_completer(vec!["that", "this"]);
|
||||
let mut buf = buffer_with("th is my test th");
|
||||
|
||||
// Hitting tab after `th` fills the first completion `that`
|
||||
buf.set_insertion_point(2);
|
||||
tab.handle(&comp, &mut buf);
|
||||
tab.handle(&mut comp, &mut buf);
|
||||
let mut expected_buffer = buffer_with("that is my test th");
|
||||
expected_buffer.set_insertion_point(4);
|
||||
assert_eq!(buf, expected_buffer);
|
||||
|
||||
// updating the cursor to end should reset the completions
|
||||
buf.set_insertion_point(18);
|
||||
tab.handle(&comp, &mut buf);
|
||||
tab.handle(&mut comp, &mut buf);
|
||||
assert_eq!(buf, buffer_with("that is my test that"));
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ impl Completer for DefaultCompleter {
|
||||
/// Suggestion {value: "batmobile".into(), description: None, extra: None, span: Span { start: 7, end: 10 }},
|
||||
/// ]);
|
||||
/// ```
|
||||
fn complete(&self, line: &str, pos: usize) -> Vec<Suggestion> {
|
||||
fn complete(&mut self, line: &str, pos: usize) -> Vec<Suggestion> {
|
||||
let mut span_line_whitespaces = 0;
|
||||
let mut completions = vec![];
|
||||
if !line.is_empty() {
|
||||
|
@ -13,7 +13,7 @@ pub(crate) struct HistoryCompleter<'menu>(&'menu dyn History);
|
||||
unsafe impl<'menu> Send for HistoryCompleter<'menu> {}
|
||||
|
||||
impl<'menu> Completer for HistoryCompleter<'menu> {
|
||||
fn complete(&self, line: &str, pos: usize) -> Vec<Suggestion> {
|
||||
fn complete(&mut self, line: &str, pos: usize) -> Vec<Suggestion> {
|
||||
let parsed = parse_selection_char(line, SELECTION_CHAR);
|
||||
let values = self.0.query_entries(parsed.remainder);
|
||||
|
||||
@ -24,7 +24,7 @@ impl<'menu> Completer for HistoryCompleter<'menu> {
|
||||
}
|
||||
|
||||
fn partial_complete(
|
||||
&self,
|
||||
&mut self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
start: usize,
|
||||
@ -39,7 +39,7 @@ impl<'menu> Completer for HistoryCompleter<'menu> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn total_completions(&self, _line: &str, _pos: usize) -> usize {
|
||||
fn total_completions(&mut self, _line: &str, _pos: usize) -> usize {
|
||||
self.0.max_values()
|
||||
}
|
||||
}
|
||||
|
@ -382,7 +382,7 @@ mod test {
|
||||
}
|
||||
|
||||
fn str_to_edit_commands(s: &str) -> Vec<EditCommand> {
|
||||
s.chars().map(|c| EditCommand::InsertChar(c)).collect()
|
||||
s.chars().map(EditCommand::InsertChar).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -582,7 +582,7 @@ impl Reedline {
|
||||
if self.quick_completions && menu.can_quick_complete() {
|
||||
menu.update_values(
|
||||
self.editor.line_buffer(),
|
||||
self.completer.as_ref(),
|
||||
self.completer.as_mut(),
|
||||
self.history.as_ref(),
|
||||
);
|
||||
|
||||
@ -595,7 +595,7 @@ impl Reedline {
|
||||
&& menu.can_partially_complete(
|
||||
self.quick_completions,
|
||||
self.editor.line_buffer(),
|
||||
self.completer.as_ref(),
|
||||
self.completer.as_mut(),
|
||||
self.history.as_ref(),
|
||||
)
|
||||
{
|
||||
@ -692,7 +692,7 @@ impl Reedline {
|
||||
ReedlineEvent::ActionHandler => {
|
||||
let line_buffer = self.editor.line_buffer();
|
||||
self.circular_completion_handler
|
||||
.handle(self.completer.as_ref(), line_buffer);
|
||||
.handle(self.completer.as_mut(), line_buffer);
|
||||
Ok(EventStatus::Handled)
|
||||
}
|
||||
ReedlineEvent::Esc => {
|
||||
@ -770,7 +770,7 @@ impl Reedline {
|
||||
menu.menu_event(MenuEvent::Edit(self.quick_completions));
|
||||
menu.update_values(
|
||||
self.editor.line_buffer(),
|
||||
self.completer.as_ref(),
|
||||
self.completer.as_mut(),
|
||||
self.history.as_ref(),
|
||||
);
|
||||
|
||||
@ -1183,7 +1183,7 @@ impl Reedline {
|
||||
if menu.is_active() {
|
||||
menu.update_working_details(
|
||||
self.editor.line_buffer(),
|
||||
self.completer.as_ref(),
|
||||
self.completer.as_mut(),
|
||||
self.history.as_ref(),
|
||||
&self.painter,
|
||||
);
|
||||
|
@ -449,7 +449,7 @@ impl Menu for ColumnarMenu {
|
||||
&mut self,
|
||||
values_updated: bool,
|
||||
line_buffer: &mut LineBuffer,
|
||||
completer: &dyn Completer,
|
||||
completer: &mut dyn Completer,
|
||||
) -> bool {
|
||||
// If the values were already updated (e.g. quick completions are true)
|
||||
// there is no need to update the values from the menu
|
||||
@ -503,7 +503,7 @@ impl Menu for ColumnarMenu {
|
||||
}
|
||||
|
||||
/// Updates menu values
|
||||
fn update_values(&mut self, line_buffer: &mut LineBuffer, completer: &dyn Completer) {
|
||||
fn update_values(&mut self, line_buffer: &mut LineBuffer, completer: &mut dyn Completer) {
|
||||
if self.only_buffer_difference {
|
||||
if let Some(old_string) = &self.input {
|
||||
let (start, input) = string_difference(line_buffer.get_buffer(), old_string);
|
||||
@ -530,7 +530,7 @@ impl Menu for ColumnarMenu {
|
||||
fn update_working_details(
|
||||
&mut self,
|
||||
line_buffer: &mut LineBuffer,
|
||||
completer: &dyn Completer,
|
||||
completer: &mut dyn Completer,
|
||||
painter: &Painter,
|
||||
) {
|
||||
if let Some(event) = self.event.take() {
|
||||
|
@ -365,7 +365,7 @@ impl Menu for ListMenu {
|
||||
&mut self,
|
||||
_values_updated: bool,
|
||||
_line_buffer: &mut LineBuffer,
|
||||
_completer: &dyn Completer,
|
||||
_completer: &mut dyn Completer,
|
||||
) -> bool {
|
||||
false
|
||||
}
|
||||
@ -385,7 +385,7 @@ impl Menu for ListMenu {
|
||||
}
|
||||
|
||||
/// Collecting the value from the completer to be shown in the menu
|
||||
fn update_values(&mut self, line_buffer: &mut LineBuffer, completer: &dyn Completer) {
|
||||
fn update_values(&mut self, line_buffer: &mut LineBuffer, completer: &mut dyn Completer) {
|
||||
let (start, input) = if self.only_buffer_difference {
|
||||
match &self.input {
|
||||
Some(old_string) => {
|
||||
@ -471,7 +471,7 @@ impl Menu for ListMenu {
|
||||
fn update_working_details(
|
||||
&mut self,
|
||||
line_buffer: &mut LineBuffer,
|
||||
completer: &dyn Completer,
|
||||
completer: &mut dyn Completer,
|
||||
painter: &Painter,
|
||||
) {
|
||||
if let Some(event) = self.event.clone() {
|
||||
|
@ -83,7 +83,7 @@ pub trait Menu: Send {
|
||||
&mut self,
|
||||
values_updated: bool,
|
||||
line_buffer: &mut LineBuffer,
|
||||
completer: &dyn Completer,
|
||||
completer: &mut dyn Completer,
|
||||
) -> bool;
|
||||
|
||||
/// Updates the values presented in the menu
|
||||
@ -91,7 +91,7 @@ pub trait Menu: Send {
|
||||
/// activated or the `quick_completion` option is true, the len of the values
|
||||
/// is calculated to know if there is only one value so it can be selected
|
||||
/// immediately
|
||||
fn update_values(&mut self, line_buffer: &mut LineBuffer, completer: &dyn Completer);
|
||||
fn update_values(&mut self, line_buffer: &mut LineBuffer, completer: &mut dyn Completer);
|
||||
|
||||
/// The working details of a menu are values that could change based on
|
||||
/// the menu conditions before it being printed, such as the number or size
|
||||
@ -101,7 +101,7 @@ pub trait Menu: Send {
|
||||
fn update_working_details(
|
||||
&mut self,
|
||||
line_buffer: &mut LineBuffer,
|
||||
completer: &dyn Completer,
|
||||
completer: &mut dyn Completer,
|
||||
painter: &Painter,
|
||||
);
|
||||
|
||||
@ -158,7 +158,7 @@ impl ReedlineMenu {
|
||||
&mut self,
|
||||
values_updated: bool,
|
||||
line_buffer: &mut LineBuffer,
|
||||
completer: &dyn Completer,
|
||||
completer: &mut dyn Completer,
|
||||
history: &dyn History,
|
||||
) -> bool {
|
||||
match self {
|
||||
@ -166,39 +166,39 @@ impl ReedlineMenu {
|
||||
menu.can_partially_complete(values_updated, line_buffer, completer)
|
||||
}
|
||||
Self::HistoryMenu(menu) => {
|
||||
let history_completer = HistoryCompleter::new(history);
|
||||
menu.can_partially_complete(values_updated, line_buffer, &history_completer)
|
||||
let mut history_completer = HistoryCompleter::new(history);
|
||||
menu.can_partially_complete(values_updated, line_buffer, &mut history_completer)
|
||||
}
|
||||
Self::WithCompleter {
|
||||
menu,
|
||||
completer: own_completer,
|
||||
} => menu.can_partially_complete(values_updated, line_buffer, own_completer.as_ref()),
|
||||
} => menu.can_partially_complete(values_updated, line_buffer, own_completer.as_mut()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update_values(
|
||||
&mut self,
|
||||
line_buffer: &mut LineBuffer,
|
||||
completer: &dyn Completer,
|
||||
completer: &mut dyn Completer,
|
||||
history: &dyn History,
|
||||
) {
|
||||
match self {
|
||||
Self::EngineCompleter(menu) => menu.update_values(line_buffer, completer),
|
||||
Self::HistoryMenu(menu) => {
|
||||
let history_completer = HistoryCompleter::new(history);
|
||||
menu.update_values(line_buffer, &history_completer)
|
||||
let mut history_completer = HistoryCompleter::new(history);
|
||||
menu.update_values(line_buffer, &mut history_completer)
|
||||
}
|
||||
Self::WithCompleter {
|
||||
menu,
|
||||
completer: own_completer,
|
||||
} => menu.update_values(line_buffer, own_completer.as_ref()),
|
||||
} => menu.update_values(line_buffer, own_completer.as_mut()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update_working_details(
|
||||
&mut self,
|
||||
line_buffer: &mut LineBuffer,
|
||||
completer: &dyn Completer,
|
||||
completer: &mut dyn Completer,
|
||||
history: &dyn History,
|
||||
painter: &Painter,
|
||||
) {
|
||||
@ -207,13 +207,13 @@ impl ReedlineMenu {
|
||||
menu.update_working_details(line_buffer, completer, painter)
|
||||
}
|
||||
Self::HistoryMenu(menu) => {
|
||||
let history_completer = HistoryCompleter::new(history);
|
||||
menu.update_working_details(line_buffer, &history_completer, painter)
|
||||
let mut history_completer = HistoryCompleter::new(history);
|
||||
menu.update_working_details(line_buffer, &mut history_completer, painter)
|
||||
}
|
||||
Self::WithCompleter {
|
||||
menu,
|
||||
completer: own_completer,
|
||||
} => menu.update_working_details(line_buffer, own_completer.as_ref(), painter),
|
||||
} => menu.update_working_details(line_buffer, own_completer.as_mut(), painter),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -243,7 +243,7 @@ impl Menu for ReedlineMenu {
|
||||
&mut self,
|
||||
values_updated: bool,
|
||||
line_buffer: &mut LineBuffer,
|
||||
completer: &dyn Completer,
|
||||
completer: &mut dyn Completer,
|
||||
) -> bool {
|
||||
match self {
|
||||
Self::EngineCompleter(menu) => {
|
||||
@ -255,25 +255,25 @@ impl Menu for ReedlineMenu {
|
||||
Self::WithCompleter {
|
||||
menu,
|
||||
completer: own_completer,
|
||||
} => menu.can_partially_complete(values_updated, line_buffer, own_completer.as_ref()),
|
||||
} => menu.can_partially_complete(values_updated, line_buffer, own_completer.as_mut()),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_values(&mut self, line_buffer: &mut LineBuffer, completer: &dyn Completer) {
|
||||
fn update_values(&mut self, line_buffer: &mut LineBuffer, completer: &mut dyn Completer) {
|
||||
match self {
|
||||
Self::EngineCompleter(menu) => menu.update_values(line_buffer, completer),
|
||||
Self::HistoryMenu(menu) => menu.update_values(line_buffer, completer),
|
||||
Self::WithCompleter {
|
||||
menu,
|
||||
completer: own_completer,
|
||||
} => menu.update_values(line_buffer, own_completer.as_ref()),
|
||||
} => menu.update_values(line_buffer, own_completer.as_mut()),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_working_details(
|
||||
&mut self,
|
||||
line_buffer: &mut LineBuffer,
|
||||
completer: &dyn Completer,
|
||||
completer: &mut dyn Completer,
|
||||
painter: &Painter,
|
||||
) {
|
||||
match self {
|
||||
@ -284,7 +284,7 @@ impl Menu for ReedlineMenu {
|
||||
Self::WithCompleter {
|
||||
menu,
|
||||
completer: own_completer,
|
||||
} => menu.update_working_details(line_buffer, own_completer.as_ref(), painter),
|
||||
} => menu.update_working_details(line_buffer, own_completer.as_mut(), painter),
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user