Command mode: Per command completers.
This commit is contained in:
parent
87e7a0de3f
commit
ff84c8e394
@ -814,6 +814,7 @@ mod cmd {
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use helix_view::editor::Action;
|
use helix_view::editor::Action;
|
||||||
|
use ui::completers::{self, Completer};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Command {
|
pub struct Command {
|
||||||
@ -822,6 +823,7 @@ pub struct Command {
|
|||||||
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 Editor, &[&str], PromptEvent),
|
||||||
|
pub completer: Option<Completer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn quit(editor: &mut Editor, args: &[&str], event: PromptEvent) {
|
fn quit(editor: &mut Editor, args: &[&str], event: PromptEvent) {
|
||||||
@ -878,30 +880,35 @@ fn new_file(editor: &mut Editor, args: &[&str], event: PromptEvent) {
|
|||||||
alias: Some("q"),
|
alias: Some("q"),
|
||||||
doc: "Close the current view.",
|
doc: "Close the current view.",
|
||||||
fun: quit,
|
fun: quit,
|
||||||
|
completer: None,
|
||||||
},
|
},
|
||||||
Command {
|
Command {
|
||||||
name: "quit!",
|
name: "quit!",
|
||||||
alias: Some("q!"),
|
alias: Some("q!"),
|
||||||
doc: "Close the current view.",
|
doc: "Close the current view.",
|
||||||
fun: force_quit,
|
fun: force_quit,
|
||||||
|
completer: None,
|
||||||
},
|
},
|
||||||
Command {
|
Command {
|
||||||
name: "open",
|
name: "open",
|
||||||
alias: Some("o"),
|
alias: Some("o"),
|
||||||
doc: "Open a file from disk into the current view.",
|
doc: "Open a file from disk into the current view.",
|
||||||
fun: open,
|
fun: open,
|
||||||
|
completer: Some(completers::filename),
|
||||||
},
|
},
|
||||||
Command {
|
Command {
|
||||||
name: "write",
|
name: "write",
|
||||||
alias: Some("w"),
|
alias: Some("w"),
|
||||||
doc: "Write changes to disk.",
|
doc: "Write changes to disk.",
|
||||||
fun: write,
|
fun: write,
|
||||||
|
completer: Some(completers::filename),
|
||||||
},
|
},
|
||||||
Command {
|
Command {
|
||||||
name: "new",
|
name: "new",
|
||||||
alias: Some("n"),
|
alias: Some("n"),
|
||||||
doc: "Create a new scratch buffer.",
|
doc: "Create a new scratch buffer.",
|
||||||
fun: new_file,
|
fun: new_file,
|
||||||
|
completer: Some(completers::filename),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -920,14 +927,17 @@ fn new_file(editor: &mut Editor, args: &[&str], event: PromptEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn command_mode(cx: &mut Context) {
|
pub fn command_mode(cx: &mut Context) {
|
||||||
|
// TODO: completion items should have a info section that would get displayed in
|
||||||
|
// a popup above the prompt when items are tabbed over
|
||||||
|
|
||||||
let prompt = Prompt::new(
|
let prompt = Prompt::new(
|
||||||
":".to_owned(),
|
":".to_owned(),
|
||||||
|input: &str| {
|
|input: &str| {
|
||||||
// we use .this over split_ascii_whitespace() because we care about empty segments
|
// we use .this over split_ascii_whitespace() because we care about empty segments
|
||||||
let parts = input.split(' ').collect::<Vec<&str>>();
|
let parts = input.split(' ').collect::<Vec<&str>>();
|
||||||
|
|
||||||
// simple heuristic: if there's no space, complete command.
|
// simple heuristic: if there's no just one part, complete command name.
|
||||||
// if there's a space, file completion kicks in. We should specialize by command later.
|
// if there's a space, per command completion kicks in.
|
||||||
if parts.len() <= 1 {
|
if parts.len() <= 1 {
|
||||||
use std::{borrow::Cow, ops::Range};
|
use std::{borrow::Cow, ops::Range};
|
||||||
let end = 0..;
|
let end = 0..;
|
||||||
@ -938,19 +948,24 @@ pub fn command_mode(cx: &mut Context) {
|
|||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
let part = parts.last().unwrap();
|
let part = parts.last().unwrap();
|
||||||
ui::completers::filename(part)
|
|
||||||
.into_iter()
|
|
||||||
.map(|(range, file)| {
|
|
||||||
// offset ranges to input
|
|
||||||
let offset = input.len() - part.len();
|
|
||||||
let range = (range.start + offset)..;
|
|
||||||
(range, file)
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
|
|
||||||
// TODO
|
if let Some(cmd::Command {
|
||||||
// additionally, completion items could have a info section that would get
|
completer: Some(completer),
|
||||||
// displayed in a popup above the prompt when items are tabbed over
|
..
|
||||||
|
}) = cmd::COMMANDS.get(parts[0])
|
||||||
|
{
|
||||||
|
completer(part)
|
||||||
|
.into_iter()
|
||||||
|
.map(|(range, file)| {
|
||||||
|
// offset ranges to input
|
||||||
|
let offset = input.len() - part.len();
|
||||||
|
let range = (range.start + offset)..;
|
||||||
|
(range, file)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, // completion
|
}, // completion
|
||||||
move |editor: &mut Editor, input: &str, event: PromptEvent| {
|
move |editor: &mut Editor, input: &str, event: PromptEvent| {
|
||||||
|
@ -114,6 +114,9 @@ pub fn file_picker(root: PathBuf) -> Picker<PathBuf> {
|
|||||||
pub mod completers {
|
pub mod completers {
|
||||||
use crate::ui::prompt::Completion;
|
use crate::ui::prompt::Completion;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
pub type Completer = fn(&str) -> Vec<Completion>;
|
||||||
|
|
||||||
// TODO: we could return an iter/lazy thing so it can fetch as many as it needs.
|
// TODO: we could return an iter/lazy thing so it can fetch as many as it needs.
|
||||||
pub fn filename(input: &str) -> Vec<Completion> {
|
pub fn filename(input: &str) -> Vec<Completion> {
|
||||||
// Rust's filename handling is really annoying.
|
// Rust's filename handling is really annoying.
|
||||||
|
Loading…
Reference in New Issue
Block a user