mirror of
https://github.com/uutils/coreutils.git
synced 2025-07-07 21:45:01 +00:00
uutils: enable shell completions
This adds a hidden `completion` subcommand to coreutils. When invoked with `coreutils completion <utility> <shell>` a completion file will be printed to stdout. When running `make install` those files will be created for all utilities and copied to the appropriate locations. `make install` will install completions for zsh, fish and bash; however, clap also supports generating completions for powershell and elvish. With this patch all utilities are required to have a publich uu_app function that returns a clap::App in addition to the uumain function.
This commit is contained in:
parent
0531153fa6
commit
a9e79c72c7
5 changed files with 76 additions and 23 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -218,6 +218,7 @@ version = "0.0.6"
|
|||
dependencies = [
|
||||
"atty",
|
||||
"chrono",
|
||||
"clap",
|
||||
"conv",
|
||||
"filetime",
|
||||
"glob 0.3.0",
|
||||
|
|
|
@ -225,6 +225,7 @@ test = [ "uu_test" ]
|
|||
[workspace]
|
||||
|
||||
[dependencies]
|
||||
clap = "2.33.3"
|
||||
lazy_static = { version="1.3" }
|
||||
textwrap = { version="=0.11.0", features=["term_size"] } # !maint: [2020-05-10; rivy] unstable crate using undocumented features; pinned currently, will review
|
||||
uucore = { version=">=0.0.8", package="uucore", path="src/uucore" }
|
||||
|
|
|
@ -314,6 +314,11 @@ else
|
|||
endif
|
||||
$(foreach man, $(filter $(INSTALLEES), $(basename $(notdir $(wildcard $(DOCSDIR)/_build/man/*)))), \
|
||||
cat $(DOCSDIR)/_build/man/$(man).1 | gzip > $(INSTALLDIR_MAN)/$(PROG_PREFIX)$(man).1.gz &&) :
|
||||
$(foreach prog, $(INSTALLEES), \
|
||||
$(BUILDDIR)/coreutils completion $(prog) zsh > $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_$(PROG_PREFIX)$(prog); \
|
||||
$(BUILDDIR)/coreutils completion $(prog) bash > $(DESTDIR)$(PREFIX)/share/bash-completion/completions/$(PROG_PREFIX)$(prog); \
|
||||
$(BUILDDIR)/coreutils completion $(prog) fish > $(DESTDIR)$(PREFIX)/share/fish/vendor_completions.d/$(PROG_PREFIX)$(prog).fish; \
|
||||
)
|
||||
|
||||
uninstall:
|
||||
ifeq (${MULTICALL}, y)
|
||||
|
|
40
build.rs
40
build.rs
|
@ -43,7 +43,7 @@ pub fn main() {
|
|||
let mut tf = File::create(Path::new(&out_dir).join("test_modules.rs")).unwrap();
|
||||
|
||||
mf.write_all(
|
||||
"type UtilityMap<T> = HashMap<&'static str, fn(T) -> i32>;\n\
|
||||
"type UtilityMap<T> = HashMap<&'static str, (fn(T) -> i32, fn() -> App<'static, 'static>)>;\n\
|
||||
\n\
|
||||
fn util_map<T: uucore::Args>() -> UtilityMap<T> {\n\
|
||||
\tlet mut map = UtilityMap::new();\n\
|
||||
|
@ -60,8 +60,8 @@ pub fn main() {
|
|||
mf.write_all(
|
||||
format!(
|
||||
"\
|
||||
\tmap.insert(\"test\", {krate}::uumain);\n\
|
||||
\t\tmap.insert(\"[\", {krate}::uumain);\n\
|
||||
\tmap.insert(\"test\", ({krate}::uumain, {krate}::uu_app));\n\
|
||||
\t\tmap.insert(\"[\", ({krate}::uumain, {krate}::uu_app));\n\
|
||||
",
|
||||
krate = krate
|
||||
)
|
||||
|
@ -80,7 +80,7 @@ pub fn main() {
|
|||
k if k.starts_with(override_prefix) => {
|
||||
mf.write_all(
|
||||
format!(
|
||||
"\tmap.insert(\"{k}\", {krate}::uumain);\n",
|
||||
"\tmap.insert(\"{k}\", ({krate}::uumain, {krate}::uu_app));\n",
|
||||
k = krate[override_prefix.len()..].to_string(),
|
||||
krate = krate
|
||||
)
|
||||
|
@ -100,7 +100,7 @@ pub fn main() {
|
|||
"false" | "true" => {
|
||||
mf.write_all(
|
||||
format!(
|
||||
"\tmap.insert(\"{krate}\", r#{krate}::uumain);\n",
|
||||
"\tmap.insert(\"{krate}\", (r#{krate}::uumain, r#{krate}::uu_app));\n",
|
||||
krate = krate
|
||||
)
|
||||
.as_bytes(),
|
||||
|
@ -120,20 +120,20 @@ pub fn main() {
|
|||
mf.write_all(
|
||||
format!(
|
||||
"\
|
||||
\tmap.insert(\"{krate}\", {krate}::uumain);\n\
|
||||
\t\tmap.insert(\"md5sum\", {krate}::uumain);\n\
|
||||
\t\tmap.insert(\"sha1sum\", {krate}::uumain);\n\
|
||||
\t\tmap.insert(\"sha224sum\", {krate}::uumain);\n\
|
||||
\t\tmap.insert(\"sha256sum\", {krate}::uumain);\n\
|
||||
\t\tmap.insert(\"sha384sum\", {krate}::uumain);\n\
|
||||
\t\tmap.insert(\"sha512sum\", {krate}::uumain);\n\
|
||||
\t\tmap.insert(\"sha3sum\", {krate}::uumain);\n\
|
||||
\t\tmap.insert(\"sha3-224sum\", {krate}::uumain);\n\
|
||||
\t\tmap.insert(\"sha3-256sum\", {krate}::uumain);\n\
|
||||
\t\tmap.insert(\"sha3-384sum\", {krate}::uumain);\n\
|
||||
\t\tmap.insert(\"sha3-512sum\", {krate}::uumain);\n\
|
||||
\t\tmap.insert(\"shake128sum\", {krate}::uumain);\n\
|
||||
\t\tmap.insert(\"shake256sum\", {krate}::uumain);\n\
|
||||
\tmap.insert(\"{krate}\", ({krate}::uumain, {krate}::uu_app_custom));\n\
|
||||
\t\tmap.insert(\"md5sum\", ({krate}::uumain, {krate}::uu_app_common));\n\
|
||||
\t\tmap.insert(\"sha1sum\", ({krate}::uumain, {krate}::uu_app_common));\n\
|
||||
\t\tmap.insert(\"sha224sum\", ({krate}::uumain, {krate}::uu_app_common));\n\
|
||||
\t\tmap.insert(\"sha256sum\", ({krate}::uumain, {krate}::uu_app_common));\n\
|
||||
\t\tmap.insert(\"sha384sum\", ({krate}::uumain, {krate}::uu_app_common));\n\
|
||||
\t\tmap.insert(\"sha512sum\", ({krate}::uumain, {krate}::uu_app_common));\n\
|
||||
\t\tmap.insert(\"sha3sum\", ({krate}::uumain, {krate}::uu_app_common));\n\
|
||||
\t\tmap.insert(\"sha3-224sum\", ({krate}::uumain, {krate}::uu_app_common));\n\
|
||||
\t\tmap.insert(\"sha3-256sum\", ({krate}::uumain, {krate}::uu_app_common));\n\
|
||||
\t\tmap.insert(\"sha3-384sum\", ({krate}::uumain, {krate}::uu_app_common));\n\
|
||||
\t\tmap.insert(\"sha3-512sum\", ({krate}::uumain, {krate}::uu_app_common));\n\
|
||||
\t\tmap.insert(\"shake128sum\", ({krate}::uumain, {krate}::uu_app_common));\n\
|
||||
\t\tmap.insert(\"shake256sum\", ({krate}::uumain, {krate}::uu_app_common));\n\
|
||||
",
|
||||
krate = krate
|
||||
)
|
||||
|
@ -153,7 +153,7 @@ pub fn main() {
|
|||
_ => {
|
||||
mf.write_all(
|
||||
format!(
|
||||
"\tmap.insert(\"{krate}\", {krate}::uumain);\n",
|
||||
"\tmap.insert(\"{krate}\", ({krate}::uumain, {krate}::uu_app));\n",
|
||||
krate = krate
|
||||
)
|
||||
.as_bytes(),
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use clap::App;
|
||||
use clap::Shell;
|
||||
use std::cmp;
|
||||
use std::collections::hash_map::HashMap;
|
||||
use std::ffi::OsString;
|
||||
|
@ -52,7 +54,7 @@ fn main() {
|
|||
let binary_as_util = name(&binary);
|
||||
|
||||
// binary name equals util name?
|
||||
if let Some(&uumain) = utils.get(binary_as_util) {
|
||||
if let Some(&(uumain, _)) = utils.get(binary_as_util) {
|
||||
process::exit(uumain((vec![binary.into()].into_iter()).chain(args)));
|
||||
}
|
||||
|
||||
|
@ -74,8 +76,12 @@ fn main() {
|
|||
if let Some(util_os) = util_name {
|
||||
let util = util_os.as_os_str().to_string_lossy();
|
||||
|
||||
if util == "completion" {
|
||||
gen_completions(args, utils);
|
||||
}
|
||||
|
||||
match utils.get(&util[..]) {
|
||||
Some(&uumain) => {
|
||||
Some(&(uumain, _)) => {
|
||||
process::exit(uumain((vec![util_os].into_iter()).chain(args)));
|
||||
}
|
||||
None => {
|
||||
|
@ -85,7 +91,7 @@ fn main() {
|
|||
let util = util_os.as_os_str().to_string_lossy();
|
||||
|
||||
match utils.get(&util[..]) {
|
||||
Some(&uumain) => {
|
||||
Some(&(uumain, _)) => {
|
||||
let code = uumain(
|
||||
(vec![util_os, OsString::from("--help")].into_iter())
|
||||
.chain(args),
|
||||
|
@ -113,3 +119,43 @@ fn main() {
|
|||
process::exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints completions for the utility in the first parameter for the shell in the second parameter to stdout
|
||||
fn gen_completions<T: uucore::Args>(
|
||||
mut args: impl Iterator<Item = OsString>,
|
||||
util_map: UtilityMap<T>,
|
||||
) -> ! {
|
||||
let utility = args
|
||||
.next()
|
||||
.expect("expected utility as the first parameter")
|
||||
.to_str()
|
||||
.expect("utility name was not valid utf-8")
|
||||
.to_owned();
|
||||
let shell = args
|
||||
.next()
|
||||
.expect("expected shell as the second parameter")
|
||||
.to_str()
|
||||
.expect("shell name was not valid utf-8")
|
||||
.to_owned();
|
||||
let mut app = if utility == "coreutils" {
|
||||
gen_coreutils_app(util_map)
|
||||
} else if let Some((_, app)) = util_map.get(utility.as_str()) {
|
||||
app()
|
||||
} else {
|
||||
eprintln!("{} is not a valid utility", utility);
|
||||
process::exit(1)
|
||||
};
|
||||
let shell: Shell = shell.parse().unwrap();
|
||||
let bin_name = std::env::var("PROG_PREFIX").unwrap_or_default() + &utility;
|
||||
app.gen_completions_to(bin_name, shell, &mut io::stdout());
|
||||
io::stdout().flush().unwrap();
|
||||
process::exit(0);
|
||||
}
|
||||
|
||||
fn gen_coreutils_app<T: uucore::Args>(util_map: UtilityMap<T>) -> App<'static, 'static> {
|
||||
let mut app = App::new("coreutils");
|
||||
for (_, (_, sub_app)) in util_map {
|
||||
app = app.subcommand(sub_app());
|
||||
}
|
||||
app
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue