Skip to content

Commit c9adff5

Browse files
committed
feat: Add custom completer for cargo <TAB> to complete aliases defined in config.toml
1 parent 662213b commit c9adff5

File tree

3 files changed

+51
-22
lines changed

3 files changed

+51
-22
lines changed

src/bin/cargo/cli.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -691,11 +691,13 @@ See '<cyan,bold>cargo help</> <cyan><<command>></>' for more information on a sp
691691
}))
692692
}).collect()
693693
})))
694-
.add(clap_complete::engine::SubcommandCandidates::new(|| {
695-
get_toolchains_from_rustup()
694+
.add(clap_complete::engine::SubcommandCandidates::new(move || {
695+
let mut candidates = get_toolchains_from_rustup()
696696
.into_iter()
697697
.map(|t| clap_complete::CompletionCandidate::new(t))
698-
.collect()
698+
.collect::<Vec<_>>();
699+
candidates.extend(crate::util::command_prelude::get_alias_candidates());
700+
candidates
699701
}))
700702
.subcommands(commands::builtin())
701703
}

src/bin/cargo/main.rs

+1-18
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use cargo::util::network::http::http_handle;
66
use cargo::util::network::http::needs_custom_http_transport;
77
use cargo::util::{self, closest_msg, command_prelude, CargoResult};
88
use cargo_util::{ProcessBuilder, ProcessError};
9-
use cargo_util_schemas::manifest::StringOrVec;
109
use std::collections::BTreeMap;
1110
use std::env;
1211
use std::ffi::OsStr;
@@ -205,7 +204,7 @@ fn list_commands(gctx: &GlobalContext) -> BTreeMap<String, CommandInfo> {
205204
}
206205

207206
// Add the user-defined aliases
208-
let alias_commands = user_defined_aliases(gctx);
207+
let alias_commands = command_prelude::user_defined_aliases(gctx);
209208
commands.extend(alias_commands);
210209

211210
// `help` is special, so it needs to be inserted separately.
@@ -249,22 +248,6 @@ fn third_party_subcommands(gctx: &GlobalContext) -> BTreeMap<String, CommandInfo
249248
}
250249
commands
251250
}
252-
253-
fn user_defined_aliases(gctx: &GlobalContext) -> BTreeMap<String, CommandInfo> {
254-
let mut commands = BTreeMap::new();
255-
if let Ok(aliases) = gctx.get::<BTreeMap<String, StringOrVec>>("alias") {
256-
for (name, target) in aliases.iter() {
257-
commands.insert(
258-
name.to_string(),
259-
CommandInfo::Alias {
260-
target: target.clone(),
261-
},
262-
);
263-
}
264-
}
265-
commands
266-
}
267-
268251
fn find_external_subcommand(gctx: &GlobalContext, cmd: &str) -> Option<PathBuf> {
269252
let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
270253
search_directories(gctx)

src/cargo/util/command_prelude.rs

+45-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use cargo_util_schemas::manifest::StringOrVec;
2424
use clap::builder::UnknownArgumentValueParser;
2525
use home::cargo_home_with_cwd;
2626
use semver::Version;
27-
use std::collections::HashMap;
27+
use std::collections::{BTreeMap, HashMap};
2828
use std::ffi::{OsStr, OsString};
2929
use std::path::Path;
3030
use std::path::PathBuf;
@@ -1370,6 +1370,50 @@ fn new_gctx_for_completions() -> CargoResult<GlobalContext> {
13701370
Ok(gctx)
13711371
}
13721372

1373+
pub fn get_alias_candidates() -> Vec<clap_complete::CompletionCandidate> {
1374+
if let Ok(gctx) = new_gctx_for_completions() {
1375+
let alias_map = user_defined_aliases(&gctx);
1376+
return alias_map
1377+
.iter()
1378+
.map(|(alias, cmd_info)| {
1379+
let help_text = match cmd_info {
1380+
CommandInfo::Alias { target } => {
1381+
let cmd_str = target
1382+
.iter()
1383+
.map(String::as_str)
1384+
.collect::<Vec<_>>()
1385+
.join(" ");
1386+
format!("alias for {}", cmd_str)
1387+
}
1388+
CommandInfo::BuiltIn { .. } => {
1389+
unreachable!("BuiltIn command shouldn't appear in alias map")
1390+
}
1391+
CommandInfo::External { .. } => {
1392+
unreachable!("External command shouldn't appear in alias map")
1393+
}
1394+
};
1395+
clap_complete::CompletionCandidate::new(alias.clone()).help(Some(help_text.into()))
1396+
})
1397+
.collect();
1398+
}
1399+
Vec::new()
1400+
}
1401+
1402+
pub fn user_defined_aliases(gctx: &GlobalContext) -> BTreeMap<String, CommandInfo> {
1403+
let mut commands = BTreeMap::new();
1404+
if let Ok(aliases) = gctx.get::<BTreeMap<String, StringOrVec>>("alias") {
1405+
for (name, target) in aliases.iter() {
1406+
commands.insert(
1407+
name.to_string(),
1408+
CommandInfo::Alias {
1409+
target: target.clone(),
1410+
},
1411+
);
1412+
}
1413+
}
1414+
commands
1415+
}
1416+
13731417
#[track_caller]
13741418
pub fn ignore_unknown<T: Default>(r: Result<T, clap::parser::MatchesError>) -> T {
13751419
match r {

0 commit comments

Comments
 (0)