on master help sign in
Command mode: Per command completers.
ff84c8eBlaž Hrastnik
helix-term/src/commands.rs+29−14
@@ -814,6 +814,7 @@ mod cmd {
814 use std::collections::HashMap;
814 use std::collections::HashMap;
815
815
816 use helix_view::editor::Action;
816 use helix_view::editor::Action;
817+ use ui::completers::{self, Completer};
817
818
818 #[derive(Clone)]
819 #[derive(Clone)]
819 pub struct Command {
820 pub struct Command {
@@ -822,6 +823,7 @@ mod cmd {
822 pub doc: &'static str,
823 pub doc: &'static str,
823 // params, flags, helper, completer
824 // params, flags, helper, completer
824 pub fun: fn(&mut Editor, &[&str], PromptEvent),
825 pub fun: fn(&mut Editor, &[&str], PromptEvent),
826+ pub completer: Option<Completer>,
825 }
827 }
826
828
827 fn quit(editor: &mut Editor, args: &[&str], event: PromptEvent) {
829 fn quit(editor: &mut Editor, args: &[&str], event: PromptEvent) {
@@ -878,30 +880,35 @@ mod cmd {
878 alias: Some("q"),
880 alias: Some("q"),
879 doc: "Close the current view.",
881 doc: "Close the current view.",
880 fun: quit,
882 fun: quit,
883+ completer: None,
881 },
884 },
882 Command {
885 Command {
883 name: "quit!",
886 name: "quit!",
884 alias: Some("q!"),
887 alias: Some("q!"),
885 doc: "Close the current view.",
888 doc: "Close the current view.",
886 fun: force_quit,
889 fun: force_quit,
890+ completer: None,
887 },
891 },
888 Command {
892 Command {
889 name: "open",
893 name: "open",
890 alias: Some("o"),
894 alias: Some("o"),
891 doc: "Open a file from disk into the current view.",
895 doc: "Open a file from disk into the current view.",
892 fun: open,
896 fun: open,
897+ completer: Some(completers::filename),
893 },
898 },
894 Command {
899 Command {
895 name: "write",
900 name: "write",
896 alias: Some("w"),
901 alias: Some("w"),
897 doc: "Write changes to disk.",
902 doc: "Write changes to disk.",
898 fun: write,
903 fun: write,
904+ completer: Some(completers::filename),
899 },
905 },
900 Command {
906 Command {
901 name: "new",
907 name: "new",
902 alias: Some("n"),
908 alias: Some("n"),
903 doc: "Create a new scratch buffer.",
909 doc: "Create a new scratch buffer.",
904 fun: new_file,
910 fun: new_file,
911+ completer: Some(completers::filename),
905 },
912 },
906 ];
913 ];
907
914
@@ -920,14 +927,17 @@ mod cmd {
920}
927}
921
928
922pub fn command_mode(cx: &mut Context) {
929pub fn command_mode(cx: &mut Context) {
930+ // TODO: completion items should have a info section that would get displayed in
931+ // a popup above the prompt when items are tabbed over
932+
923 let prompt = Prompt::new(
933 let prompt = Prompt::new(
924 ":".to_owned(),
934 ":".to_owned(),
925 |input: &str| {
935 |input: &str| {
926 // we use .this over split_ascii_whitespace() because we care about empty segments
936 // we use .this over split_ascii_whitespace() because we care about empty segments
927 let parts = input.split(' ').collect::<Vec<&str>>();
937 let parts = input.split(' ').collect::<Vec<&str>>();
928
938
929− // simple heuristic: if there's no space, complete command.
939+ // simple heuristic: if there's no just one part, complete command name.
930− // if there's a space, file completion kicks in. We should specialize by command later.
940+ // if there's a space, per command completion kicks in.
931 if parts.len() <= 1 {
941 if parts.len() <= 1 {
932 use std::{borrow::Cow, ops::Range};
942 use std::{borrow::Cow, ops::Range};
933 let end = 0..;
943 let end = 0..;
@@ -938,19 +948,24 @@ pub fn command_mode(cx: &mut Context) {
938 .collect()
948 .collect()
939 } else {
949 } else {
940 let part = parts.last().unwrap();
950 let part = parts.last().unwrap();
941− ui::completers::filename(part)
942− .into_iter()
943− .map(|(range, file)| {
944− // offset ranges to input
945− let offset = input.len() - part.len();
946− let range = (range.start + offset)..;
947− (range, file)
948− })
949− .collect()
950
951
951− // TODO
952+ if let Some(cmd::Command {
952− // additionally, completion items could have a info section that would get
953+ completer: Some(completer),
953− // displayed in a popup above the prompt when items are tabbed over
954+ ..
955+ }) = cmd::COMMANDS.get(parts[0])
956+ {
957+ completer(part)
958+ .into_iter()
959+ .map(|(range, file)| {
960+ // offset ranges to input
961+ let offset = input.len() - part.len();
962+ let range = (range.start + offset)..;
963+ (range, file)
964+ })
965+ .collect()
966+ } else {
967+ Vec::new()
968+ }
954 }
969 }
955 }, // completion
970 }, // completion
956 move |editor: &mut Editor, input: &str, event: PromptEvent| {
971 move |editor: &mut Editor, input: &str, event: PromptEvent| {
helix-term/src/ui/mod.rs+3
@@ -114,6 +114,9 @@ pub fn file_picker(root: PathBuf) -> Picker<PathBuf> {
114pub mod completers {
114pub mod completers {
115 use crate::ui::prompt::Completion;
115 use crate::ui::prompt::Completion;
116 use std::borrow::Cow;
116 use std::borrow::Cow;
117+
118+ pub type Completer = fn(&str) -> Vec<Completion>;
119+
117 // TODO: we could return an iter/lazy thing so it can fetch as many as it needs.
120 // TODO: we could return an iter/lazy thing so it can fetch as many as it needs.
118 pub fn filename(input: &str) -> Vec<Completion> {
121 pub fn filename(input: &str) -> Vec<Completion> {
119 // Rust's filename handling is really annoying.
122 // Rust's filename handling is really annoying.