Skip to content

Commit cce8d49

Browse files
committed
feat: Added a map api for PathCompleter and added its test
1 parent 7163b81 commit cce8d49

File tree

2 files changed

+76
-1
lines changed

2 files changed

+76
-1
lines changed

clap_complete/src/engine/custom.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@ pub struct PathCompleter {
216216
#[allow(clippy::type_complexity)]
217217
filter: Option<Box<dyn Fn(&std::path::Path) -> bool + Send + Sync>>,
218218
stdio: bool,
219+
#[allow(clippy::type_complexity)]
220+
mapper: Option<Box<dyn Fn(CompletionCandidate) -> CompletionCandidate + Send + Sync>>,
219221
}
220222

221223
impl PathCompleter {
@@ -225,6 +227,7 @@ impl PathCompleter {
225227
filter: None,
226228
current_dir: None,
227229
stdio: false,
230+
mapper: None,
228231
}
229232
}
230233

@@ -253,6 +256,15 @@ impl PathCompleter {
253256
self
254257
}
255258

259+
/// Transform completion candidates after filtering
260+
pub fn map(
261+
mut self,
262+
mapper: impl Fn(CompletionCandidate) -> CompletionCandidate + Send + Sync + 'static,
263+
) -> Self {
264+
self.mapper = Some(Box::new(mapper));
265+
self
266+
}
267+
256268
/// Override [`std::env::current_dir`]
257269
pub fn current_dir(mut self, path: impl Into<std::path::PathBuf>) -> Self {
258270
self.current_dir = Some(path.into());
@@ -275,6 +287,12 @@ impl ValueCompleter for PathCompleter {
275287
current_dir_actual.as_deref()
276288
});
277289
let mut candidates = complete_path(current, current_dir, filter);
290+
if let Some(mapper) = &self.mapper {
291+
candidates = candidates
292+
.into_iter()
293+
.map(|candidate| mapper(candidate))
294+
.collect();
295+
}
278296
if self.stdio && current.is_empty() {
279297
candidates.push(CompletionCandidate::new("-").help(Some("stdio".into())));
280298
}

clap_complete/tests/testsuite/engine.rs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1216,14 +1216,71 @@ fn suggest_value_path_with_filter_and_mapper() {
12161216
.and_then(|n| n.to_str())
12171217
.map_or(false, |name| name.starts_with('c'))
12181218
})
1219+
.map(|candidate| {
1220+
if candidate.get_value().to_string_lossy().contains("c_dir") {
1221+
candidate
1222+
.help(Some("Addable cargo package".into()))
1223+
.display_order(Some(0))
1224+
} else {
1225+
candidate.display_order(Some(1))
1226+
}
1227+
}),
12191228
)),
12201229
)
12211230
.args_conflicts_with_subcommands(true);
12221231

12231232
assert_data_eq!(
12241233
complete!(cmd, "--input [TAB]", current_dir = Some(testdir_path)),
12251234
snapbox::str![[r#"
1226-
c_dir/
1235+
c_dir/ Addable cargo package
1236+
d_dir/
1237+
"#]],
1238+
);
1239+
}
1240+
1241+
#[test]
1242+
fn suggest_value_file_path_with_mapper() {
1243+
let testdir = snapbox::dir::DirRoot::mutable_temp().unwrap();
1244+
let testdir_path = testdir.path().unwrap();
1245+
fs::write(testdir_path.join("a_file.txt"), "").unwrap();
1246+
fs::write(testdir_path.join("b_file.md"), "").unwrap();
1247+
fs::write(testdir_path.join("c_file.rs"), "").unwrap();
1248+
fs::create_dir_all(testdir_path.join("d_dir")).unwrap();
1249+
1250+
let mut cmd = Command::new("dynamic")
1251+
.arg(
1252+
clap::Arg::new("input")
1253+
.long("input")
1254+
.short('i')
1255+
.add(ArgValueCompleter::new(
1256+
PathCompleter::file()
1257+
.current_dir(testdir_path.to_owned())
1258+
.map(|candidate| {
1259+
let path = Path::new(candidate.get_value());
1260+
if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
1261+
match ext {
1262+
"rs" => candidate
1263+
.help(Some("Rust source file".into()))
1264+
.display_order(Some(0)),
1265+
"txt" => candidate
1266+
.help(Some("Text file".into()))
1267+
.display_order(Some(1)),
1268+
_ => candidate.display_order(Some(2))
1269+
}
1270+
} else {
1271+
candidate.display_order(Some(3))
1272+
}
1273+
}),
1274+
)),
1275+
)
1276+
.args_conflicts_with_subcommands(true);
1277+
1278+
assert_data_eq!(
1279+
complete!(cmd, "--input [TAB]", current_dir = Some(testdir_path)),
1280+
snapbox::str![[r#"
1281+
c_file.rs Rust source file
1282+
a_file.txt Text file
1283+
b_file.md
12271284
d_dir/
12281285
"#]],
12291286
);

0 commit comments

Comments
 (0)