Skip to content

Commit

Permalink
Merge pull request #2414 from miDeb/completions2
Browse files Browse the repository at this point in the history
uutils: implement shell completions
  • Loading branch information
sylvestre authored Jun 26, 2021
2 parents 5981351 + 9b8150d commit 5fce7ec
Show file tree
Hide file tree
Showing 110 changed files with 3,652 additions and 3,248 deletions.
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
8 changes: 8 additions & 0 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -314,13 +314,21 @@ 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)
rm -f $(addprefix $(INSTALLDIR_BIN)/,$(PROG_PREFIX)coreutils)
endif
rm -f $(addprefix $(INSTALLDIR_MAN)/,$(PROG_PREFIX)coreutils.1.gz)
rm -f $(addprefix $(INSTALLDIR_BIN)/$(PROG_PREFIX),$(PROGS))
rm -f $(addprefix $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_$(PROG_PREFIX),$(PROGS))
rm -f $(addprefix $(DESTDIR)$(PREFIX)/share/bash-completion/completions/$(PROG_PREFIX),$(PROGS))
rm -f $(addprefix $(DESTDIR)$(PREFIX)/share/fish/vendor_completions.d/$(PROG_PREFIX),$(addsuffix .fish,$(PROGS)))
rm -f $(addprefix $(INSTALLDIR_MAN)/$(PROG_PREFIX),$(addsuffix .1.gz,$(PROGS)))

.PHONY: all build build-coreutils build-pkgs build-docs test distclean clean busytest install uninstall
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ $ cargo install --path .

This command will install uutils into Cargo's *bin* folder (*e.g.* `$HOME/.cargo/bin`).

This does not install files necessary for shell completion. For shell completion to work,
use `GNU Make` or see `Manually install shell completions`.

### GNU Make

To install all available utilities:
Expand Down Expand Up @@ -179,6 +182,10 @@ Set install parent directory (default value is /usr/local):
$ make PREFIX=/my/path install
```

Installing with `make` installs shell completions for all installed utilities
for `bash`, `fish` and `zsh`. Completions for `elvish` and `powershell` can also
be generated; See `Manually install shell completions`.

### NixOS

The [standard package set](https://nixos.org/nixpkgs/manual/) of [NixOS](https://nixos.org/)
Expand All @@ -188,6 +195,23 @@ provides this package out of the box since 18.03:
$ nix-env -iA nixos.uutils-coreutils
```

### Manually install shell completions

The `coreutils` binary can generate completions for the `bash`, `elvish`, `fish`, `powershell`
and `zsh` shells. It prints the result to stdout.

The syntax is:
```bash
cargo run completion <utility> <shell>
```

So, to install completions for `ls` on `bash` to `/usr/local/share/bash-completion/completions/ls`,
run:

```bash
cargo run completion ls bash > /usr/local/share/bash-completion/completions/ls
```

## Un-installation Instructions

Un-installation differs depending on how you have installed uutils. If you used
Expand Down
40 changes: 20 additions & 20 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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\
Expand All @@ -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
)
Expand All @@ -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
)
Expand All @@ -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(),
Expand All @@ -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
)
Expand All @@ -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(),
Expand Down
52 changes: 49 additions & 3 deletions src/bin/coreutils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)));
}

Expand All @@ -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 => {
Expand All @@ -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),
Expand Down Expand Up @@ -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
}
13 changes: 8 additions & 5 deletions src/uu/arch/src/arch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@ static ABOUT: &str = "Display machine architecture";
static SUMMARY: &str = "Determine architecture name for current machine.";

pub fn uumain(args: impl uucore::Args) -> i32 {
App::new(executable!())
.version(crate_version!())
.about(ABOUT)
.after_help(SUMMARY)
.get_matches_from(args);
uu_app().get_matches_from(args);

let uts = return_if_err!(1, PlatformInfo::new());
println!("{}", uts.machine().trim());
0
}

pub fn uu_app() -> App<'static, 'static> {
App::new(executable!())
.version(crate_version!())
.about(ABOUT)
.after_help(SUMMARY)
}
5 changes: 5 additions & 0 deletions src/uu/base32/src/base32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ extern crate uucore;

use std::io::{stdin, Read};

use clap::App;
use uucore::encoding::Format;

pub mod base_common;
Expand Down Expand Up @@ -56,3 +57,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {

0
}

pub fn uu_app() -> App<'static, 'static> {
base_common::base_app(executable!(), VERSION, ABOUT)
}
17 changes: 10 additions & 7 deletions src/uu/base32/src/base_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,17 @@ pub fn parse_base_cmd_args(
about: &str,
usage: &str,
) -> Result<Config, String> {
let app = App::new(name)
let app = base_app(name, version, about).usage(usage);
let arg_list = args
.collect_str(InvalidEncodingHandling::ConvertLossy)
.accept_any();
Config::from(app.get_matches_from(arg_list))
}

pub fn base_app<'a>(name: &str, version: &'a str, about: &'a str) -> App<'static, 'a> {
App::new(name)
.version(version)
.about(about)
.usage(usage)
// Format arguments.
.arg(
Arg::with_name(options::DECODE)
Expand All @@ -106,11 +113,7 @@ pub fn parse_base_cmd_args(
)
// "multiple" arguments are used to check whether there is more than one
// file passed in.
.arg(Arg::with_name(options::FILE).index(1).multiple(true));
let arg_list = args
.collect_str(InvalidEncodingHandling::ConvertLossy)
.accept_any();
Config::from(app.get_matches_from(arg_list))
.arg(Arg::with_name(options::FILE).index(1).multiple(true))
}

pub fn get_input<'a>(config: &Config, stdin_ref: &'a Stdin) -> Box<dyn Read + 'a> {
Expand Down
1 change: 1 addition & 0 deletions src/uu/base64/src/base64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
extern crate uucore;

use uu_base32::base_common;
pub use uu_base32::uu_app;

use uucore::encoding::Format;

Expand Down
Loading

0 comments on commit 5fce7ec

Please sign in to comment.