Improve command mode handling.
This commit is contained in:
parent
243456a583
commit
9604a0c294
1 changed files with 117 additions and 50 deletions
|
@ -809,7 +809,115 @@ pub fn append_mode(cx: &mut Context) {
|
|||
doc.set_selection(view.id, selection);
|
||||
}
|
||||
|
||||
const COMMAND_LIST: &[&str] = &["write", "open", "quit", "quit!"];
|
||||
mod cmd {
|
||||
use super::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use helix_view::editor::Action;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Command {
|
||||
pub name: &'static str,
|
||||
pub alias: Option<&'static str>,
|
||||
pub doc: &'static str,
|
||||
// params, flags, helper, completer
|
||||
pub fun: fn(&mut Editor, &[&str], PromptEvent),
|
||||
}
|
||||
|
||||
fn quit(editor: &mut Editor, args: &[&str], event: PromptEvent) {
|
||||
// last view and we have unsaved changes
|
||||
if editor.tree.views().count() == 1 {
|
||||
let modified: Vec<_> = editor
|
||||
.documents()
|
||||
.filter(|doc| doc.is_modified())
|
||||
.map(|doc| {
|
||||
doc.relative_path()
|
||||
.and_then(|path| path.to_str())
|
||||
.unwrap_or("[scratch]")
|
||||
})
|
||||
.collect();
|
||||
|
||||
if !modified.is_empty() {
|
||||
let err = format!(
|
||||
"{} unsaved buffer(s) remaining: {:?}",
|
||||
modified.len(),
|
||||
modified
|
||||
);
|
||||
editor.set_error(err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
editor.close(editor.view().id, /* close_buffer */ false);
|
||||
}
|
||||
|
||||
fn force_quit(editor: &mut Editor, args: &[&str], event: PromptEvent) {
|
||||
editor.close(editor.view().id, /* close_buffer */ false);
|
||||
}
|
||||
|
||||
fn open(editor: &mut Editor, args: &[&str], event: PromptEvent) {
|
||||
let path = args[0];
|
||||
editor.open(path.into(), Action::Replace);
|
||||
}
|
||||
|
||||
fn write(editor: &mut Editor, args: &[&str], event: PromptEvent) {
|
||||
let id = editor.view().doc;
|
||||
let doc = &mut editor.documents[id];
|
||||
if doc.path().is_none() {
|
||||
editor.set_error("cannot write a buffer without a filename".to_string());
|
||||
return;
|
||||
}
|
||||
tokio::spawn(doc.save());
|
||||
}
|
||||
fn new_file(editor: &mut Editor, args: &[&str], event: PromptEvent) {
|
||||
editor.new_file(Action::Replace);
|
||||
}
|
||||
|
||||
pub const COMMAND_LIST: &[Command] = &[
|
||||
Command {
|
||||
name: "quit",
|
||||
alias: Some("q"),
|
||||
doc: "Close the current view.",
|
||||
fun: quit,
|
||||
},
|
||||
Command {
|
||||
name: "quit!",
|
||||
alias: Some("q!"),
|
||||
doc: "Close the current view.",
|
||||
fun: force_quit,
|
||||
},
|
||||
Command {
|
||||
name: "open",
|
||||
alias: Some("o"),
|
||||
doc: "Open a file from disk into the current view.",
|
||||
fun: open,
|
||||
},
|
||||
Command {
|
||||
name: "write",
|
||||
alias: Some("w"),
|
||||
doc: "Write changes to disk.",
|
||||
fun: write,
|
||||
},
|
||||
Command {
|
||||
name: "new",
|
||||
alias: Some("n"),
|
||||
doc: "Create a new scratch buffer.",
|
||||
fun: new_file,
|
||||
},
|
||||
];
|
||||
|
||||
pub static COMMANDS: Lazy<HashMap<&'static str, Command>> = Lazy::new(|| {
|
||||
let mut map = HashMap::new();
|
||||
|
||||
for cmd in COMMAND_LIST {
|
||||
map.insert(cmd.name, cmd.clone());
|
||||
if let Some(alias) = cmd.alias {
|
||||
map.insert(alias, cmd.clone());
|
||||
}
|
||||
}
|
||||
|
||||
map
|
||||
});
|
||||
}
|
||||
|
||||
pub fn command_mode(cx: &mut Context) {
|
||||
let prompt = Prompt::new(
|
||||
|
@ -823,10 +931,10 @@ pub fn command_mode(cx: &mut Context) {
|
|||
if parts.len() <= 1 {
|
||||
use std::{borrow::Cow, ops::Range};
|
||||
let end = 0..;
|
||||
COMMAND_LIST
|
||||
cmd::COMMAND_LIST
|
||||
.iter()
|
||||
.filter(|command| command.contains(input))
|
||||
.map(|command| (end.clone(), Cow::Borrowed(*command)))
|
||||
.filter(|command| command.name.contains(input))
|
||||
.map(|command| (end.clone(), Cow::Borrowed(command.name)))
|
||||
.collect()
|
||||
} else {
|
||||
let part = parts.last().unwrap();
|
||||
|
@ -854,52 +962,11 @@ pub fn command_mode(cx: &mut Context) {
|
|||
|
||||
let parts = input.split_ascii_whitespace().collect::<Vec<&str>>();
|
||||
|
||||
match *parts.as_slice() {
|
||||
["q"] | ["quit"] => {
|
||||
// last view and we have unsaved changes
|
||||
if editor.tree.views().count() == 1 {
|
||||
let modified: Vec<_> = editor
|
||||
.documents()
|
||||
.filter(|doc| doc.is_modified())
|
||||
.map(|doc| {
|
||||
doc.relative_path()
|
||||
.and_then(|path| path.to_str())
|
||||
.unwrap_or("[scratch]")
|
||||
})
|
||||
.collect();
|
||||
|
||||
if !modified.is_empty() {
|
||||
let err = format!(
|
||||
"{} unsaved buffer(s) remaining: {:?}",
|
||||
modified.len(),
|
||||
modified
|
||||
);
|
||||
editor.set_error(err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
editor.close(editor.view().id, /* close_buffer */ false);
|
||||
}
|
||||
["q!"] | ["quit!"] => {
|
||||
editor.close(editor.view().id, /* close_buffer */ false);
|
||||
}
|
||||
["o", path] | ["open", path] => {
|
||||
editor.open(path.into(), Action::Replace);
|
||||
}
|
||||
["w"] | ["write"] => {
|
||||
let id = editor.view().doc;
|
||||
let doc = &mut editor.documents[id];
|
||||
if doc.path().is_none() {
|
||||
editor.set_error("cannot write a buffer without a filename".to_string());
|
||||
return;
|
||||
}
|
||||
tokio::spawn(doc.save());
|
||||
}
|
||||
["new"] => {
|
||||
editor.new_file(Action::Replace);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
if let Some(cmd) = cmd::COMMANDS.get(parts[0]) {
|
||||
(cmd.fun)(editor, &parts[1..], event);
|
||||
} else {
|
||||
editor.set_error(format!("no such command: '{}'", parts[0]));
|
||||
};
|
||||
},
|
||||
);
|
||||
cx.push_layer(Box::new(prompt));
|
||||
|
|
Loading…
Reference in a new issue