mirror of
https://github.com/nushell/nushell.git
synced 2024-11-26 18:33:50 +01:00
Add a custom path completer to nushell. (#2463)
Previously, we used rustyline's filename completer. This allowed us to make progress on the completion engine without building all the parts at once. We now need our own filename completer to make progress. The primary driver to having our own filename completer is that it can better integrate with our path constructs. For example, if we have > ls .../<TAB> we want to show a list of suggestions that includes all files two directories up from the current working directory. The least jarring experience to a user would be to maintain the three dots. The easiest way for us to do this is by building our own completer and path constructs.
This commit is contained in:
parent
965e07d8cc
commit
188d33b306
@ -33,7 +33,7 @@ impl Completer {
|
||||
.collect();
|
||||
|
||||
if partial != "" {
|
||||
let path_completer = crate::completion::path::Completer::new();
|
||||
let path_completer = crate::completion::path::Completer;
|
||||
let path_results = path_completer.complete(ctx, partial);
|
||||
suggestions.extend(path_results.into_iter().filter(|suggestion| {
|
||||
let path = Path::new(&suggestion.replacement);
|
||||
|
@ -1,27 +1,47 @@
|
||||
use rustyline::completion::FilenameCompleter;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::completion::{Context, Suggestion};
|
||||
|
||||
pub struct Completer {
|
||||
inner: FilenameCompleter,
|
||||
}
|
||||
const SEP: char = std::path::MAIN_SEPARATOR;
|
||||
|
||||
pub struct Completer;
|
||||
|
||||
impl Completer {
|
||||
pub fn new() -> Completer {
|
||||
Completer {
|
||||
inner: FilenameCompleter::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn complete(&self, _ctx: &Context<'_>, partial: &str) -> Vec<Suggestion> {
|
||||
let expanded = nu_parser::expand_ndots(partial);
|
||||
let expanded = expanded.as_ref();
|
||||
|
||||
if let Ok((_pos, pairs)) = self.inner.complete_path(&expanded, expanded.len()) {
|
||||
pairs
|
||||
.into_iter()
|
||||
.map(|v| Suggestion {
|
||||
replacement: v.replacement,
|
||||
display: v.display,
|
||||
let (base_dir_name, partial) = match expanded.rfind(SEP) {
|
||||
Some(pos) => expanded.split_at(pos + SEP.len_utf8()),
|
||||
None => ("", expanded),
|
||||
};
|
||||
|
||||
let base_dir = if base_dir_name == "" {
|
||||
Path::new(".")
|
||||
} else {
|
||||
Path::new(base_dir_name)
|
||||
};
|
||||
|
||||
if let Ok(result) = base_dir.read_dir() {
|
||||
result
|
||||
.filter_map(|entry| {
|
||||
entry.ok().and_then(|entry| {
|
||||
let mut file_name = entry.file_name().to_string_lossy().into_owned();
|
||||
if file_name.starts_with(partial) {
|
||||
let mut path = format!("{}{}", base_dir_name, file_name);
|
||||
if entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false) {
|
||||
path.push(std::path::MAIN_SEPARATOR);
|
||||
file_name.push(std::path::MAIN_SEPARATOR);
|
||||
}
|
||||
|
||||
Some(Suggestion {
|
||||
replacement: path,
|
||||
display: file_name,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
|
@ -41,12 +41,12 @@ impl NuCompleter {
|
||||
}
|
||||
|
||||
LocationType::Flag(cmd) => {
|
||||
let flag_completer = crate::completion::flag::Completer {};
|
||||
let flag_completer = crate::completion::flag::Completer;
|
||||
flag_completer.complete(context, cmd, partial)
|
||||
}
|
||||
|
||||
LocationType::Argument(cmd, _arg_name) => {
|
||||
let path_completer = crate::completion::path::Completer::new();
|
||||
let path_completer = crate::completion::path::Completer;
|
||||
let completed_paths = path_completer.complete(context, partial);
|
||||
match cmd.as_deref().unwrap_or("") {
|
||||
"cd" => select_directory_suggestions(completed_paths),
|
||||
|
Loading…
Reference in New Issue
Block a user