Make the prompt callback take a Context.

This commit is contained in:
Joe Neeman 2021-06-22 14:49:55 -05:00 committed by Blaž Hrastnik
parent 16883e7543
commit fd1ae35051
4 changed files with 87 additions and 81 deletions

View file

@ -28,7 +28,7 @@ use insert::*;
use movement::Movement; use movement::Movement;
use crate::{ use crate::{
compositor::{Callback, Component, Compositor}, compositor::{self, Callback, Component, Compositor},
ui::{self, Completion, Picker, Popup, Prompt, PromptEvent}, ui::{self, Completion, Picker, Popup, Prompt, PromptEvent},
}; };
@ -1032,30 +1032,32 @@ mod cmd {
pub alias: Option<&'static str>, pub alias: Option<&'static str>,
pub doc: &'static str, pub doc: &'static str,
// params, flags, helper, completer // params, flags, helper, completer
pub fun: fn(&mut Editor, &[&str], PromptEvent), pub fun: fn(&mut compositor::Context, &[&str], PromptEvent),
pub completer: Option<Completer>, pub completer: Option<Completer>,
} }
fn quit(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
// last view and we have unsaved changes // last view and we have unsaved changes
if editor.tree.views().count() == 1 && buffers_remaining_impl(editor) { if cx.editor.tree.views().count() == 1 && buffers_remaining_impl(cx.editor) {
return; return;
} }
editor.close(view!(editor).id, /* close_buffer */ false); cx.editor
.close(view!(cx.editor).id, /* close_buffer */ false);
} }
fn force_quit(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn force_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
editor.close(view!(editor).id, /* close_buffer */ false); cx.editor
.close(view!(cx.editor).id, /* close_buffer */ false);
} }
fn open(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn open(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
match args.get(0) { match args.get(0) {
Some(path) => { Some(path) => {
// TODO: handle error // TODO: handle error
editor.open(path.into(), Action::Replace); cx.editor.open(path.into(), Action::Replace);
} }
None => { None => {
editor.set_error("wrong argument count".to_string()); cx.editor.set_error("wrong argument count".to_string());
} }
}; };
} }
@ -1086,30 +1088,30 @@ mod cmd {
Ok(()) Ok(())
} }
fn write(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn write(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
let (view, doc) = current!(editor); let (view, doc) = current!(cx.editor);
if let Err(e) = write_impl(view, doc, args.first()) { if let Err(e) = write_impl(view, doc, args.first()) {
editor.set_error(e.to_string()); cx.editor.set_error(e.to_string());
}; };
} }
fn new_file(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn new_file(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
editor.new_file(Action::Replace); cx.editor.new_file(Action::Replace);
} }
fn format(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn format(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
let (view, doc) = current!(editor); let (view, doc) = current!(cx.editor);
doc.format(view.id) doc.format(view.id)
} }
fn set_indent_style(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn set_indent_style(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
use IndentStyle::*; use IndentStyle::*;
// If no argument, report current indent style. // If no argument, report current indent style.
if args.is_empty() { if args.is_empty() {
let style = current!(editor).1.indent_style; let style = current!(cx.editor).1.indent_style;
editor.set_status(match style { cx.editor.set_status(match style {
Tabs => "tabs".into(), Tabs => "tabs".into(),
Spaces(1) => "1 space".into(), Spaces(1) => "1 space".into(),
Spaces(n) if (2..=8).contains(&n) => format!("{} spaces", n), Spaces(n) if (2..=8).contains(&n) => format!("{} spaces", n),
@ -1131,22 +1133,23 @@ mod cmd {
}; };
if let Some(s) = style { if let Some(s) = style {
let doc = doc_mut!(editor); let doc = doc_mut!(cx.editor);
doc.indent_style = s; doc.indent_style = s;
} else { } else {
// Invalid argument. // Invalid argument.
editor.set_error(format!("invalid indent style '{}'", args[0],)); cx.editor
.set_error(format!("invalid indent style '{}'", args[0],));
} }
} }
/// Sets or reports the current document's line ending setting. /// Sets or reports the current document's line ending setting.
fn set_line_ending(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn set_line_ending(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
use LineEnding::*; use LineEnding::*;
// If no argument, report current line ending setting. // If no argument, report current line ending setting.
if args.is_empty() { if args.is_empty() {
let line_ending = current!(editor).1.line_ending; let line_ending = current!(cx.editor).1.line_ending;
editor.set_status(match line_ending { cx.editor.set_status(match line_ending {
Crlf => "crlf".into(), Crlf => "crlf".into(),
LF => "line feed".into(), LF => "line feed".into(),
FF => "form feed".into(), FF => "form feed".into(),
@ -1171,49 +1174,50 @@ mod cmd {
}; };
if let Some(le) = line_ending { if let Some(le) = line_ending {
doc_mut!(editor).line_ending = le; doc_mut!(cx.editor).line_ending = le;
} else { } else {
// Invalid argument. // Invalid argument.
editor.set_error(format!("invalid line ending '{}'", args[0],)); cx.editor
.set_error(format!("invalid line ending '{}'", args[0],));
} }
} }
fn earlier(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn earlier(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() { let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() {
Ok(uk) => uk, Ok(uk) => uk,
Err(msg) => { Err(msg) => {
editor.set_error(msg); cx.editor.set_error(msg);
return; return;
} }
}; };
let (view, doc) = current!(editor); let (view, doc) = current!(cx.editor);
doc.earlier(view.id, uk) doc.earlier(view.id, uk)
} }
fn later(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn later(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() { let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() {
Ok(uk) => uk, Ok(uk) => uk,
Err(msg) => { Err(msg) => {
editor.set_error(msg); cx.editor.set_error(msg);
return; return;
} }
}; };
let (view, doc) = current!(editor); let (view, doc) = current!(cx.editor);
doc.later(view.id, uk) doc.later(view.id, uk)
} }
fn write_quit(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn write_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
let (view, doc) = current!(editor); let (view, doc) = current!(cx.editor);
if let Err(e) = write_impl(view, doc, args.first()) { if let Err(e) = write_impl(view, doc, args.first()) {
editor.set_error(e.to_string()); cx.editor.set_error(e.to_string());
return; return;
}; };
quit(editor, &[], event) quit(cx, &[], event)
} }
fn force_write_quit(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn force_write_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
write(editor, args, event); write(cx, args, event);
force_quit(editor, &[], event); force_quit(cx, &[], event);
} }
/// Returns `true` if there are modified buffers remaining and sets editor error, /// Returns `true` if there are modified buffers remaining and sets editor error,
@ -1273,16 +1277,16 @@ mod cmd {
} }
} }
fn write_all(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn write_all(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
write_all_impl(editor, args, event, false, false) write_all_impl(&mut cx.editor, args, event, false, false)
} }
fn write_all_quit(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn write_all_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
write_all_impl(editor, args, event, true, false) write_all_impl(&mut cx.editor, args, event, true, false)
} }
fn force_write_all_quit(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn force_write_all_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
write_all_impl(editor, args, event, true, true) write_all_impl(&mut cx.editor, args, event, true, true)
} }
fn quit_all_impl(editor: &mut Editor, args: &[&str], event: PromptEvent, force: bool) { fn quit_all_impl(editor: &mut Editor, args: &[&str], event: PromptEvent, force: bool) {
@ -1297,50 +1301,50 @@ mod cmd {
} }
} }
fn quit_all(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn quit_all(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
quit_all_impl(editor, args, event, false) quit_all_impl(&mut cx.editor, args, event, false)
} }
fn force_quit_all(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn force_quit_all(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
quit_all_impl(editor, args, event, true) quit_all_impl(&mut cx.editor, args, event, true)
} }
fn theme(editor: &mut Editor, args: &[&str], event: PromptEvent) { fn theme(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
let theme = if let Some(theme) = args.first() { let theme = if let Some(theme) = args.first() {
theme theme
} else { } else {
editor.set_error("theme name not provided".into()); cx.editor.set_error("theme name not provided".into());
return; return;
}; };
editor.set_theme_from_name(theme); cx.editor.set_theme_from_name(theme);
} }
fn yank_main_selection_to_clipboard(editor: &mut Editor, _: &[&str], _: PromptEvent) { fn yank_main_selection_to_clipboard(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
yank_main_selection_to_clipboard_impl(editor); yank_main_selection_to_clipboard_impl(&mut cx.editor);
} }
fn yank_joined_to_clipboard(editor: &mut Editor, args: &[&str], _: PromptEvent) { fn yank_joined_to_clipboard(cx: &mut compositor::Context, args: &[&str], _: PromptEvent) {
let (_, doc) = current!(editor); let (_, doc) = current!(cx.editor);
let separator = args let separator = args
.first() .first()
.copied() .copied()
.unwrap_or_else(|| doc.line_ending.as_str()); .unwrap_or_else(|| doc.line_ending.as_str());
yank_joined_to_clipboard_impl(editor, separator); yank_joined_to_clipboard_impl(&mut cx.editor, separator);
} }
fn paste_clipboard_after(editor: &mut Editor, _: &[&str], _: PromptEvent) { fn paste_clipboard_after(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
paste_clipboard_impl(editor, Paste::After); paste_clipboard_impl(&mut cx.editor, Paste::After);
} }
fn paste_clipboard_before(editor: &mut Editor, _: &[&str], _: PromptEvent) { fn paste_clipboard_before(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
paste_clipboard_impl(editor, Paste::After); paste_clipboard_impl(&mut cx.editor, Paste::After);
} }
fn replace_selections_with_clipboard(editor: &mut Editor, _: &[&str], _: PromptEvent) { fn replace_selections_with_clipboard(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
let (view, doc) = current!(editor); let (view, doc) = current!(cx.editor);
match editor.clipboard_provider.get_contents() { match cx.editor.clipboard_provider.get_contents() {
Ok(contents) => { Ok(contents) => {
let transaction = let transaction =
Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| { Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
@ -1356,8 +1360,9 @@ mod cmd {
} }
} }
fn show_clipboard_provider(editor: &mut Editor, _: &[&str], _: PromptEvent) { fn show_clipboard_provider(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
editor.set_status(editor.clipboard_provider.name().into()); cx.editor
.set_status(cx.editor.clipboard_provider.name().into());
} }
fn change_current_directory(editor: &mut Editor, args: &[&str], _: PromptEvent) { fn change_current_directory(editor: &mut Editor, args: &[&str], _: PromptEvent) {
@ -1633,7 +1638,7 @@ fn command_mode(cx: &mut Context) {
} }
} }
}, // completion }, // completion
move |editor: &mut Editor, input: &str, event: PromptEvent| { move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
use helix_view::editor::Action; use helix_view::editor::Action;
if event != PromptEvent::Validate { if event != PromptEvent::Validate {
@ -1646,9 +1651,10 @@ fn command_mode(cx: &mut Context) {
} }
if let Some(cmd) = cmd::COMMANDS.get(parts[0]) { if let Some(cmd) = cmd::COMMANDS.get(parts[0]) {
(cmd.fun)(editor, &parts[1..], event); (cmd.fun)(cx, &parts[1..], event);
} else { } else {
editor.set_error(format!("no such command: '{}'", parts[0])); cx.editor
.set_error(format!("no such command: '{}'", parts[0]));
}; };
}, },
); );

View file

@ -39,10 +39,10 @@ pub fn regex_prompt(
Prompt::new( Prompt::new(
prompt, prompt,
|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
move |editor: &mut Editor, input: &str, event: PromptEvent| { move |cx: &mut crate::compositor::Context, input: &str, event: PromptEvent| {
match event { match event {
PromptEvent::Abort => { PromptEvent::Abort => {
let (view, doc) = current!(editor); let (view, doc) = current!(cx.editor);
doc.set_selection(view.id, snapshot.clone()); doc.set_selection(view.id, snapshot.clone());
} }
PromptEvent::Validate => { PromptEvent::Validate => {
@ -56,8 +56,8 @@ pub fn regex_prompt(
match Regex::new(input) { match Regex::new(input) {
Ok(regex) => { Ok(regex) => {
let (view, doc) = current!(editor); let (view, doc) = current!(cx.editor);
let registers = &mut editor.registers; let registers = &mut cx.editor.registers;
// revert state to what it was before the last update // revert state to what it was before the last update
doc.set_selection(view.id, snapshot.clone()); doc.set_selection(view.id, snapshot.clone());

View file

@ -44,7 +44,7 @@ impl<T> Picker<T> {
let prompt = Prompt::new( let prompt = Prompt::new(
"".to_string(), "".to_string(),
|pattern: &str| Vec::new(), |pattern: &str| Vec::new(),
|editor: &mut Editor, pattern: &str, event: PromptEvent| { |editor: &mut Context, pattern: &str, event: PromptEvent| {
// //
}, },
); );

View file

@ -20,7 +20,7 @@ pub struct Prompt {
completion: Vec<Completion>, completion: Vec<Completion>,
selection: Option<usize>, selection: Option<usize>,
completion_fn: Box<dyn FnMut(&str) -> Vec<Completion>>, completion_fn: Box<dyn FnMut(&str) -> Vec<Completion>>,
callback_fn: Box<dyn FnMut(&mut Editor, &str, PromptEvent)>, callback_fn: Box<dyn FnMut(&mut Context, &str, PromptEvent)>,
pub doc_fn: Box<dyn Fn(&str) -> Option<&'static str>>, pub doc_fn: Box<dyn Fn(&str) -> Option<&'static str>>,
} }
@ -54,7 +54,7 @@ impl Prompt {
pub fn new( pub fn new(
prompt: String, prompt: String,
mut completion_fn: impl FnMut(&str) -> Vec<Completion> + 'static, mut completion_fn: impl FnMut(&str) -> Vec<Completion> + 'static,
callback_fn: impl FnMut(&mut Editor, &str, PromptEvent) + 'static, callback_fn: impl FnMut(&mut Context, &str, PromptEvent) + 'static,
) -> Self { ) -> Self {
Self { Self {
prompt, prompt,
@ -386,7 +386,7 @@ impl Component for Prompt {
modifiers: KeyModifiers::SHIFT, modifiers: KeyModifiers::SHIFT,
} => { } => {
self.insert_char(c); self.insert_char(c);
(self.callback_fn)(cx.editor, &self.line, PromptEvent::Update); (self.callback_fn)(cx, &self.line, PromptEvent::Update);
} }
KeyEvent { KeyEvent {
code: KeyCode::Char('c'), code: KeyCode::Char('c'),
@ -395,7 +395,7 @@ impl Component for Prompt {
| KeyEvent { | KeyEvent {
code: KeyCode::Esc, .. code: KeyCode::Esc, ..
} => { } => {
(self.callback_fn)(cx.editor, &self.line, PromptEvent::Abort); (self.callback_fn)(cx, &self.line, PromptEvent::Abort);
return close_fn; return close_fn;
} }
KeyEvent { KeyEvent {
@ -459,7 +459,7 @@ impl Component for Prompt {
modifiers: KeyModifiers::NONE, modifiers: KeyModifiers::NONE,
} => { } => {
self.delete_char_backwards(); self.delete_char_backwards();
(self.callback_fn)(cx.editor, &self.line, PromptEvent::Update); (self.callback_fn)(cx, &self.line, PromptEvent::Update);
} }
KeyEvent { KeyEvent {
code: KeyCode::Enter, code: KeyCode::Enter,
@ -469,7 +469,7 @@ impl Component for Prompt {
self.completion = (self.completion_fn)(&self.line); self.completion = (self.completion_fn)(&self.line);
self.exit_selection(); self.exit_selection();
} else { } else {
(self.callback_fn)(cx.editor, &self.line, PromptEvent::Validate); (self.callback_fn)(cx, &self.line, PromptEvent::Validate);
return close_fn; return close_fn;
} }
} }