Add `config` support and cleanup `readme`

This commit is contained in:
rwxrob 2021-08-23 22:10:27 -04:00
parent d022b32e71
commit 119279f749
No known key found for this signature in database
GPG Key ID: 1CCACEDD2F65578E
2 changed files with 196 additions and 61 deletions

View File

@ -9,7 +9,7 @@ create a new Bash command with a command something like this:
gh repo create rwxrob/mycmd -p rwxrob/template-bash-command gh repo create rwxrob/mycmd -p rwxrob/template-bash-command
``` ```
This `command` inside can then be renamed and finished. This `cmd` inside can then be renamed and finished.
Obviously, not all of this is needed for many Bash scripts, but anything Obviously, not all of this is needed for many Bash scripts, but anything
with more than two subcommands will benefit from the builtin tab with more than two subcommands will benefit from the builtin tab
@ -32,6 +32,7 @@ Required:
Optional: Optional:
* `pandoc` - for rich help docs * `pandoc` - for rich help docs
* `jq` - for `json` and anything that uses it
## Justification ## Justification
@ -48,7 +49,7 @@ more powerful, safer, flexible, and performant than POSIX shell or Zsh.
* Write GitHub Flavored Markdown only * Write GitHub Flavored Markdown only
* Use present tense ("outputs" over "will output") * Use present tense ("outputs" over "will output")
* Prefer "output" and "display" over ~~print~~ * Prefer term "output" and "display" over ~~print~~
* Follow the [naming conventions](#naming-conventions) * Follow the [naming conventions](#naming-conventions)
* Use the official bash path: `#!/bin/bash` * Use the official bash path: `#!/bin/bash`
* Use of `#!/usr/bin/bash` is outdated * Use of `#!/usr/bin/bash` is outdated
@ -65,53 +66,99 @@ Copyright 2021 Rob Muhlestein <rob@rwx.gg>
Released under Apache-2.0 License Released under Apache-2.0 License
Please mention <https://rwxrob.tv> Please mention <https://rwxrob.tv>
## Commands ## The `bar` Command
### The `bar` Command
Bars.
### The `foo` Command
Foos.
### Display Help Information
``` ```
help [<command>] cmd bar
```
Bar the things.
## The `config` Command
```
cmd config
cmd config KEY
cmd config KEY VALUE
```
The `config` command is for reading, writing, and displaying standard
open desktop configurations properties.
### Arguments
With no arguments outputs all the currently cached configuration
settings.
With a single KEY argument fetches the value for that key and outputs
it.
With more than one argument the remaining arguments after the KEY will
be combined into the VALUE and written to the `config` file in the
standard configuration home location (Search for `XDG_CONFIG_HOME` for
more information).
### Configuration `config` File Format
The file (which is always named `config`) uses the simplest possible
format to facilitate standard UNIX parsing and filtering with any number
of existing tools (and no `jq` dependency).
* One KEY=VALUE per line
* KEYs may be anything but the equal sign (`=`)
* VALUEs may be anything but line returns must be escaped
Note that this is *not* the same as Java properties and other similar
format. It is designed for ultimate simplicity, efficiency, and
portability.
## The `foo` Command
Foos things.
## The `help` Command
```
cmd help [COMMAND]
``` ```
Displays specific help information. If no argument is passed displays Displays specific help information. If no argument is passed displays
general help information (main). Otherwise, the documentation for the general help information (main). Otherwise, the documentation for the
specific argument keyword is displayed, which usually corresponds to specific argument keyword is displayed, which usually corresponds to
a command name (but not necessarily). All documentation is written in a COMMAND name (but not necessarily). All documentation is written in
GitHub Flavored Markdown and will displayed as a web page if `pandoc` GitHub Flavored Markdown and will displayed as a web page if `pandoc`
and `$HELP_BROWSER` are detected, otherwise, just the Markdown is sent and `$HELP_BROWSER` are detected, otherwise, just the Markdown is sent
to `$PAGER` (default: more). to `$PAGER` (default: more).
Also see `readme` and `usage` commands. Also see `readme` and `usage` commands.
### The `json` Command ## Convert to JSON String
Converts input into JSON string using `jq` containing only escaped
(`
`) line returns.
### Generate `README.md` File
``` ```
command readme > README.md cmd json STRING
cmd json <<< STRING
cmd json < FILE
cmd json < <(COMMAND)
```
Converts input into JSON string using `jq` (if found) containing only
escaped (`\n`) line returns.
## Generate `README.md` File
```
cmd readme > README.md
``` ```
The `readme` command will output the embedded help documentation in raw The `readme` command will output the embedded help documentation in raw
GitHub Flavored Markdown suitable for use as a `README.md` file on GitHub Flavored Markdown suitable for use as a `README.md` file on
GitHub or similar hosting service. GitHub or similar hosting service.
### The `usage` Command ## The `usage` Command
Displays a summary of usage. Displays a summary of usage.
---- ----
*Autogenerated Sun Aug 15 04:56:38 PM EDT 2021* *Autogenerated Mon Aug 23 10:09:44 PM EDT 2021*

160
cmd
View File

@ -8,12 +8,13 @@ set -e
: "${PAGER:=more}" : "${PAGER:=more}"
: "${EDITOR:=vi}" : "${EDITOR:=vi}"
: "${HELP_BROWSER:=}" : "${HELP_BROWSER:=}"
: "${EXE:="${0##*/}"}"
: "${XDG_CONFIG_HOME:="$HOME/.config"}"
EXE="${0##*/}" declare -A HELP
declare -A CONFIG
declare -A help # associative arrays *require* declaration HELP[main]='
help[main]='
# Bash Template Command # Bash Template Command
*This `README.md` is autogenerated.* *This `README.md` is autogenerated.*
@ -25,7 +26,7 @@ create a new Bash command with a command something like this:
gh repo create rwxrob/mycmd -p rwxrob/template-bash-command gh repo create rwxrob/mycmd -p rwxrob/template-bash-command
``` ```
This `command` inside can then be renamed and finished. This `cmd` inside can then be renamed and finished.
Obviously, not all of this is needed for many Bash scripts, but anything Obviously, not all of this is needed for many Bash scripts, but anything
with more than two subcommands will benefit from the builtin tab with more than two subcommands will benefit from the builtin tab
@ -48,6 +49,7 @@ Required:
Optional: Optional:
* `pandoc` - for rich help docs * `pandoc` - for rich help docs
* `jq` - for `json` and anything that uses it
## Justification ## Justification
@ -64,7 +66,7 @@ more powerful, safer, flexible, and performant than POSIX shell or Zsh.
* Write GitHub Flavored Markdown only * Write GitHub Flavored Markdown only
* Use present tense ("outputs" over "will output") * Use present tense ("outputs" over "will output")
* Prefer "output" and "display" over ~~print~~ * Prefer term "output" and "display" over ~~print~~
* Follow the [naming conventions](#naming-conventions) * Follow the [naming conventions](#naming-conventions)
* Use the official bash path: `#!/bin/bash` * Use the official bash path: `#!/bin/bash`
* Use of `#!/usr/bin/bash` is outdated * Use of `#!/usr/bin/bash` is outdated
@ -79,31 +81,42 @@ more powerful, safer, flexible, and performant than POSIX shell or Zsh.
Copyright 2021 Rob Muhlestein <rob@rwx.gg> Copyright 2021 Rob Muhlestein <rob@rwx.gg>
Released under Apache-2.0 License Released under Apache-2.0 License
Please mention <https://rwxrob.tv> Please mention <https://rwxrob.tv>'
' HELP[foo]='Foos things.'
help[foo]='Foos.'
command_foo() { command_foo() {
_filter "$@" && return $? _filter "$@" && return $?
echo "would foo: $*" echo "would foo: $*"
} }
help[bar]='Bars.' HELP[bar]='
```
'"$EXE"' bar
```
Bar the things.'
command_bar() { command_bar() {
_buffer "$@" && return $? _buffer "$@" && return $?
echo "would bar: $*" echo "would bar: $*"
} }
help[json]=' HELP[json]='
Converts input into JSON string using `jq` containing only escaped ## Convert to JSON String
(`\n`) line returns.'
command_json() { ```
_jsonstr "$@" '"$EXE"' json STRING
} '"$EXE"' json <<< STRING
'"$EXE"' json < FILE
'"$EXE"' json < <(COMMAND)
```
Converts input into JSON string using `jq` (if found) containing only
escaped (`\\n`) line returns.'
command_json() { _jsonstr "$@"; }
command__hidden() { command__hidden() {
_filter "$@" && return $? _filter "$@" && return $?
@ -113,7 +126,7 @@ command__hidden() {
# ------------------ builtin commands and functions ------------------ # ------------------ builtin commands and functions ------------------
# (https://github.com/rwxrob/template-bash-command) # (https://github.com/rwxrob/template-bash-command)
help[usage]='Displays a summary of usage.' HELP[usage]='Displays a summary of usage.'
command_usage() { command_usage() {
local -a cmds local -a cmds
@ -125,17 +138,16 @@ command_usage() {
printf "usage: %s (%s)\n" "$EXE" "${cmds[*]}" printf "usage: %s (%s)\n" "$EXE" "${cmds[*]}"
} }
help[help]=' HELP[help]='
# Display Help Information
``` ```
help [<command>] '"$EXE"' help [COMMAND]
``` ```
Displays specific help information. If no argument is passed displays Displays specific help information. If no argument is passed displays
general help information (main). Otherwise, the documentation for the general help information (main). Otherwise, the documentation for the
specific argument keyword is displayed, which usually corresponds to specific argument keyword is displayed, which usually corresponds to
a command name (but not necessarily). All documentation is written in a COMMAND name (but not necessarily). All documentation is written in
GitHub Flavored Markdown and will displayed as a web page if `pandoc` GitHub Flavored Markdown and will displayed as a web page if `pandoc`
and `$HELP_BROWSER` are detected, otherwise, just the Markdown is sent and `$HELP_BROWSER` are detected, otherwise, just the Markdown is sent
to `$PAGER` (default: more). to `$PAGER` (default: more).
@ -147,50 +159,97 @@ command_help() {
local name="${1:-main}" title body local name="${1:-main}" title body
title=$(_help_title "$name") || true title=$(_help_title "$name") || true
if [[ -z "$title" ]]; then if [[ -z "$title" ]]; then
body="${help[$name]}" body="${HELP[$name]}"
title="$EXE $name" title="$EXE $name"
[[ $name = main ]] && title="$EXE" [[ $name = main ]] && title="$EXE"
else else
body="${help[$name]}" body="${HELP[$name]}"
body=${body#*$title} body=${body#*$title}
fi fi
local file="/tmp/help-$EXE-$name.html" local file="/tmp/help-$EXE-$name.html"
if _have pandoc ; then if _have pandoc ; then
if _have "$HELP_BROWSER" && [[ -t 1 ]] ;then if _have "$HELP_BROWSER" && [[ -t 1 ]] ;then
pandoc -s --metadata title="$title" \ pandoc -f gfm -s --metadata title="$title" \
-o "$file" <<< "$body" -o "$file" <<< "$body"
[[ -z "$2" ]] && cd /tmp && exec "$HELP_BROWSER" "$file" [[ -z "$2" ]] && cd /tmp && exec "$HELP_BROWSER" "$file"
return 0 return 0
fi fi
pandoc -s --metadata title="$title" \ pandoc -f gfm -s --metadata title="$title" \
-t plain <<< "$body" | "$PAGER" -t plain <<< "$body" | "$PAGER"
return 0 return 0
fi fi
echo -e "$title\n\n$body" | "$PAGER" echo -e "$title\n\n$body" | "$PAGER"
} }
help[readme]=' HELP[readme]='
# Generate `README.md` File ## Generate `README.md` File
``` ```
command readme > README.md '"$EXE"' readme > README.md
``` ```
The `readme` command will output the embedded help documentation in raw The `readme` command will output the embedded help documentation in raw
GitHub Flavored Markdown suitable for use as a `README.md` file on GitHub Flavored Markdown suitable for use as a `README.md` file on
GitHub or similar hosting service. ' GitHub or similar hosting service.'
command_readme() { command_readme() {
_trim "${help[main]}" _trim "${HELP[main]}"
echo
while IFS= read -r name; do while IFS= read -r name; do
[[ $name = main ]] && continue [[ $name = main ]] && continue
body=$(_trim "${help[$name]}") body=$(_trim "${HELP[$name]}")
[[ $body =~ ^\# ]] || body="# The \`$name\` Command\n\n$body" [[ $body =~ ^\# ]] || body="## The \`$name\` Command"$'\n\n'$body
printf "##%s\n\n" "$body" printf "%s\n\n" "$body"
done < <(printf "%s\n" "${!help[@]}" | LC_COLLATE=C sort) done < <(printf "%s\n" "${!HELP[@]}" | LC_COLLATE=C sort)
echo -e "----\n\n*Autogenerated $(date)*\n" echo -e "----\n\n*Autogenerated $(date)*\n"
} }
HELP[config]='
```
'"$EXE"' config
'"$EXE"' config KEY
'"$EXE"' config KEY VALUE
```
The `config` command is for reading, writing, and displaying standard
open desktop configurations properties.
### Arguments
With no arguments outputs all the currently cached configuration
settings.
With a single KEY argument fetches the value for that key and outputs
it.
With more than one argument the remaining arguments after the KEY will
be combined into the VALUE and written to the `config` file in the
standard configuration home location (Search for `XDG_CONFIG_HOME` for
more information).
### Configuration `config` File Format
The file (which is always named `config`) uses the simplest possible
format to facilitate standard UNIX parsing and filtering with any number
of existing tools (and no `jq` dependency).
* One KEY=VALUE per line
* KEYs may be anything but the equal sign (`=`)
* VALUEs may be anything but line returns must be escaped
Note that this is *not* the same as Java properties and other similar
format. It is designed for ultimate simplicity, efficiency, and
portability.'
command_config() {
case $# in
0) _dump_config ;;
1) printf "${CONFIG[$1]}" ;;
*) _set_config "$@" ;;
esac
}
_help_title() { _help_title() {
_filter "$@" && return $?; _filter "$@" && return $?;
local name="$1" local name="$1"
@ -198,7 +257,34 @@ _help_title() {
[[ $line =~ ^[:space]*$ ]] && continue [[ $line =~ ^[:space]*$ ]] && continue
[[ $line =~ ^#\ (.+) ]] && echo "${BASH_REMATCH[1]}" && return 0 [[ $line =~ ^#\ (.+) ]] && echo "${BASH_REMATCH[1]}" && return 0
return 1 return 1
done <<< "${help[$name]}" done <<< "${HELP[$name]}"
}
_set_config() {
local key="$1"; shift; local val="$*"
val="${val//$'\n'/\\n}"
CONFIG["$key"]="$val"
_write_config
}
_read_config() {
local path="$XDG_CONFIG_HOME/$EXE/config"
while IFS= read -r line; do
[[ $line =~ ^([^=]+)=(.+)$ ]] || continue
CONFIG["${BASH_REMATCH[1]}"]="${BASH_REMATCH[2]}"
done < "$path"
}
_write_config() {
local path="$XDG_CONFIG_HOME/$EXE/config"
mkdir -p "${path%/config}"
_dump_config > "$path"
}
_dump_config() {
paste -d=\
<(printf "%s\n" "${!CONFIG[@]}") \
<(printf "%s\n" "${CONFIG[@]}")
} }
_trim() { _trim() {
@ -250,6 +336,8 @@ for c in "${COMMANDS[@]}"; do
fi fi
done done
_read_config
if [[ -n "$1" ]]; then if [[ -n "$1" ]]; then
declare cmd="$1"; shift declare cmd="$1"; shift
for c in "${COMMANDS[@]}"; do for c in "${COMMANDS[@]}"; do