@@ -809,7 +809,115 @@ pub fn append_mode(cx: &mut Context) {
809 doc.set_selection(view.id, selection);
809 doc.set_selection(view.id, selection);
814+ use std::collections::HashMap;
816+ use helix_view::editor::Action;
819+ pub struct Command {
820+ pub name: &'static str,
821+ pub alias: Option<&'static str>,
822+ pub doc: &'static str,
823+ // params, flags, helper, completer
824+ pub fun: fn(&mut Editor, &[&str], PromptEvent),
827+ fn quit(editor: &mut Editor, args: &[&str], event: PromptEvent) {
828+ // last view and we have unsaved changes
829+ if editor.tree.views().count() == 1 {
830+ let modified: Vec<_> = editor
832+ .filter(|doc| doc.is_modified())
835+ .and_then(|path| path.to_str())
836+ .unwrap_or("[scratch]")
840+ if !modified.is_empty() {
842+ "{} unsaved buffer(s) remaining: {:?}",
846+ editor.set_error(err);
850+ editor.close(editor.view().id, /* close_buffer */ false);
853+ fn force_quit(editor: &mut Editor, args: &[&str], event: PromptEvent) {
854+ editor.close(editor.view().id, /* close_buffer */ false);
857+ fn open(editor: &mut Editor, args: &[&str], event: PromptEvent) {
859+ editor.open(path.into(), Action::Replace);
862+ fn write(editor: &mut Editor, args: &[&str], event: PromptEvent) {
863+ let id = editor.view().doc;
864+ let doc = &mut editor.documents[id];
865+ if doc.path().is_none() {
866+ editor.set_error("cannot write a buffer without a filename".to_string());
869+ tokio::spawn(doc.save());
871+ fn new_file(editor: &mut Editor, args: &[&str], event: PromptEvent) {
872+ editor.new_file(Action::Replace);
812−const COMMAND_LIST: &[&str] = &["write", "open", "quit", "quit!"];
875+ pub const COMMAND_LIST: &[Command] = &[
879+ doc: "Close the current view.",
885+ doc: "Close the current view.",
891+ doc: "Open a file from disk into the current view.",
897+ doc: "Write changes to disk.",
903+ doc: "Create a new scratch buffer.",
908+ pub static COMMANDS: Lazy<HashMap<&'static str, Command>> = Lazy::new(|| {
909+ let mut map = HashMap::new();
911+ for cmd in COMMAND_LIST {
912+ map.insert(cmd.name, cmd.clone());
913+ if let Some(alias) = cmd.alias {
914+ map.insert(alias, cmd.clone());
814pub fn command_mode(cx: &mut Context) {
922pub fn command_mode(cx: &mut Context) {
815 let prompt = Prompt::new(
923 let prompt = Prompt::new(
@@ -823,10 +931,10 @@ pub fn command_mode(cx: &mut Context) {
823 if parts.len() <= 1 {
931 if parts.len() <= 1 {
824 use std::{borrow::Cow, ops::Range};
932 use std::{borrow::Cow, ops::Range};
825 let end = 0..;
933 let end = 0..;
826− COMMAND_LIST
934+ cmd::COMMAND_LIST
828− .filter(|command| command.contains(input))
936+ .filter(|command| command.name.contains(input))
829− .map(|command| (end.clone(), Cow::Borrowed(*command)))
937+ .map(|command| (end.clone(), Cow::Borrowed(command.name)))
830 .collect()
938 .collect()
832 let part = parts.last().unwrap();
940 let part = parts.last().unwrap();
@@ -854,52 +962,11 @@ pub fn command_mode(cx: &mut Context) {
855 let parts = input.split_ascii_whitespace().collect::<Vec<&str>>();
963 let parts = input.split_ascii_whitespace().collect::<Vec<&str>>();
857− match *parts.as_slice() {
965+ if let Some(cmd) = cmd::COMMANDS.get(parts[0]) {
858− ["q"] | ["quit"] => {
966+ (cmd.fun)(editor, &parts[1..], event);
859− // last view and we have unsaved changes
967+ } else {
860− if editor.tree.views().count() == 1 {
968+ editor.set_error(format!("no such command: '{}'", parts[0]));
861− let modified: Vec<_> = editor
863− .filter(|doc| doc.is_modified())
866− .and_then(|path| path.to_str())
867− .unwrap_or("[scratch]")
871− if !modified.is_empty() {
873− "{} unsaved buffer(s) remaining: {:?}",
877− editor.set_error(err);
881− editor.close(editor.view().id, /* close_buffer */ false);
883− ["q!"] | ["quit!"] => {
884− editor.close(editor.view().id, /* close_buffer */ false);
886− ["o", path] | ["open", path] => {
887− editor.open(path.into(), Action::Replace);
889− ["w"] | ["write"] => {
890− let id = editor.view().doc;
891− let doc = &mut editor.documents[id];
892− if doc.path().is_none() {
893− editor.set_error("cannot write a buffer without a filename".to_string());
896− tokio::spawn(doc.save());
899− editor.new_file(Action::Replace);
905 cx.push_layer(Box::new(prompt));
972 cx.push_layer(Box::new(prompt));