Basile Henry 1 month ago committed by GitHub
commit 3607921e12
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -31,6 +31,7 @@ pub struct Prompt {
selection: Option<usize>, selection: Option<usize>,
history_register: Option<char>, history_register: Option<char>,
history_pos: Option<usize>, history_pos: Option<usize>,
history_substring: Option<String>,
completion_fn: CompletionFn, completion_fn: CompletionFn,
callback_fn: CallbackFn, callback_fn: CallbackFn,
pub doc_fn: DocFn, pub doc_fn: DocFn,
@ -83,6 +84,7 @@ impl Prompt {
selection: None, selection: None,
history_register, history_register,
history_pos: None, history_pos: None,
history_substring: None,
completion_fn: Box::new(completion_fn), completion_fn: Box::new(completion_fn),
callback_fn: Box::new(callback_fn), callback_fn: Box::new(callback_fn),
doc_fn: Box::new(|_| None), doc_fn: Box::new(|_| None),
@ -96,6 +98,7 @@ impl Prompt {
self.line = line; self.line = line;
self.cursor = cursor; self.cursor = cursor;
self.recalculate_completion(editor); self.recalculate_completion(editor);
self.reset_history();
self self
} }
@ -232,12 +235,14 @@ impl Prompt {
self.cursor = pos; self.cursor = pos;
} }
self.recalculate_completion(cx.editor); self.recalculate_completion(cx.editor);
self.reset_history();
} }
pub fn insert_str(&mut self, s: &str, editor: &Editor) { pub fn insert_str(&mut self, s: &str, editor: &Editor) {
self.line.insert_str(self.cursor, s); self.line.insert_str(self.cursor, s);
self.cursor += s.len(); self.cursor += s.len();
self.recalculate_completion(editor); self.recalculate_completion(editor);
self.reset_history();
} }
pub fn move_cursor(&mut self, movement: Movement) { pub fn move_cursor(&mut self, movement: Movement) {
@ -259,6 +264,7 @@ impl Prompt {
self.cursor = pos; self.cursor = pos;
self.recalculate_completion(editor); self.recalculate_completion(editor);
self.reset_history();
} }
pub fn delete_char_forwards(&mut self, editor: &Editor) { pub fn delete_char_forwards(&mut self, editor: &Editor) {
@ -266,6 +272,7 @@ impl Prompt {
self.line.replace_range(self.cursor..pos, ""); self.line.replace_range(self.cursor..pos, "");
self.recalculate_completion(editor); self.recalculate_completion(editor);
self.reset_history();
} }
pub fn delete_word_backwards(&mut self, editor: &Editor) { pub fn delete_word_backwards(&mut self, editor: &Editor) {
@ -274,6 +281,7 @@ impl Prompt {
self.cursor = pos; self.cursor = pos;
self.recalculate_completion(editor); self.recalculate_completion(editor);
self.reset_history();
} }
pub fn delete_word_forwards(&mut self, editor: &Editor) { pub fn delete_word_forwards(&mut self, editor: &Editor) {
@ -281,6 +289,7 @@ impl Prompt {
self.line.replace_range(self.cursor..pos, ""); self.line.replace_range(self.cursor..pos, "");
self.recalculate_completion(editor); self.recalculate_completion(editor);
self.reset_history();
} }
pub fn kill_to_start_of_line(&mut self, editor: &Editor) { pub fn kill_to_start_of_line(&mut self, editor: &Editor) {
@ -289,6 +298,7 @@ impl Prompt {
self.cursor = pos; self.cursor = pos;
self.recalculate_completion(editor); self.recalculate_completion(editor);
self.reset_history();
} }
pub fn kill_to_end_of_line(&mut self, editor: &Editor) { pub fn kill_to_end_of_line(&mut self, editor: &Editor) {
@ -296,12 +306,19 @@ impl Prompt {
self.line.replace_range(self.cursor..pos, ""); self.line.replace_range(self.cursor..pos, "");
self.recalculate_completion(editor); self.recalculate_completion(editor);
self.reset_history();
} }
pub fn clear(&mut self, editor: &Editor) { pub fn clear(&mut self, editor: &Editor) {
self.line.clear(); self.line.clear();
self.cursor = 0; self.cursor = 0;
self.recalculate_completion(editor); self.recalculate_completion(editor);
self.reset_history();
}
pub fn reset_history(&mut self) {
self.history_pos = None;
self.history_substring = None;
} }
pub fn change_history( pub fn change_history(
@ -312,11 +329,15 @@ impl Prompt {
) { ) {
(self.callback_fn)(cx, &self.line, PromptEvent::Abort); (self.callback_fn)(cx, &self.line, PromptEvent::Abort);
let mut values = match cx.editor.registers.read(register, cx.editor) { let mut values = match cx.editor.registers.read(register, cx.editor) {
Some(values) if values.len() > 0 => values.rev(), Some(values) if values.len() > 0 => values.rev().enumerate(),
_ => return, _ => return,
}; };
let end = values.len().saturating_sub(1); // Using `history_pos` as the trigger so that we only consider updating
// the substring to match on when entering history
if self.history_pos.is_none() && !self.line.is_empty() {
self.history_substring = Some(self.line.clone())
}
let index = match direction { let index = match direction {
CompletionDirection::Forward => self.history_pos.map_or(0, |i| i + 1), CompletionDirection::Forward => self.history_pos.map_or(0, |i| i + 1),
@ -324,18 +345,41 @@ impl Prompt {
.history_pos .history_pos
.unwrap_or_else(|| values.len()) .unwrap_or_else(|| values.len())
.saturating_sub(1), .saturating_sub(1),
} };
.min(end);
let history_line = if let Some(substr) = self.history_substring.as_ref() {
match direction {
CompletionDirection::Forward => {
if index > 0 {
// Same as skip but without taking ownership
let _ = values.nth(index - 1);
}
values.find(|prev| prev.1.find(substr).is_some())
}
CompletionDirection::Backward => {
let r_index = values.len() - 1 - index;
if r_index > 0 {
// Same as skip but without taking ownership
let _ = values.nth_back(r_index - 1);
}
values.rfind(|prev| prev.1.find(substr).is_some())
}
}
} else {
values.nth(index)
};
self.line = values.nth(index).unwrap().to_string(); if let Some((index, line)) = history_line {
// Appease the borrow checker. self.line = line.to_string();
drop(values); // Appease the borrow checker.
drop(values);
self.history_pos = Some(index); self.history_pos = Some(index);
self.move_end(); self.move_end();
(self.callback_fn)(cx, &self.line, PromptEvent::Update); (self.callback_fn)(cx, &self.line, PromptEvent::Update);
self.recalculate_completion(cx.editor); self.recalculate_completion(cx.editor);
}
} }
pub fn change_completion_selection(&mut self, direction: CompletionDirection) { pub fn change_completion_selection(&mut self, direction: CompletionDirection) {
@ -357,6 +401,7 @@ impl Prompt {
self.line.replace_range(range.clone(), item); self.line.replace_range(range.clone(), item);
self.move_end(); self.move_end();
self.reset_history();
} }
pub fn exit_selection(&mut self) { pub fn exit_selection(&mut self) {
@ -492,6 +537,28 @@ impl Prompt {
) )
.into(); .into();
text.render(line_area, surface, cx); text.render(line_area, surface, cx);
} else if let Some((pre, substr, post)) =
self.history_substring.as_ref().and_then(|substr| {
self.line
.split_once(substr)
.map(|(pre, post)| (pre, substr, post))
})
{
surface.set_string(line_area.x, line_area.y, pre, prompt_color);
surface.set_string(
line_area.x + pre.len() as u16,
line_area.y,
substr,
selected_color,
);
surface.set_string(
line_area.x + (pre.len() + substr.len()) as u16,
line_area.y,
post,
prompt_color,
);
} else { } else {
surface.set_string(line_area.x, line_area.y, self.line.clone(), prompt_color); surface.set_string(line_area.x, line_area.y, self.line.clone(), prompt_color);
} }

@ -4,7 +4,7 @@ use super::*;
async fn test_history_completion() -> anyhow::Result<()> { async fn test_history_completion() -> anyhow::Result<()> {
test_key_sequence( test_key_sequence(
&mut AppBuilder::new().build()?, &mut AppBuilder::new().build()?,
Some(":asdf<ret>:theme d<C-n><tab>"), Some(":asdf<ret>:<C-n><tab>"),
Some(&|app| { Some(&|app| {
assert!(!app.editor.is_err()); assert!(!app.editor.is_err());
}), }),

Loading…
Cancel
Save