Add --man subcommand (#2041)

This commit is contained in:
Casey Rodarmor 2024-05-15 00:28:50 -07:00 committed by GitHub
parent 07aaa4f440
commit a9b0912b2b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 220 additions and 159 deletions

17
Cargo.lock generated
View File

@ -215,6 +215,16 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
[[package]]
name = "clap_mangen"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1dd95b5ebb5c1c54581dd6346f3ed6a79a3eef95dd372fc2ac13d535535300e"
dependencies = [
"clap 4.5.4",
"roff",
]
[[package]] [[package]]
name = "colorchoice" name = "colorchoice"
version = "1.0.1" version = "1.0.1"
@ -512,6 +522,7 @@ dependencies = [
"camino", "camino",
"clap 4.5.4", "clap 4.5.4",
"clap_complete", "clap_complete",
"clap_mangen",
"cradle", "cradle",
"ctrlc", "ctrlc",
"derivative", "derivative",
@ -774,6 +785,12 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
[[package]]
name = "roff"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.34" version = "0.38.34"

View File

@ -15,7 +15,7 @@ repository = "https://github.com/casey/just"
rust-version = "1.63" rust-version = "1.63"
[workspace] [workspace]
members = [".", "bin/ref-type", "bin/generate-book", "bin/update-contributors"] members = [".", "crates/*"]
[dependencies] [dependencies]
ansi_term = "0.12.0" ansi_term = "0.12.0"
@ -24,6 +24,7 @@ blake3 = { version = "1.5.0", features = ["rayon", "mmap"] }
camino = "1.0.4" camino = "1.0.4"
clap = { version = "4.0.0", features = ["env", "wrap_help"] } clap = { version = "4.0.0", features = ["env", "wrap_help"] }
clap_complete = "4.0.0" clap_complete = "4.0.0"
clap_mangen = "0.2.20"
ctrlc = { version = "3.1.1", features = ["termination"] } ctrlc = { version = "3.1.1", features = ["termination"] }
derivative = "2.0.0" derivative = "2.0.0"
dirs = "5.0.1" dirs = "5.0.1"
@ -64,13 +65,6 @@ path = "src/main.rs"
name = "just" name = "just"
test = false test = false
[features]
# No features are active by default.
default = []
# The `help4help2man` feature modifies the message produced by `--help`
# so that `help2man` produces a reasonable man page.
help4help2man = []
# The public documentation is minimal and doesn't change between # The public documentation is minimal and doesn't change between
# platforms, so we only build them for linux on docs.rs to save # platforms, so we only build them for linux on docs.rs to save
# their build machines some cycles. # their build machines some cycles.

View File

@ -3158,6 +3158,14 @@ fpath=($HOMEBREW_PREFIX/share/zsh/site-functions $fpath)
# compinit # compinit
``` ```
### Man Page
`just` can print its own man page with `just --man`. Man pages are written in
[`roff`](https://en.wikipedia.org/wiki/Roff_%28software%29), a venerable markup
language and one of the first practical applications of Unix. If you have
[`groff`](https://www.gnu.org/software/groff/) installed you can view the man
page with `just --man | groff -mandoc -Tascii | less`.
### Grammar ### Grammar
A non-normative grammar of `justfile`s can be found in A non-normative grammar of `justfile`s can be found in

View File

@ -30,7 +30,7 @@ _just() {
case "${cmd}" in case "${cmd}" in
"$1") "$1")
opts="-n -f -q -u -v -d -c -e -l -s -E -h -V --check --chooser --color --command-color --yes --dry-run --dump-format --highlight --list-heading --list-prefix --no-aliases --no-deps --no-dotenv --no-highlight --justfile --quiet --set --shell --shell-arg --shell-command --clear-shell-args --unsorted --unstable --verbose --working-directory --changelog --choose --command --completions --dump --edit --evaluate --fmt --init --list --show --summary --variables --dotenv-filename --dotenv-path --help --version [ARGUMENTS]..." opts="-n -f -q -u -v -d -c -e -l -s -E -h -V --check --chooser --color --command-color --yes --dry-run --dump-format --highlight --list-heading --list-prefix --no-aliases --no-deps --no-dotenv --no-highlight --justfile --quiet --set --shell --shell-arg --shell-command --clear-shell-args --unsorted --unstable --verbose --working-directory --changelog --choose --command --completions --dump --edit --evaluate --fmt --init --list --man --show --summary --variables --dotenv-filename --dotenv-path --help --version [ARGUMENTS]..."
if [[ ${cur} == -* ]] ; then if [[ ${cur} == -* ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0

View File

@ -66,6 +66,7 @@ set edit:completion:arg-completer[just] = {|@words|
cand --init 'Initialize new justfile in project root' cand --init 'Initialize new justfile in project root'
cand -l 'List available recipes and their arguments' cand -l 'List available recipes and their arguments'
cand --list 'List available recipes and their arguments' cand --list 'List available recipes and their arguments'
cand --man 'Print man page'
cand --summary 'List names of available recipes' cand --summary 'List names of available recipes'
cand --variables 'List names of variables' cand --variables 'List names of variables'
cand -h 'Print help' cand -h 'Print help'

View File

@ -73,6 +73,7 @@ complete -c just -l evaluate -d 'Evaluate and print all variables. If a variable
complete -c just -l fmt -d 'Format and overwrite justfile' complete -c just -l fmt -d 'Format and overwrite justfile'
complete -c just -l init -d 'Initialize new justfile in project root' complete -c just -l init -d 'Initialize new justfile in project root'
complete -c just -s l -l list -d 'List available recipes and their arguments' complete -c just -s l -l list -d 'List available recipes and their arguments'
complete -c just -l man -d 'Print man page'
complete -c just -l summary -d 'List names of available recipes' complete -c just -l summary -d 'List names of available recipes'
complete -c just -l variables -d 'List names of variables' complete -c just -l variables -d 'List names of variables'
complete -c just -s h -l help -d 'Print help' complete -c just -s h -l help -d 'Print help'

View File

@ -69,6 +69,7 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock {
[CompletionResult]::new('--init', 'init', [CompletionResultType]::ParameterName, 'Initialize new justfile in project root') [CompletionResult]::new('--init', 'init', [CompletionResultType]::ParameterName, 'Initialize new justfile in project root')
[CompletionResult]::new('-l', 'l', [CompletionResultType]::ParameterName, 'List available recipes and their arguments') [CompletionResult]::new('-l', 'l', [CompletionResultType]::ParameterName, 'List available recipes and their arguments')
[CompletionResult]::new('--list', 'list', [CompletionResultType]::ParameterName, 'List available recipes and their arguments') [CompletionResult]::new('--list', 'list', [CompletionResultType]::ParameterName, 'List available recipes and their arguments')
[CompletionResult]::new('--man', 'man', [CompletionResultType]::ParameterName, 'Print man page')
[CompletionResult]::new('--summary', 'summary', [CompletionResultType]::ParameterName, 'List names of available recipes') [CompletionResult]::new('--summary', 'summary', [CompletionResultType]::ParameterName, 'List names of available recipes')
[CompletionResult]::new('--variables', 'variables', [CompletionResultType]::ParameterName, 'List names of variables') [CompletionResult]::new('--variables', 'variables', [CompletionResultType]::ParameterName, 'List names of variables')
[CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help')

View File

@ -64,6 +64,7 @@ _just() {
'--init[Initialize new justfile in project root]' \ '--init[Initialize new justfile in project root]' \
'-l[List available recipes and their arguments]' \ '-l[List available recipes and their arguments]' \
'--list[List available recipes and their arguments]' \ '--list[List available recipes and their arguments]' \
'--man[Print man page]' \
'--summary[List names of available recipes]' \ '--summary[List names of available recipes]' \
'--variables[List names of variables]' \ '--variables[List names of variables]' \
'-h[Print help]' \ '-h[Print help]' \

View File

@ -43,13 +43,7 @@ shellcheck:
shellcheck www/install.sh shellcheck www/install.sh
man: man:
cargo build --features help4help2man cargo run -- --man > man/just.1
help2man \
--name 'save and run commands' \
--manual 'Just Manual' \
--no-info \
target/debug/just \
> man/just.1
view-man: man view-man: man
man man/just.1 man man/just.1
@ -115,10 +109,6 @@ install-dev-deps:
cargo install cargo-watch cargo install cargo-watch
cargo install mdbook mdbook-linkcheck cargo install mdbook mdbook-linkcheck
# install system development dependencies with homebrew
install-dev-deps-homebrew:
brew install help2man
# everyone's favorite animate paper clip # everyone's favorite animate paper clip
clippy: clippy:
cargo clippy --all --all-targets --all-features cargo clippy --all --all-targets --all-features

View File

@ -1,159 +1,168 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. .ie \n(.g .ds Aq \(aq
.TH JUST "1" "May 2024" "just 1.26.0" "Just Manual" .el .ds Aq '
.TH just 1 "just 1.26.0"
.SH NAME .SH NAME
just \- save and run commands just \- 🤖 Just a command runner \- https://github.com/casey/just
.SH SYNOPSIS
\fBjust\fR [\fB\-\-check\fR] [\fB\-\-chooser\fR] [\fB\-\-color\fR] [\fB\-\-command\-color\fR] [\fB\-\-yes\fR] [\fB\-n\fR|\fB\-\-dry\-run\fR] [\fB\-\-dump\-format\fR] [\fB\-\-highlight\fR] [\fB\-\-list\-heading\fR] [\fB\-\-list\-prefix\fR] [\fB\-\-no\-aliases\fR] [\fB\-\-no\-deps\fR] [\fB\-\-no\-dotenv\fR] [\fB\-\-no\-highlight\fR] [\fB\-f\fR|\fB\-\-justfile\fR] [\fB\-q\fR|\fB\-\-quiet\fR] [\fB\-\-set\fR] [\fB\-\-shell\fR] [\fB\-\-shell\-arg\fR] [\fB\-\-shell\-command\fR] [\fB\-\-clear\-shell\-args\fR] [\fB\-u\fR|\fB\-\-unsorted\fR] [\fB\-\-unstable\fR] [\fB\-v\fR|\fB\-\-verbose\fR]... [\fB\-d\fR|\fB\-\-working\-directory\fR] [\fB\-\-changelog\fR] [\fB\-\-choose\fR] [\fB\-c\fR|\fB\-\-command\fR] [\fB\-\-completions\fR] [\fB\-\-dump\fR] [\fB\-e\fR|\fB\-\-edit\fR] [\fB\-\-evaluate\fR] [\fB\-\-fmt\fR] [\fB\-\-init\fR] [\fB\-l\fR|\fB\-\-list\fR] [\fB\-\-man\fR] [\fB\-s\fR|\fB\-\-show\fR] [\fB\-\-summary\fR] [\fB\-\-variables\fR] [\fB\-\-dotenv\-filename\fR] [\fB\-E\fR|\fB\-\-dotenv\-path\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] [\fIARGUMENTS\fR]
.SH DESCRIPTION .SH DESCRIPTION
just 1.26.0 🤖 Just a command runner \- https://github.com/casey/just
\- Please see https://github.com/casey/just for more information. .SH OPTIONS
.SS "USAGE:"
.IP
just [FLAGS] [OPTIONS] [\-\-] [ARGUMENTS]...
.SS "FLAGS:"
.TP
\fB\-\-changelog\fR
Print changelog
.TP .TP
\fB\-\-check\fR \fB\-\-check\fR
Run `\-\-fmt` in 'check' mode. Exits with 0 if justfile is formatted Run `\-\-fmt` in \*(Aqcheck\*(Aq mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.
correctly. Exits with 1 and prints a diff if formatting is required.
.TP .TP
\fB\-\-choose\fR \fB\-\-chooser\fR
Select one or more recipes to run using a binary chooser. If `\-\-chooser` is Override binary invoked by `\-\-choose`
not passed the chooser defaults to the value of $JUST_CHOOSER, falling back .RS
to `fzf` May also be specified with the \fBJUST_CHOOSER\fR environment variable.
.RE
.TP
\fB\-\-color\fR [default: auto]
Print colorful output
.br
.br
[\fIpossible values: \fRauto, always, never]
.TP
\fB\-\-command\-color\fR
Echo recipe lines in <COMMAND\-COLOR>
.br
.br
[\fIpossible values: \fRblack, blue, cyan, green, purple, red, yellow]
.TP
\fB\-\-yes\fR
Automatically confirm all recipes.
.TP
\fB\-n\fR, \fB\-\-dry\-run\fR
Print what just would do without doing it
.TP
\fB\-\-dump\-format\fR=\fIFORMAT\fR [default: just]
Dump justfile as <FORMAT>
.br
.br
[\fIpossible values: \fRjust, json]
.TP
\fB\-\-highlight\fR
Highlight echoed recipe lines in bold
.TP
\fB\-\-list\-heading\fR=\fITEXT\fR
Print <TEXT> before list
.TP
\fB\-\-list\-prefix\fR=\fITEXT\fR
Print <TEXT> before each list item
.TP
\fB\-\-no\-aliases\fR
Don\*(Aqt show aliases in list
.TP
\fB\-\-no\-deps\fR
Don\*(Aqt run recipe dependencies
.TP
\fB\-\-no\-dotenv\fR
Don\*(Aqt load `.env` file
.TP
\fB\-\-no\-highlight\fR
Don\*(Aqt highlight echoed recipe lines in bold
.TP
\fB\-f\fR, \fB\-\-justfile\fR
Use <JUSTFILE> as justfile
.TP
\fB\-q\fR, \fB\-\-quiet\fR
Suppress all output
.TP
\fB\-\-set\fR=\fIVARIABLE VALUE\fR
Override <VARIABLE> with <VALUE>
.TP
\fB\-\-shell\fR
Invoke <SHELL> to run recipes
.TP
\fB\-\-shell\-arg\fR
Invoke shell with <SHELL\-ARG> as an argument
.TP
\fB\-\-shell\-command\fR
Invoke <COMMAND> with the shell used to run recipe lines and backticks
.TP .TP
\fB\-\-clear\-shell\-args\fR \fB\-\-clear\-shell\-args\fR
Clear shell arguments Clear shell arguments
.TP .TP
\fB\-n\fR, \fB\-\-dry\-run\fR \fB\-u\fR, \fB\-\-unsorted\fR
Print what just would do without doing it Return list and summary entries in source order
.TP
\fB\-\-unstable\fR
Enable unstable features
.RS
May also be specified with the \fBJUST_UNSTABLE\fR environment variable.
.RE
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Use verbose output
.TP
\fB\-d\fR, \fB\-\-working\-directory\fR
Use <WORKING\-DIRECTORY> as working directory. \-\-justfile must also be set
.TP
\fB\-\-changelog\fR
Print changelog
.TP
\fB\-\-choose\fR
Select one or more recipes to run using a binary chooser. If `\-\-chooser` is not passed the chooser defaults to the value of $JUST_CHOOSER, falling back to `fzf`
.TP
\fB\-c\fR, \fB\-\-command\fR
Run an arbitrary command with the working directory, `.env`, overrides, and exports set
.TP
\fB\-\-completions\fR=\fISHELL\fR
Print shell completion script for <SHELL>
.br
.br
[\fIpossible values: \fRbash, elvish, fish, powershell, zsh]
.TP .TP
\fB\-\-dump\fR \fB\-\-dump\fR
Print justfile Print justfile
.TP .TP
\fB\-e\fR, \fB\-\-edit\fR \fB\-e\fR, \fB\-\-edit\fR
Edit justfile with editor given by $VISUAL or $EDITOR, falling back to Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`
`vim`
.TP .TP
\fB\-\-evaluate\fR \fB\-\-evaluate\fR
Evaluate and print all variables. If a variable name is given as an Evaluate and print all variables. If a variable name is given as an argument, only print that variable\*(Aqs value.
argument, only print that variable's value.
.TP .TP
\fB\-\-fmt\fR \fB\-\-fmt\fR
Format and overwrite justfile Format and overwrite justfile
.TP .TP
\fB\-\-highlight\fR
Highlight echoed recipe lines in bold
.TP
\fB\-\-init\fR \fB\-\-init\fR
Initialize new justfile in project root Initialize new justfile in project root
.TP .TP
\fB\-l\fR, \fB\-\-list\fR \fB\-l\fR, \fB\-\-list\fR
List available recipes and their arguments List available recipes and their arguments
.TP .TP
\fB\-\-no\-aliases\fR \fB\-\-man\fR
Don't show aliases in list Print man page
.TP .TP
\fB\-\-no\-deps\fR \fB\-s\fR, \fB\-\-show\fR=\fIRECIPE\fR
Don't run recipe dependencies Show information about <RECIPE>
.TP
\fB\-\-no\-dotenv\fR
Don't load `.env` file
.TP
\fB\-\-no\-highlight\fR
Don't highlight echoed recipe lines in bold
.TP
\fB\-q\fR, \fB\-\-quiet\fR
Suppress all output
.TP
\fB\-\-shell\-command\fR
Invoke <COMMAND> with the shell used to run recipe lines and backticks
.TP .TP
\fB\-\-summary\fR \fB\-\-summary\fR
List names of available recipes List names of available recipes
.TP .TP
\fB\-u\fR, \fB\-\-unsorted\fR
Return list and summary entries in source order
.TP
\fB\-\-unstable\fR
Enable unstable features
.TP
\fB\-\-variables\fR \fB\-\-variables\fR
List names of variables List names of variables
.TP .TP
\fB\-v\fR, \fB\-\-verbose\fR \fB\-\-dotenv\-filename\fR
Use verbose output Search for environment file named <DOTENV\-FILENAME> instead of `.env`
.TP .TP
\fB\-\-yes\fR \fB\-E\fR, \fB\-\-dotenv\-path\fR
Automatically confirm all recipes. Load <DOTENV\-PATH> as environment file instead of searching for one
.TP .TP
\fB\-h\fR, \fB\-\-help\fR \fB\-h\fR, \fB\-\-help\fR
Print help information Print help
.TP .TP
\fB\-V\fR, \fB\-\-version\fR \fB\-V\fR, \fB\-\-version\fR
Print version information Print version
.SS "OPTIONS:"
.TP .TP
\fB\-\-chooser\fR <CHOOSER> [\fIARGUMENTS\fR]
Override binary invoked by `\-\-choose`
.HP
\fB\-\-color\fR <COLOR>
.TP
Print colorful output [default: auto]
[possible values: auto, always, never]
.HP
\fB\-c\fR, \fB\-\-command\fR <COMMAND>
.IP
Run an arbitrary command with the working directory, `.env`, overrides, and exports set
.HP
\fB\-\-command\-color\fR <COMMAND\-COLOR>
.IP
Echo recipe lines in <COMMAND\-COLOR> [possible values: black, blue, cyan, green, purple, red,
yellow]
.HP
\fB\-\-completions\fR <SHELL>
.IP
Print shell completion script for <SHELL> [possible values: zsh, bash, fish, powershell,
elvish]
.HP
\fB\-\-dotenv\-filename\fR <DOTENV\-FILENAME>
.IP
Search for environment file named <DOTENV\-FILENAME> instead of `.env`
.HP
\fB\-E\fR, \fB\-\-dotenv\-path\fR <DOTENV\-PATH>
.IP
Load <DOTENV\-PATH> as environment file instead of searching for one
.HP
\fB\-\-dump\-format\fR <FORMAT>
.TP
Dump justfile as <FORMAT> [default: just]
[possible values: just, json]
.TP
\fB\-f\fR, \fB\-\-justfile\fR <JUSTFILE>
Use <JUSTFILE> as justfile
.TP
\fB\-\-list\-heading\fR <TEXT>
Print <TEXT> before list
.TP
\fB\-\-list\-prefix\fR <TEXT>
Print <TEXT> before each list item
.TP
\fB\-\-set\fR <VARIABLE> <VALUE>
Override <VARIABLE> with <VALUE>
.TP
\fB\-\-shell\fR <SHELL>
Invoke <SHELL> to run recipes
.TP
\fB\-\-shell\-arg\fR <SHELL\-ARG>...
Invoke shell with <SHELL\-ARG> as an argument
.TP
\fB\-s\fR, \fB\-\-show\fR <RECIPE>
Show information about <RECIPE>
.HP
\fB\-d\fR, \fB\-\-working\-directory\fR <WORKING\-DIRECTORY>
.IP
Use <WORKING\-DIRECTORY> as working directory. \fB\-\-justfile\fR must also be set
.SS "ARGS:"
.TP
<ARGUMENTS>...
Overrides and recipe(s) to run, defaulting to the first recipe in the justfile Overrides and recipe(s) to run, defaulting to the first recipe in the justfile
.SH VERSION
v1.26.0
.SH AUTHORS
Casey Rodarmor <casey@rodarmor.com>

View File

@ -56,6 +56,7 @@ mod cmd {
pub(crate) const FORMAT: &str = "FORMAT"; pub(crate) const FORMAT: &str = "FORMAT";
pub(crate) const INIT: &str = "INIT"; pub(crate) const INIT: &str = "INIT";
pub(crate) const LIST: &str = "LIST"; pub(crate) const LIST: &str = "LIST";
pub(crate) const MAN: &str = "MAN";
pub(crate) const SHOW: &str = "SHOW"; pub(crate) const SHOW: &str = "SHOW";
pub(crate) const SUMMARY: &str = "SUMMARY"; pub(crate) const SUMMARY: &str = "SUMMARY";
pub(crate) const VARIABLES: &str = "VARIABLES"; pub(crate) const VARIABLES: &str = "VARIABLES";
@ -71,13 +72,14 @@ mod cmd {
FORMAT, FORMAT,
INIT, INIT,
LIST, LIST,
MAN,
SHOW, SHOW,
SUMMARY, SUMMARY,
VARIABLES, VARIABLES,
]; ];
pub(crate) const ARGLESS: &[&str] = &[ pub(crate) const ARGLESS: &[&str] = &[
CHANGELOG, DUMP, EDIT, FORMAT, INIT, LIST, SUMMARY, VARIABLES, CHANGELOG, DUMP, EDIT, FORMAT, INIT, LIST, MAN, SUMMARY, VARIABLES,
]; ];
} }
@ -140,8 +142,15 @@ mod arg {
impl Config { impl Config {
pub(crate) fn app() -> Command { pub(crate) fn app() -> Command {
let app = Command::new(env!("CARGO_PKG_NAME")) Command::new(env!("CARGO_PKG_NAME"))
.bin_name(env!("CARGO_PKG_NAME")) .bin_name(env!("CARGO_PKG_NAME"))
.version(env!("CARGO_PKG_VERSION"))
.author(env!("CARGO_PKG_AUTHORS"))
.about(concat!(
env!("CARGO_PKG_DESCRIPTION"),
" - ",
env!("CARGO_PKG_HOMEPAGE")
))
.trailing_var_arg(true) .trailing_var_arg(true)
.styles( .styles(
Styles::styled() Styles::styled()
@ -400,6 +409,12 @@ impl Config {
.action(ArgAction::SetTrue) .action(ArgAction::SetTrue)
.help("List available recipes and their arguments"), .help("List available recipes and their arguments"),
) )
.arg(
Arg::new(cmd::MAN)
.long("man")
.action(ArgAction::SetTrue)
.help("Print man page"),
)
.arg( .arg(
Arg::new(cmd::SHOW) Arg::new(cmd::SHOW)
.short('s') .short('s')
@ -442,24 +457,7 @@ impl Config {
.num_args(1..) .num_args(1..)
.action(ArgAction::Append) .action(ArgAction::Append)
.help("Overrides and recipe(s) to run, defaulting to the first recipe in the justfile"), .help("Overrides and recipe(s) to run, defaulting to the first recipe in the justfile"),
); )
if cfg!(feature = "help4help2man") {
app.version(env!("CARGO_PKG_VERSION")).about(concat!(
"- Please see ",
env!("CARGO_PKG_HOMEPAGE"),
" for more information."
))
} else {
app
.version(env!("CARGO_PKG_VERSION"))
.author(env!("CARGO_PKG_AUTHORS"))
.about(concat!(
env!("CARGO_PKG_DESCRIPTION"),
" - ",
env!("CARGO_PKG_HOMEPAGE")
))
}
} }
fn color_from_matches(matches: &ArgMatches) -> ConfigResult<Color> { fn color_from_matches(matches: &ArgMatches) -> ConfigResult<Color> {
@ -629,6 +627,8 @@ impl Config {
Subcommand::Init Subcommand::Init
} else if matches.get_flag(cmd::LIST) { } else if matches.get_flag(cmd::LIST) {
Subcommand::List Subcommand::List
} else if matches.get_flag(cmd::MAN) {
Subcommand::Man
} else if let Some(name) = matches.get_one::<String>(cmd::SHOW).map(Into::into) { } else if let Some(name) = matches.get_one::<String>(cmd::SHOW).map(Into::into) {
Subcommand::Show { name } Subcommand::Show { name }
} else if matches.get_flag(cmd::EVALUATE) { } else if matches.get_flag(cmd::EVALUATE) {

View File

@ -142,6 +142,9 @@ pub(crate) enum Error<'src> {
line_number: Option<usize>, line_number: Option<usize>,
signal: i32, signal: i32,
}, },
StdoutIo {
io_error: io::Error,
},
TempdirIo { TempdirIo {
recipe: &'src str, recipe: &'src str,
io_error: io::Error, io_error: io::Error,
@ -406,6 +409,9 @@ impl<'src> ColorDisplay for Error<'src> {
write!(f, "Recipe `{recipe}` was terminated by signal {signal}")?; write!(f, "Recipe `{recipe}` was terminated by signal {signal}")?;
} }
} }
StdoutIo { io_error } => {
write!(f, "I/O error writing to stdout: {io_error}?")?;
}
TempdirIo { recipe, io_error } => { TempdirIo { recipe, io_error } => {
write!(f, "Recipe `{recipe}` could not be run because of an IO error while trying to create a temporary \ write!(f, "Recipe `{recipe}` could not be run because of an IO error while trying to create a temporary \
directory or write a file to that directory: {io_error}")?; directory or write a file to that directory: {io_error}")?;

View File

@ -1,5 +1,6 @@
use { use {
super::*, super::*,
clap_mangen::Man,
std::io::{Read, Seek}, std::io::{Read, Seek},
tempfile::tempfile, tempfile::tempfile,
}; };
@ -30,6 +31,7 @@ pub(crate) enum Subcommand {
Format, Format,
Init, Init,
List, List,
Man,
Run { Run {
arguments: Vec<String>, arguments: Vec<String>,
overrides: BTreeMap<String, String>, overrides: BTreeMap<String, String>,
@ -56,6 +58,7 @@ impl Subcommand {
} }
Completions { shell } => return Self::completions(*shell), Completions { shell } => return Self::completions(*shell),
Init => return Self::init(config), Init => return Self::init(config),
Man => return Self::man(),
Run { Run {
arguments, arguments,
overrides, overrides,
@ -87,7 +90,7 @@ impl Subcommand {
Show { ref name } => Self::show(config, name, justfile)?, Show { ref name } => Self::show(config, name, justfile)?,
Summary => Self::summary(config, justfile), Summary => Self::summary(config, justfile),
Variables => Self::variables(justfile), Variables => Self::variables(justfile),
Changelog | Completions { .. } | Edit | Init | Run { .. } => unreachable!(), Changelog | Completions { .. } | Edit | Init | Man | Run { .. } => unreachable!(),
} }
Ok(()) Ok(())
@ -440,6 +443,26 @@ impl Subcommand {
} }
} }
fn man() -> Result<(), Error<'static>> {
let mut buffer = Vec::<u8>::new();
Man::new(Config::app())
.render(&mut buffer)
.expect("writing to buffer cannot fail");
let mut stdout = io::stdout().lock();
stdout
.write_all(&buffer)
.map_err(|io_error| Error::StdoutIo { io_error })?;
stdout
.flush()
.map_err(|io_error| Error::StdoutIo { io_error })?;
Ok(())
}
fn list(config: &Config, level: usize, justfile: &Justfile) { fn list(config: &Config, level: usize, justfile: &Justfile) {
const MAX_WIDTH: usize = 50; const MAX_WIDTH: usize = 50;

View File

@ -66,6 +66,7 @@ mod interrupts;
mod invocation_directory; mod invocation_directory;
mod json; mod json;
mod line_prefixes; mod line_prefixes;
mod man;
mod misc; mod misc;
mod modules; mod modules;
mod multibyte_char; mod multibyte_char;

9
tests/man.rs Normal file
View File

@ -0,0 +1,9 @@
use super::*;
#[test]
fn output() {
Test::new()
.arg("--man")
.stdout_regex("(?s).*.TH just 1.*")
.run();
}