mirror of https://github.com/helix-editor/helix
Make the select prompt interactive.
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,18 +262,37 @@ 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 Regex::new(input) {
|
match event {
|
||||||
Ok(regex) => {
|
PromptEvent::Abort => {
|
||||||
|
// revert state
|
||||||
let view = editor.view_mut().unwrap();
|
let view = editor.view_mut().unwrap();
|
||||||
let text = &view.doc.text().slice(..);
|
view.doc.state = snapshot.clone();
|
||||||
let selection = selection::split_on_matches(text, view.doc.selection(), ®ex);
|
}
|
||||||
view.doc.set_selection(selection);
|
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(), ®ex);
|
||||||
|
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| {
|
||||||
"q" => editor.should_close = true,
|
if event != PromptEvent::Validate {
|
||||||
_ => (),
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match input {
|
||||||
|
"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…
Reference in New Issue