mirror of
https://github.com/clap-rs/clap
synced 2024-12-14 06:42:33 +00:00
fix(complete): Preserve absolute paths
This commit is contained in:
parent
ebb1302e90
commit
78157e6ce6
3 changed files with 24 additions and 22 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -482,7 +482,6 @@ dependencies = [
|
||||||
"completest",
|
"completest",
|
||||||
"completest-pty",
|
"completest-pty",
|
||||||
"is_executable",
|
"is_executable",
|
||||||
"pathdiff",
|
|
||||||
"shlex",
|
"shlex",
|
||||||
"snapbox",
|
"snapbox",
|
||||||
"trycmd",
|
"trycmd",
|
||||||
|
|
|
@ -37,7 +37,6 @@ bench = false
|
||||||
clap = { path = "../", version = "4.5.15", default-features = false, features = ["std"] }
|
clap = { path = "../", version = "4.5.15", default-features = false, features = ["std"] }
|
||||||
clap_lex = { path = "../clap_lex", version = "0.7.0", optional = true }
|
clap_lex = { path = "../clap_lex", version = "0.7.0", optional = true }
|
||||||
is_executable = { version = "1.0.1", optional = true }
|
is_executable = { version = "1.0.1", optional = true }
|
||||||
pathdiff = { version = "0.2.1", optional = true }
|
|
||||||
shlex = { version = "1.1.0", optional = true }
|
shlex = { version = "1.1.0", optional = true }
|
||||||
unicode-xid = { version = "0.2.2", optional = true }
|
unicode-xid = { version = "0.2.2", optional = true }
|
||||||
|
|
||||||
|
@ -57,8 +56,8 @@ required-features = ["unstable-dynamic", "unstable-command"]
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
unstable-doc = ["unstable-dynamic", "unstable-command"] # for docs.rs
|
unstable-doc = ["unstable-dynamic", "unstable-command"] # for docs.rs
|
||||||
unstable-dynamic = ["dep:clap_lex", "dep:shlex", "dep:is_executable", "dep:pathdiff", "clap/unstable-ext"]
|
unstable-dynamic = ["dep:clap_lex", "dep:shlex", "dep:is_executable", "clap/unstable-ext"]
|
||||||
unstable-command = ["unstable-dynamic", "dep:unicode-xid", "clap/derive", "dep:is_executable", "dep:pathdiff", "clap/unstable-ext"]
|
unstable-command = ["unstable-dynamic", "dep:unicode-xid", "clap/derive", "dep:is_executable", "clap/unstable-ext"]
|
||||||
debug = ["clap/debug"]
|
debug = ["clap/debug"]
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
|
|
|
@ -348,38 +348,42 @@ fn complete_path(
|
||||||
) -> Vec<CompletionCandidate> {
|
) -> Vec<CompletionCandidate> {
|
||||||
let mut completions = Vec::new();
|
let mut completions = Vec::new();
|
||||||
|
|
||||||
let current_dir = match current_dir {
|
let value_path = std::path::Path::new(value_os);
|
||||||
Some(current_dir) => current_dir,
|
let (prefix, current) = split_file_name(value_path);
|
||||||
None => {
|
let current = current.to_string_lossy();
|
||||||
// Can't complete without a `current_dir`
|
let search_root = if prefix.is_absolute() {
|
||||||
return Vec::new();
|
prefix.to_owned()
|
||||||
}
|
} else {
|
||||||
|
let current_dir = match current_dir {
|
||||||
|
Some(current_dir) => current_dir,
|
||||||
|
None => {
|
||||||
|
// Can't complete without a `current_dir`
|
||||||
|
return Vec::new();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
current_dir.join(prefix)
|
||||||
};
|
};
|
||||||
let absolute = current_dir.join(value_os);
|
debug!("complete_path: search_root={search_root:?}, prefix={prefix:?}");
|
||||||
let (root, prefix) = split_file_name(&absolute);
|
|
||||||
let prefix = prefix.to_string_lossy();
|
|
||||||
debug!("complete_path: root={root:?}, prefix={prefix:?}");
|
|
||||||
|
|
||||||
for entry in std::fs::read_dir(&root)
|
for entry in std::fs::read_dir(&search_root)
|
||||||
.ok()
|
.ok()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.filter_map(Result::ok)
|
.filter_map(Result::ok)
|
||||||
{
|
{
|
||||||
let raw_file_name = entry.file_name();
|
let raw_file_name = entry.file_name();
|
||||||
if !raw_file_name.starts_with(&prefix) {
|
if !raw_file_name.starts_with(¤t) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if entry.metadata().map(|m| m.is_dir()).unwrap_or(false) {
|
if entry.metadata().map(|m| m.is_dir()).unwrap_or(false) {
|
||||||
let path = entry.path();
|
let mut suggestion = prefix.join(raw_file_name);
|
||||||
let mut suggestion = pathdiff::diff_paths(&path, current_dir).unwrap_or(path);
|
|
||||||
suggestion.push(""); // Ensure trailing `/`
|
suggestion.push(""); // Ensure trailing `/`
|
||||||
completions.push(CompletionCandidate::new(suggestion.as_os_str().to_owned()));
|
completions.push(CompletionCandidate::new(suggestion.as_os_str().to_owned()));
|
||||||
} else {
|
} else {
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
if is_wanted(&path) {
|
if is_wanted(&path) {
|
||||||
let suggestion = pathdiff::diff_paths(&path, current_dir).unwrap_or(path);
|
let suggestion = prefix.join(raw_file_name);
|
||||||
completions.push(CompletionCandidate::new(suggestion.as_os_str().to_owned()));
|
completions.push(CompletionCandidate::new(suggestion.as_os_str().to_owned()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -401,12 +405,12 @@ fn split_file_name(path: &std::path::Path) -> (&std::path::Path, &OsStr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path_has_name(path: &std::path::Path) -> bool {
|
fn path_has_name(path: &std::path::Path) -> bool {
|
||||||
let path = path.as_os_str().as_encoded_bytes();
|
let path_bytes = path.as_os_str().as_encoded_bytes();
|
||||||
let Some(trailing) = path.last() else {
|
let Some(trailing) = path_bytes.last() else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let trailing = *trailing as char;
|
let trailing = *trailing as char;
|
||||||
!std::path::is_separator(trailing)
|
!std::path::is_separator(trailing) && path.file_name().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn complete_custom_arg_value(
|
fn complete_custom_arg_value(
|
||||||
|
|
Loading…
Reference in a new issue