Make the select prompt interactive.

imgbot
Blaž Hrastnik 4 years ago
parent 1a843b6c06
commit 8f0b28aeb8

@ -10,7 +10,7 @@ use helix_core::{
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use crate::compositor::Compositor; use crate::compositor::Compositor;
use crate::ui::Prompt; use crate::ui::{Prompt, PromptEvent};
use helix_view::{ use helix_view::{
document::Mode, document::Mode,
@ -262,19 +262,38 @@ pub fn split_selection(cx: &mut Context) {
// # update state // # update state
// } // }
let snapshot = cx.view.doc.state.clone();
let prompt = Prompt::new( let prompt = Prompt::new(
"split:".to_string(), "split:".to_string(),
|input: &str| Vec::new(), // this is fine because Vec::new() doesn't allocate |input: &str| Vec::new(), // this is fine because Vec::new() doesn't allocate
|editor: &mut Editor, input: &str| { move |editor: &mut Editor, input: &str, event: PromptEvent| {
match event {
PromptEvent::Abort => {
// revert state
let view = editor.view_mut().unwrap();
view.doc.state = snapshot.clone();
}
PromptEvent::Validate => {
//
}
PromptEvent::Update => {
match Regex::new(input) { match Regex::new(input) {
Ok(regex) => { Ok(regex) => {
let view = editor.view_mut().unwrap(); 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 text = &view.doc.text().slice(..);
let selection = selection::split_on_matches(text, view.doc.selection(), &regex); let selection =
selection::split_on_matches(text, view.doc.selection(), &regex);
view.doc.set_selection(selection); 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)) .filter(|command| command.contains(_input))
.collect() .collect()
}, // completion }, // completion
|editor: &mut Editor, input: &str| match input { |editor: &mut Editor, input: &str, event: PromptEvent| {
if event != PromptEvent::Validate {
return;
}
match input {
"q" => editor.should_close = true, "q" => editor.should_close = true,
_ => (), _ => (),
}
}, },
); );
compositor.push(Box::new(prompt)); compositor.push(Box::new(prompt));

@ -2,7 +2,7 @@ mod editor;
mod prompt; mod prompt;
pub use editor::EditorView; pub use editor::EditorView;
pub use prompt::Prompt; pub use prompt::{Prompt, PromptEvent};
pub use tui::layout::Rect; pub use tui::layout::Rect;
pub use tui::style::{Color, Modifier, Style}; pub use tui::style::{Color, Modifier, Style};

@ -12,14 +12,24 @@ pub struct Prompt {
pub completion: Vec<String>, pub completion: Vec<String>,
pub completion_selection_index: Option<usize>, pub completion_selection_index: Option<usize>,
completion_fn: Box<dyn FnMut(&str) -> Vec<String>>, 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 { impl Prompt {
pub fn new( pub fn new(
prompt: String, prompt: String,
mut completion_fn: impl FnMut(&str) -> Vec<String> + 'static, 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 { Prompt {
prompt, prompt,
@ -160,10 +170,14 @@ impl Component for Prompt {
KeyEvent { KeyEvent {
code: KeyCode::Char(c), code: KeyCode::Char(c),
modifiers: KeyModifiers::NONE, modifiers: KeyModifiers::NONE,
} => self.insert_char(c), } => {
self.insert_char(c);
(self.callback_fn)(cx.editor, &self.line, PromptEvent::Update);
}
KeyEvent { KeyEvent {
code: KeyCode::Esc, .. code: KeyCode::Esc, ..
} => { } => {
(self.callback_fn)(cx.editor, &self.line, PromptEvent::Abort);
return close_fn; return close_fn;
} }
KeyEvent { KeyEvent {
@ -185,12 +199,15 @@ impl Component for Prompt {
KeyEvent { KeyEvent {
code: KeyCode::Backspace, code: KeyCode::Backspace,
modifiers: KeyModifiers::NONE, modifiers: KeyModifiers::NONE,
} => self.delete_char_backwards(), } => {
self.delete_char_backwards();
(self.callback_fn)(cx.editor, &self.line, PromptEvent::Update);
}
KeyEvent { KeyEvent {
code: KeyCode::Enter, code: KeyCode::Enter,
.. ..
} => { } => {
(self.callback_fn)(cx.editor, &self.line); (self.callback_fn)(cx.editor, &self.line, PromptEvent::Validate);
return close_fn; return close_fn;
} }
KeyEvent { KeyEvent {

Loading…
Cancel
Save