aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlaž Hrastnik2020-12-15 10:29:56 +0000
committerBlaž Hrastnik2020-12-15 10:29:56 +0000
commit8f0b28aeb872797e4be3f07575e628f5f93e74e0 (patch)
tree10d7964d79cd2c6959e9f38be4682bea7c3b4754
parent1a843b6c06b5d4d75feb0a424bbfdcfb33ab7651 (diff)
Make the select prompt interactive.
-rw-r--r--helix-term/src/commands.rs47
-rw-r--r--helix-term/src/ui/mod.rs2
-rw-r--r--helix-term/src/ui/prompt.rs27
3 files changed, 59 insertions, 17 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index e49c780a..462d2a20 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -10,7 +10,7 @@ use helix_core::{
use once_cell::sync::Lazy;
use crate::compositor::Compositor;
-use crate::ui::Prompt;
+use crate::ui::{Prompt, PromptEvent};
use helix_view::{
document::Mode,
@@ -262,18 +262,37 @@ pub fn split_selection(cx: &mut Context) {
// # update state
// }
+ let snapshot = cx.view.doc.state.clone();
+
let prompt = Prompt::new(
"split:".to_string(),
|input: &str| Vec::new(), // this is fine because Vec::new() doesn't allocate
- |editor: &mut Editor, input: &str| {
- match Regex::new(input) {
- Ok(regex) => {
+ move |editor: &mut Editor, input: &str, event: PromptEvent| {
+ match event {
+ PromptEvent::Abort => {
+ // revert state
let view = editor.view_mut().unwrap();
- let text = &view.doc.text().slice(..);
- let selection = selection::split_on_matches(text, view.doc.selection(), &regex);
- view.doc.set_selection(selection);
+ view.doc.state = snapshot.clone();
+ }
+ PromptEvent::Validate => {
+ //
+ }
+ PromptEvent::Update => {
+ match Regex::new(input) {
+ Ok(regex) => {
+ let view = editor.view_mut().unwrap();
+
+ // revert state to what it was before the last update
+ view.doc.state = snapshot.clone();
+
+ let text = &view.doc.text().slice(..);
+ let selection =
+ selection::split_on_matches(text, view.doc.selection(), &regex);
+ view.doc.set_selection(selection);
+ }
+ Err(_) => (), // TODO: mark command line as error
+ }
}
- Err(_) => (), // TODO: mark command line as error
}
},
);
@@ -416,9 +435,15 @@ pub fn command_mode(cx: &mut Context) {
.filter(|command| command.contains(_input))
.collect()
}, // completion
- |editor: &mut Editor, input: &str| match input {
- "q" => editor.should_close = true,
- _ => (),
+ |editor: &mut Editor, input: &str, event: PromptEvent| {
+ if event != PromptEvent::Validate {
+ return;
+ }
+
+ match input {
+ "q" => editor.should_close = true,
+ _ => (),
+ }
},
);
compositor.push(Box::new(prompt));
diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs
index bc79e09c..9a70d1bd 100644
--- a/helix-term/src/ui/mod.rs
+++ b/helix-term/src/ui/mod.rs
@@ -2,7 +2,7 @@ mod editor;
mod prompt;
pub use editor::EditorView;
-pub use prompt::Prompt;
+pub use prompt::{Prompt, PromptEvent};
pub use tui::layout::Rect;
pub use tui::style::{Color, Modifier, Style};
diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs
index f5ef9477..07c0f917 100644
--- a/helix-term/src/ui/prompt.rs
+++ b/helix-term/src/ui/prompt.rs
@@ -12,14 +12,24 @@ pub struct Prompt {
pub completion: Vec<String>,
pub completion_selection_index: Option<usize>,
completion_fn: Box<dyn FnMut(&str) -> Vec<String>>,
- callback_fn: Box<dyn FnMut(&mut Editor, &str)>,
+ callback_fn: Box<dyn FnMut(&mut Editor, &str, PromptEvent)>,
+}
+
+#[derive(PartialEq)]
+pub enum PromptEvent {
+ /// The prompt input has been updated.
+ Update,
+ /// Validate and finalize the change.
+ Validate,
+ /// Abort the change, reverting to the initial state.
+ Abort,
}
impl Prompt {
pub fn new(
prompt: String,
mut completion_fn: impl FnMut(&str) -> Vec<String> + 'static,
- callback_fn: impl FnMut(&mut Editor, &str) + 'static,
+ callback_fn: impl FnMut(&mut Editor, &str, PromptEvent) + 'static,
) -> Prompt {
Prompt {
prompt,
@@ -160,10 +170,14 @@ impl Component for Prompt {
KeyEvent {
code: KeyCode::Char(c),
modifiers: KeyModifiers::NONE,
- } => self.insert_char(c),
+ } => {
+ self.insert_char(c);
+ (self.callback_fn)(cx.editor, &self.line, PromptEvent::Update);
+ }
KeyEvent {
code: KeyCode::Esc, ..
} => {
+ (self.callback_fn)(cx.editor, &self.line, PromptEvent::Abort);
return close_fn;
}
KeyEvent {
@@ -185,12 +199,15 @@ impl Component for Prompt {
KeyEvent {
code: KeyCode::Backspace,
modifiers: KeyModifiers::NONE,
- } => self.delete_char_backwards(),
+ } => {
+ self.delete_char_backwards();
+ (self.callback_fn)(cx.editor, &self.line, PromptEvent::Update);
+ }
KeyEvent {
code: KeyCode::Enter,
..
} => {
- (self.callback_fn)(cx.editor, &self.line);
+ (self.callback_fn)(cx.editor, &self.line, PromptEvent::Validate);
return close_fn;
}
KeyEvent {