Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Categories Used:
- Support `.lzma` decompression (and fix `.lzma` being a wrong alias for `.xz`) [\#838](https://github.com/ouch-org/ouch/pull/838) ([zzzsyyy](https://github.com/zzzsyyy))
- Support `.lz` compression [\#867](https://github.com/ouch-org/ouch/pull/867) ([sorairolake](https://github.com/sorairolake))
- Support `.lzma` compression [\#867](https://github.com/ouch-org/ouch/pull/867) ([sorairolake](https://github.com/sorairolake))
- Add `--completions` flag to generate shell completion scripts

### Improvements

Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ bytesize = "1.3.0"
bzip2 = "0.4.4"
bzip3 = { version = "0.9.0", features = ["bundled"], optional = true }
clap = { version = "4.5.20", features = ["derive", "env"] }
clap_complete = "4.5.28"
filetime_creation = "0.2"
flate2 = { version = "1.0.30", default-features = false }
fs-err = "2.11.0"
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ ouch help <COMMAND>
ouch <COMMAND> --help # equivalent
```

## Shell Completions

You can generate shell completion scripts using the `--completions` flag:

```sh
# Generate bash completions
ouch --completions bash

# Generate zsh completions
ouch --completions zsh
```

## Decompressing

Use the `decompress` subcommand, `ouch` will detect the extensions automatically.
Expand Down
8 changes: 8 additions & 0 deletions ouch.code-workspace
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"folders": [
{
"path": "."
}
],
"settings": {}
}
64 changes: 47 additions & 17 deletions src/cli/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,13 @@ pub struct CliArgs {
#[arg(short = 'c', long, global = true)]
pub threads: Option<usize>,

/// Generate shell completion scripts
#[arg(long, exclusive = true, value_enum)]
pub completions: Option<clap_complete::Shell>,

// Ouch and claps subcommands
#[command(subcommand)]
pub cmd: Subcommand,
pub cmd: Option<Subcommand>,
}

#[derive(Parser, PartialEq, Eq, Debug)]
Expand Down Expand Up @@ -151,12 +155,13 @@ mod tests {
// This is usually replaced in assertion tests
password: None,
threads: None,
cmd: Subcommand::Decompress {
cmd: Some(Subcommand::Decompress {
// Put a crazy value here so no test can assert it unintentionally
files: vec!["\x00\x11\x22".into()],
output_dir: None,
remove: false,
},
}),
completions: None,
}
}

Expand All @@ -165,76 +170,76 @@ mod tests {
test!(
"ouch decompress file.tar.gz",
CliArgs {
cmd: Subcommand::Decompress {
cmd: Some(Subcommand::Decompress {
files: to_paths(["file.tar.gz"]),
output_dir: None,
remove: false,
},
}),
..mock_cli_args()
}
);
test!(
"ouch d file.tar.gz",
CliArgs {
cmd: Subcommand::Decompress {
cmd: Some(Subcommand::Decompress {
files: to_paths(["file.tar.gz"]),
output_dir: None,
remove: false,
},
}),
..mock_cli_args()
}
);
test!(
"ouch d a b c",
CliArgs {
cmd: Subcommand::Decompress {
cmd: Some(Subcommand::Decompress {
files: to_paths(["a", "b", "c"]),
output_dir: None,
remove: false,
},
}),
..mock_cli_args()
}
);

test!(
"ouch compress file file.tar.gz",
CliArgs {
cmd: Subcommand::Compress {
cmd: Some(Subcommand::Compress {
files: to_paths(["file"]),
output: PathBuf::from("file.tar.gz"),
level: None,
fast: false,
slow: false,
follow_symlinks: false,
},
}),
..mock_cli_args()
}
);
test!(
"ouch compress a b c archive.tar.gz",
CliArgs {
cmd: Subcommand::Compress {
cmd: Some(Subcommand::Compress {
files: to_paths(["a", "b", "c"]),
output: PathBuf::from("archive.tar.gz"),
level: None,
fast: false,
slow: false,
follow_symlinks: false,
},
}),
..mock_cli_args()
}
);
test!(
"ouch compress a b c archive.tar.gz",
CliArgs {
cmd: Subcommand::Compress {
cmd: Some(Subcommand::Compress {
files: to_paths(["a", "b", "c"]),
output: PathBuf::from("archive.tar.gz"),
level: None,
fast: false,
slow: false,
follow_symlinks: false,
},
}),
..mock_cli_args()
}
);
Expand All @@ -252,19 +257,44 @@ mod tests {
test!(
input,
CliArgs {
cmd: Subcommand::Compress {
cmd: Some(Subcommand::Compress {
files: to_paths(["a", "b", "c"]),
output: PathBuf::from("output"),
level: None,
fast: false,
slow: false,
follow_symlinks: false,
},
}),
format: Some("tar.gz".into()),
..mock_cli_args()
}
);
}

test!(
"ouch --completions bash",
CliArgs {
completions: Some(clap_complete::Shell::Bash),
cmd: None,
..mock_cli_args()
}
);
test!(
"ouch --completions zsh",
CliArgs {
completions: Some(clap_complete::Shell::Zsh),
cmd: None,
..mock_cli_args()
}
);
test!(
"ouch --completions fish",
CliArgs {
completions: Some(clap_complete::Shell::Fish),
cmd: None,
..mock_cli_args()
}
);
}

#[test]
Expand Down
18 changes: 16 additions & 2 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use std::{
path::{Path, PathBuf},
};

use clap::Parser;
use clap::{error::ErrorKind, CommandFactory, Parser};
use clap_complete::generate;
use fs_err as fs;

pub use self::args::{CliArgs, Subcommand};
Expand All @@ -26,6 +27,19 @@ impl CliArgs {
pub fn parse_and_validate_args() -> crate::Result<(Self, QuestionPolicy, FileVisibilityPolicy)> {
let mut args = Self::parse();

if let Some(shell) = args.completions {
let mut cmd = Self::command();
let name = cmd.get_name().to_string();
generate(shell, &mut cmd, name, &mut io::stdout());
std::process::exit(0);
}

if args.cmd.is_none() {
let mut cmd = Self::command();
cmd.error(ErrorKind::MissingSubcommand, "A subcommand is required (compress, decompress, list)...")
.exit();
}

set_accessible(args.accessible);
set_log_display_level(args.quiet);

Expand All @@ -36,7 +50,7 @@ impl CliArgs {

let (Subcommand::Compress { files, .. }
| Subcommand::Decompress { files, .. }
| Subcommand::List { archives: files, .. }) = &mut args.cmd;
| Subcommand::List { archives: files, .. }) = args.cmd.as_mut().unwrap();
*files = canonicalize_files(files)?;

let skip_questions_positively = match (args.yes, args.no) {
Expand Down
2 changes: 1 addition & 1 deletion src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub fn run(
.unwrap();
}

match args.cmd {
match args.cmd.unwrap() {
Subcommand::Compress {
files,
output: output_path,
Expand Down
27 changes: 14 additions & 13 deletions tests/snapshots/ui__ui_test_usage_help_flag-2.snap
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
---
source: tests/ui.rs
assertion_line: 176
expression: "output_to_string(ouch!(\"-h\"))"
snapshot_kind: text
---
A command-line utility for easily compressing and decompressing files and directories.

Usage: <OUCH_BIN> [OPTIONS] <COMMAND>
Usage: <OUCH_BIN> [OPTIONS] [COMMAND]

Commands:
compress Compress one or more files into one output file [aliases: c]
Expand All @@ -14,14 +14,15 @@ Commands:
help Print this message or the help of the given subcommand(s)

Options:
-y, --yes Skip [Y/n] questions, default to yes
-n, --no Skip [Y/n] questions, default to no
-A, --accessible Activate accessibility mode, reducing visual noise [env: ACCESSIBLE=]
-H, --hidden Ignore hidden files
-q, --quiet Silence output
-g, --gitignore Ignore files matched by git's ignore files
-f, --format <FORMAT> Specify the format of the archive
-p, --password <PASSWORD> Decompress or list with password
-c, --threads <THREADS> Concurrent working threads
-h, --help Print help (see more with '--help')
-V, --version Print version
-y, --yes Skip [Y/n] questions, default to yes
-n, --no Skip [Y/n] questions, default to no
-A, --accessible Activate accessibility mode, reducing visual noise [env: ACCESSIBLE=]
-H, --hidden Ignore hidden files
-q, --quiet Silence output
-g, --gitignore Ignore files matched by git's ignore files
-f, --format <FORMAT> Specify the format of the archive
-p, --password <PASSWORD> Decompress or list with password
-c, --threads <THREADS> Concurrent working threads
--completions <COMPLETIONS> Generate shell completion scripts [possible values: bash, elvish, fish, powershell, zsh]
-h, --help Print help (see more with '--help')
-V, --version Print version
9 changes: 7 additions & 2 deletions tests/snapshots/ui__ui_test_usage_help_flag.snap
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
---
source: tests/ui.rs
assertion_line: 175
expression: "output_to_string(ouch!(\"--help\"))"
snapshot_kind: text
---
A command-line utility for easily compressing and decompressing files and directories.

Supported formats: tar, zip, gz, 7z, xz, lzma, lzip, bz/bz2, bz3, lz4, sz (Snappy), zst, rar and br.

Repository: https://github.com/ouch-org/ouch

Usage: <OUCH_BIN> [OPTIONS] <COMMAND>
Usage: <OUCH_BIN> [OPTIONS] [COMMAND]

Commands:
compress Compress one or more files into one output file [aliases: c]
Expand Down Expand Up @@ -47,6 +47,11 @@ Options:
-c, --threads <THREADS>
Concurrent working threads

--completions <COMPLETIONS>
Generate shell completion scripts

[possible values: bash, elvish, fish, powershell, zsh]

-h, --help
Print help (see a summary with '-h')

Expand Down
Loading