mirror of
https://github.com/danbulant/nushell
synced 2026-05-21 05:18:42 +00: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
3 changed files with 39 additions and 19 deletions
|
|
@ -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 a new issue