Compare commits

...

6 Commits

Author SHA1 Message Date
Rob Muhlestein d51e7f3e87 deprecate 2024-11-23 00:15:21 -05:00
rwxrob 6b13675289
Add several updates 2022-01-27 16:17:09 -05:00
rwxrob 815089d968
Fix header titles 2021-12-25 12:15:54 -05:00
rwxrob 1806be55e7
Add Security disclaimer 2021-12-18 11:13:23 -05:00
rwxrob 32593202c6
Add basic color support 2021-12-16 00:22:08 -05:00
rwxrob b77c674962
Fix false return values for config (closes #8) 2021-12-15 23:19:22 -05:00
2 changed files with 122 additions and 69 deletions

View File

@ -1,5 +1,11 @@
# Bash Template Command
*I no longer use this using [Bonzai][] instead. But it does have some good bash tricks to keep around including self-completion.*
[Bonzai]: <https://github.com/rwxrob/bonzai>
----
*This `README.md` is autogenerated.*
This is a GitHub template repo that will be copied instead of forked to
@ -145,6 +151,12 @@ more powerful, safer, flexible, and performant than POSIX shell or Zsh.
[`shellcheck`]: <https://www.shellcheck.net>
## Security
This script is expected to be installed for a specific user and only
ever run by that user. No additional security vetting for running as an
untrusted user has been done.
## Legal
Copyright 2021 Rob Muhlestein <rob@rwx.gg>
@ -266,5 +278,5 @@ Displays a summary of usage.
----
*Autogenerated Wed Sep 8 10:06:20 AM EDT 2021*
*Autogenerated Sat Dec 18 11:13:17 AM EST 2021*

177
cmd
View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
# shellcheck disable=SC2016
set -e
# export PATH="/bin:/usr/bin:/usr/local/bin" # safer, if you can
@ -13,6 +13,16 @@ set -e
declare -A HELP
declare -A CONF
# declare black=$'\e[30m'
# declare red=$'\e[31m'
# declare green=$'\e[32m'
# declare yellow=$'\e[33m'
# declare blue=$'\e[34m'
# declare magenta=$'\e[35m'
# declare cyan=$'\e[36m'
# declare white=$'\e[37m'
# declare reset=$'\e[0m'
_initialize() {
: # put initialization code here
}
@ -172,6 +182,12 @@ more powerful, safer, flexible, and performant than POSIX shell or Zsh.
[`shellcheck`]: <https://www.shellcheck.net>
## Security
This script is expected to be installed for a specific user and only
ever run by that user. No additional security vetting for running as an
untrusted user has been done.
## Legal
Copyright 2021 Rob Muhlestein <rob@rwx.gg>
@ -208,9 +224,16 @@ x.some.config.setting() {
## Everything from here to the end of file can be snipped and updated
## with latest from https://github.com/rwxrob/template-bash-command.
# -------------------------- utility command -------------------------
# ------------------------------- usage ------------------------------
HELP[usage]='Displays a summary of usage.'
HELP[usage]='
```
'"$EXE"' usage
```
Display all possible commands. Note that this is usually easier by
simply using tab completion instead.'
x.usage() {
local -a cmds
@ -222,7 +245,7 @@ x.usage() {
printf "usage: %s (%s)\n" "$EXE" "${cmds[*]}"
}
# --------------------------- help command ---------------------------
# ------------------------------- help -------------------------------
HELP[help]='
@ -242,17 +265,19 @@ Also see `readme` and `usage` commands.
'
x.help() {
local name="${1:-main}" title body
local name="${1:-main}" title body file
title=$(_help_title "$name") || true
if [[ -z "$title" ]]; then
body="${HELP[$name]}"
title="$EXE $name"
[[ $name = main ]] && title="$EXE"
[[ $name == main ]] && title="$EXE"
fi
if [[ $name == main ]]; then
body=$(x.readme)
body=${body#*$title}
else
body="${HELP[$name]}"
body=${body#*$title}
fi
local file="/tmp/help-$EXE-$name.html"
file="/tmp/help-$EXE-$name.html"
if _have pandoc ; then
if _have "$HELP_BROWSER" && [[ -t 1 ]] ;then
pandoc -f gfm -s --metadata title="$title" \
@ -277,7 +302,7 @@ _help_title() {
done <<< "${HELP[$name]}"
}
# -------------------------- readme command --------------------------
# ------------------------------ readme ------------------------------
HELP[readme]='
## Generate `README.md` File
@ -302,44 +327,46 @@ x.readme() {
echo -e "----\n\n*Autogenerated $(date)*\n"
}
# x.json() { _jsonstr "$@"; }
# x.urlencode() { _urlencode "$@"; }
# -------------------------- config command --------------------------
# ------------------------------ config ------------------------------
HELP[config]='
```
'"$EXE"' config
'"$EXE"' config KEY
'"$EXE"' config KEY VALUE
'"$EXE"' config KEY ""
'"$EXE"' config keys
'"$EXE"' config val[ues]
'"$EXE"' config dir[ectory]
'"$EXE"' config path [file]
'"$EXE"' config edit [file]
'"$EXE"' config del[ete]
'"$EXE"' config.set KEY VALUE
'"$EXE"' config.set KEY ""
'"$EXE"' config.keys
'"$EXE"' config.values
'"$EXE"' config.directory
'"$EXE"' config.path [file]
'"$EXE"' config.edit [file]
'"$EXE"' config.delete
'"$EXE"' config.read
'"$EXE"' config.write
'"$EXE"' config.dump
```
The `config` command is for reading, writing, and displaying standard
open desktop configuration properties. Pass an empty string to delete
a property.
open desktop configuration properties.
### Arguments
With no arguments outputs all the currently cached configuration
settings.
With no arguments calls `dump` and outputs all the currently cached
configuration settings.
With a single KEY argument fetches the value for that key and outputs
it unless it is one of the following special (reserved) key names:
* `dir*` full path to config directory
* `path` full path to specific config file (default: `values`)
* `edit` opens config file in editor (default: `editor` or `$EDITOR)
* `keys` output the configuration keys, one per line
* `val*` output the configuration values, one per line
* `del*` if key argument then delete a specific key, otherwise prompt
* `directory` full path to config directory
* `path` full path to specific config file (default: `values`)
* `edit` opens config file in editor (default: `editor` or `$EDITOR)
* `keys` output the configuration keys, one per line
* `values` output the configuration values, one per line
* `delete` if key argument then delete a specific key, otherwise prompt
* `read` reads the configuration file into CONF associative array
* `write` write the CONF associative array to the configuration file
* `dump` write the flattened CONF associative array to standard output
With more than one argument the remaining arguments after the KEY will
be combined into the VALUE and written to a `values` file in the
@ -370,74 +397,69 @@ existing tools (and no `jq` dependency).
* 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.'
Note that, although similar, this is *not* the same as Java properties
and other similar format. It is designed for ultimate simplicity,
efficiency, and portability.'
x.config() {
case $1 in
dir*) shift; _config_dir "$@"; return $? ;;
path) shift; _config_path "$@"; return $? ;;
edit) shift; _config_edit "$@"; return $? ;;
del*) shift; _config_del "$@"; return $? ;;
keys) shift; _config_keys "$@"; return $? ;;
val*) shift; _config_vals "$@"; return $? ;;
esac
case $# in
0) _config_dump ;;
1) _config_get "$@" ;;
*) _config_set "$@" ;;
0) x.config.dump ;;
1) x.config.get "$@" ;;
*) x.config.set "$@" ;;
esac
}
_config_edit() {
x.config.edit() {
: "${CONF[editor]:="${EDITOR:=vi}"}"
exec "${CONF[editor]}" "$(_config_path "${1:-values}")"
exec "${CONF[editor]}" "$(x.config.path "${1:-values}")"
}
_config_del() {
x.config.delete() {
if [[ -z "$1" ]];then
select key in "${!CONF[@]}"; do
_config_del "$key"
x.config.delete "$key"
return $?
done
fi
_config_set "$1" ''
x.config.set "$1" ''
}
_config_keys() { printf "%s\n" "${!CONF[@]}"; }
x.config.keys() { printf "%s\n" "${!CONF[@]}"; }
_config_vals() { printf "%s\n" "${CONF[@]}"; }
x.config.values() { printf "%s\n" "${CONF[@]}"; }
_config_dir() {
x.config.dir() {
local dir="$HOME/.config/$EXE"
[[ -n "$XDG_CONFIG_HOME" ]] && dir="$XDG_CONFIG_HOME/$EXE"
[[ -n "$CONFIG_DIR" ]] && dir="$CONFIG_DIR"
[[ -n "$1" ]] && echo "$dir/$1" && return 0
printf "%s" "$dir"
[[ -t 1 ]] && echo
return 0
}
_config_path() {
x.config.path() {
local file=${1:-values}
printf "%s/%s" "$(_config_dir)" "$file"
printf "%s/%s" "$(x.config.dir)" "$file"
[[ -t 1 ]] && echo
return 0
}
_config_set() {
x.config.set() {
local key="$1"; shift; local val="$*"
val="${val//$'\n'/\\n}"
CONF["$key"]="$val"
_config_write
x.config.write
}
_config_get() {
printf "${CONF[$1]}"
x.config.get() {
printf "%s" "${CONF[$1]}"
[[ -t 1 ]] && echo
return 0
}
_config_read() {
local values="$(_config_path)"
x.config.read() {
local values="$(x.config.path)"
[[ -r "$values" ]] || return 0
while IFS= read -r line; do
[[ $line =~ ^([^=]+)=(.+)$ ]] || continue
@ -445,13 +467,13 @@ _config_read() {
done < "$values"
}
_config_write() {
local dir="$(_config_dir)"
x.config.write() {
local dir="$(x.config.dir)"
mkdir -p "$dir"
_config_dump > "$dir/values"
x.config.dump > "$dir/values"
}
_config_dump() {
x.config.dump() {
(( ${#CONF[@]} == 0 )) && return 0
paste -d=\
<(printf "%s\n" "${!CONF[@]}") \
@ -493,7 +515,7 @@ _reduce() {
_newest() {
IFS=$'\n'
local -a f=($(ls -1 --color=never -trd ${1:-.}/* 2>/dev/null))
mapfile -t f < <(ls -1 --color=never -trd "${1:-.}"/* 2>/dev/null)
[[ ${#f} > 0 ]] && echo "${f[-1]}"
}
@ -502,6 +524,8 @@ _trim() {
echo -e "${it%"${it##*[![:space:]]}"}"
}
_join() { local IFS="$1"; shift; echo "$*"; }
_have(){ type "$1" &>/dev/null; }
_checkdep() {
@ -522,10 +546,27 @@ _buffer() {
"${FUNCNAME[1]}" "$(</dev/stdin)"
}
_prompt() {
local key="$1" def="$2" regx="$3" value first=yes
shift 3
local text="${*:-Enter value for %s [%s]: }"
[[ -z "$key" ]] && echo "Missing prompt key" >&2 && return 1
[[ -z "$regx" ]] && echo "Missing valid regx" >&2 && return 1
while [[ ! $value =~ $regx ]];do
printf "$text" "$key" "$def" >&2
IFS= read -r value
[[ -z "$value" ]] && value="$def"
[[ $value =~ ^\ +$ ]] && value=""
[[ -n "$first" ]] && unset first && continue
echo "Must match /$regx/" >&2
done
_trim "$value"
}
# --------------------- completion and delegation --------------------
# `complete -C foo foo` > `source <(foo bloated_completion)`
_config_read
x.config.read
_have _initialize && _initialize "$@"
while IFS= read -r line; do