|
|
|
@ -31,6 +31,7 @@ pub struct Prompt {
|
|
|
|
|
selection: Option<usize>,
|
|
|
|
|
history_register: Option<char>,
|
|
|
|
|
history_pos: Option<usize>,
|
|
|
|
|
history_substring: Option<String>,
|
|
|
|
|
completion_fn: CompletionFn,
|
|
|
|
|
callback_fn: CallbackFn,
|
|
|
|
|
pub doc_fn: DocFn,
|
|
|
|
@ -83,6 +84,7 @@ impl Prompt {
|
|
|
|
|
selection: None,
|
|
|
|
|
history_register,
|
|
|
|
|
history_pos: None,
|
|
|
|
|
history_substring: None,
|
|
|
|
|
completion_fn: Box::new(completion_fn),
|
|
|
|
|
callback_fn: Box::new(callback_fn),
|
|
|
|
|
doc_fn: Box::new(|_| None),
|
|
|
|
@ -96,6 +98,7 @@ impl Prompt {
|
|
|
|
|
self.line = line;
|
|
|
|
|
self.cursor = cursor;
|
|
|
|
|
self.recalculate_completion(editor);
|
|
|
|
|
self.reset_history();
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -232,12 +235,14 @@ impl Prompt {
|
|
|
|
|
self.cursor = pos;
|
|
|
|
|
}
|
|
|
|
|
self.recalculate_completion(cx.editor);
|
|
|
|
|
self.reset_history();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn insert_str(&mut self, s: &str, editor: &Editor) {
|
|
|
|
|
self.line.insert_str(self.cursor, s);
|
|
|
|
|
self.cursor += s.len();
|
|
|
|
|
self.recalculate_completion(editor);
|
|
|
|
|
self.reset_history();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn move_cursor(&mut self, movement: Movement) {
|
|
|
|
@ -259,6 +264,7 @@ impl Prompt {
|
|
|
|
|
self.cursor = pos;
|
|
|
|
|
|
|
|
|
|
self.recalculate_completion(editor);
|
|
|
|
|
self.reset_history();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn delete_char_forwards(&mut self, editor: &Editor) {
|
|
|
|
@ -266,6 +272,7 @@ impl Prompt {
|
|
|
|
|
self.line.replace_range(self.cursor..pos, "");
|
|
|
|
|
|
|
|
|
|
self.recalculate_completion(editor);
|
|
|
|
|
self.reset_history();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn delete_word_backwards(&mut self, editor: &Editor) {
|
|
|
|
@ -274,6 +281,7 @@ impl Prompt {
|
|
|
|
|
self.cursor = pos;
|
|
|
|
|
|
|
|
|
|
self.recalculate_completion(editor);
|
|
|
|
|
self.reset_history();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn delete_word_forwards(&mut self, editor: &Editor) {
|
|
|
|
@ -281,6 +289,7 @@ impl Prompt {
|
|
|
|
|
self.line.replace_range(self.cursor..pos, "");
|
|
|
|
|
|
|
|
|
|
self.recalculate_completion(editor);
|
|
|
|
|
self.reset_history();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn kill_to_start_of_line(&mut self, editor: &Editor) {
|
|
|
|
@ -289,6 +298,7 @@ impl Prompt {
|
|
|
|
|
self.cursor = pos;
|
|
|
|
|
|
|
|
|
|
self.recalculate_completion(editor);
|
|
|
|
|
self.reset_history();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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.recalculate_completion(editor);
|
|
|
|
|
self.reset_history();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn clear(&mut self, editor: &Editor) {
|
|
|
|
|
self.line.clear();
|
|
|
|
|
self.cursor = 0;
|
|
|
|
|
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(
|
|
|
|
@ -312,11 +329,15 @@ impl Prompt {
|
|
|
|
|
) {
|
|
|
|
|
(self.callback_fn)(cx, &self.line, PromptEvent::Abort);
|
|
|
|
|
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,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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 {
|
|
|
|
|
CompletionDirection::Forward => self.history_pos.map_or(0, |i| i + 1),
|
|
|
|
@ -324,18 +345,41 @@ impl Prompt {
|
|
|
|
|
.history_pos
|
|
|
|
|
.unwrap_or_else(|| values.len())
|
|
|
|
|
.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();
|
|
|
|
|
// Appease the borrow checker.
|
|
|
|
|
drop(values);
|
|
|
|
|
if let Some((index, line)) = history_line {
|
|
|
|
|
self.line = line.to_string();
|
|
|
|
|
// Appease the borrow checker.
|
|
|
|
|
drop(values);
|
|
|
|
|
|
|
|
|
|
self.history_pos = Some(index);
|
|
|
|
|
self.history_pos = Some(index);
|
|
|
|
|
|
|
|
|
|
self.move_end();
|
|
|
|
|
(self.callback_fn)(cx, &self.line, PromptEvent::Update);
|
|
|
|
|
self.recalculate_completion(cx.editor);
|
|
|
|
|
self.move_end();
|
|
|
|
|
(self.callback_fn)(cx, &self.line, PromptEvent::Update);
|
|
|
|
|
self.recalculate_completion(cx.editor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn change_completion_selection(&mut self, direction: CompletionDirection) {
|
|
|
|
@ -357,6 +401,7 @@ impl Prompt {
|
|
|
|
|
self.line.replace_range(range.clone(), item);
|
|
|
|
|
|
|
|
|
|
self.move_end();
|
|
|
|
|
self.reset_history();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn exit_selection(&mut self) {
|
|
|
|
@ -492,6 +537,28 @@ impl Prompt {
|
|
|
|
|
)
|
|
|
|
|
.into();
|
|
|
|
|
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 {
|
|
|
|
|
surface.set_string(line_area.x, line_area.y, self.line.clone(), prompt_color);
|
|
|
|
|
}
|
|
|
|
|