diff --git a/Cargo.lock b/Cargo.lock index 5f96f7f8b..51424332d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -218,6 +218,7 @@ version = "0.0.6" dependencies = [ "atty", "chrono", + "clap", "conv", "filetime", "glob 0.3.0", diff --git a/Cargo.toml b/Cargo.toml index 0fec2af78..2783ff1b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" } diff --git a/GNUmakefile b/GNUmakefile index e5ad01340..ea9c7254a 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -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) diff --git a/build.rs b/build.rs index 2ed8e1345..e9fe129eb 100644 --- a/build.rs +++ b/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 = HashMap<&'static str, fn(T) -> i32>;\n\ + "type UtilityMap = HashMap<&'static str, (fn(T) -> i32, fn() -> App<'static, 'static>)>;\n\ \n\ fn util_map() -> UtilityMap {\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(), diff --git a/src/bin/coreutils.rs b/src/bin/coreutils.rs index 2e703b682..270f5153a 100644 --- a/src/bin/coreutils.rs +++ b/src/bin/coreutils.rs @@ -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( + mut args: impl Iterator, + util_map: UtilityMap, +) -> ! { + 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(util_map: UtilityMap) -> App<'static, 'static> { + let mut app = App::new("coreutils"); + for (_, (_, sub_app)) in util_map { + app = app.subcommand(sub_app()); + } + app +}