Composure module by Erichs: light-hearted functions for intuitive shell programming
(in /home/bsgt/stablecaps_bashrc/modules/composure.sh)
Function Index
01 - _bootstrap_composure
02 - _get_composure_dir
03 - _get_author_name
04 - _composure_keywords
05 - _letterpress
06 - _determine_printf_cmd
07 - _longest_function_name_length
08 - _temp_filename_for
09 - _prompt
10 - _add_composure_file
11 - _transcribe
12 - _typeset_functions
13 - _typeset_functions_about
14 - _shell
15 - _generate_metadata_functions
16 - _list_composure_files
17 - _load_composed_functions
18 - _strip_trailing_whitespace
19 - _strip_semicolons
20 - cite
21 - draft
22 - glossary
23 - metafor
24 - reference(){
25 - revise
26 - write
>> _bootstrap_composure():
function _bootstrap_composure() {
_generate_metadata_functions
_load_composed_functions
_determine_printf_cmd
}
>> _get_composure_dir():
function _get_composure_dir() {
if [ -n "$XDG_DATA_HOME" ]; then
echo "$XDG_DATA_HOME/composure"
else
echo "$HOME/.local/composure"
fi
}
>> _get_author_name():
function _get_author_name() {
typeset name localname
localname="$(git --git-dir "$(_get_composure_dir)/.git" config --get user.name)"
for name in "$GIT_AUTHOR_NAME" "$localname"; do
if [ -n "$name" ]; then
echo "$name"
break
fi
done
}
Function Calls:
└─ _get_author_name
└─ _get_composure_dir
>> _composure_keywords():
function _composure_keywords() {
echo "about author example group param version"
}
>> _letterpress():
function _letterpress() {
typeset rightcol="$1" leftcol="${2:- }" leftwidth="${3:-20}"
if [ -z "$rightcol" ]; then
return
fi
$_printf_cmd "%-*s%s\n" "$leftwidth" "$leftcol" "$rightcol"
}
>> _determine_printf_cmd():
function _determine_printf_cmd() {
if [ -z "$_printf_cmd" ]; then
_printf_cmd=printf
[ -x "$(which gprintf 2>/dev/null)" ] && _printf_cmd=gprintf
export _printf_cmd
fi
}
>> _longest_function_name_length():
function _longest_function_name_length() {
echo "$1" | awk 'BEGIN{ maxlength=0 }
{
for(i=1;i<=NF;i++)
if (length($i)>maxlength)
{
maxlength=length($i)
}
}
END{ print maxlength}'
}
>> _temp_filename_for():
function _temp_filename_for() {
typeset file=$(mktemp "/tmp/$1.XXXX")
command rm "$file" 2>/dev/null # ensure file is unlinked prior to use
echo "$file"
}
>> _prompt():
function _prompt() {
typeset prompt="$1"
typeset result
case "$(_shell)" in
bash)
read -r -e -p "$prompt" result;;
*)
echo -n "$prompt" >&2; read -r result;;
esac
echo "$result"
}
Function Calls:
└─ _prompt
└─ _shell
>> _add_composure_file():
function _add_composure_file() {
typeset func="$1"
typeset file="$2"
typeset operation="$3"
typeset comment="${4:-}"
typeset composure_dir=$(_get_composure_dir)
(
if ! cd "$composure_dir"; then
printf "%s\n" "Oops! Can't find $composure_dir!"
return
fi
if git rev-parse 2>/dev/null; then
if [ ! -f "$file" ]; then
printf "%s\n" "Oops! Couldn't find $file to version it for you..."
return
fi
cp "$file" "$composure_dir/$func.inc"
git add --all .
if [ -z "$comment" ]; then
comment="$(_prompt 'Git Comment: ')"
fi
git commit -m "$operation $func: $comment"
fi
)
}
Function Calls:
└─ _add_composure_file
├─ _get_composure_dir
└─ _prompt
└─ _shell
>> _transcribe():
function _transcribe() {
typeset func="$1"
typeset file="$2"
typeset operation="$3"
typeset comment="${4:-}"
typeset composure_dir=$(_get_composure_dir)
if git --version >/dev/null 2>&1; then
if [ -d "$composure_dir" ]; then
_add_composure_file "$func" "$file" "$operation" "$comment"
else
if [ "$USE_COMPOSURE_REPO" = "0" ]; then
return # if you say so...
fi
printf "%s\n" "I see you don't have a $composure_dir repo..."
typeset input=''
typeset valid=0
while [ $valid != 1 ]; do
printf "\n%s" 'would you like to create one? y/n: '
read -r input
case $input in
y|yes|Y|Yes|YES)
(
echo 'creating git repository for your functions...'
mkdir -p "$composure_dir" || return 1
cd "$composure_dir" || return 1
git init
echo "composure stores your function definitions here" > README.txt
git add README.txt
git commit -m 'initial commit'
)
_transcribe "$func" "$file" "$operation" "$comment"
valid=1
;;
n|no|N|No|NO)
printf "%s\n" "ok. add 'export USE_COMPOSURE_REPO=0' to your startup script to disable this message."
valid=1
;;
*)
printf "%s\n" "sorry, didn't get that..."
;;
esac
done
fi
fi
}
Function Calls:
└─ _transcribe
├─ _get_composure_dir
└─ _add_composure_file
├─ _get_composure_dir
└─ _prompt
>> _typeset_functions():
function _typeset_functions() {
case "$(_shell)" in
sh|bash)
typeset -F | awk '{print $3}'
;;
*)
typeset +f | sed 's/().*$//'
;;
esac
}
Function Calls:
└─ _typeset_functions
└─ _shell
>> _typeset_functions_about():
function _typeset_functions_about() {
typeset f
for f in $(_typeset_functions); do
typeset -f -- "$f" | grep -qE "^about[[:space:]]|[[:space:]]about[[:space:]]" && echo -- "$f"
done
}
Function Calls:
└─ _typeset_functions_about
└─ _typeset_functions
└─ _shell
>> _shell():
function _shell() {
typeset this=$(ps -o comm -p $$ | tail -1 | awk '{print $NF}' | sed 's/^-*//')
echo "${this##*/}" # e.g. /bin/bash => bash
}
>> _generate_metadata_functions():
function _generate_metadata_functions() {
typeset f
for f in $(_composure_keywords)
do
eval "$f() { :; }"
done
}
Function Calls:
└─ _generate_metadata_functions
└─ _composure_keywords
>> _list_composure_files():
function _list_composure_files() {
typeset composure_dir="$(_get_composure_dir)"
[ -d "$composure_dir" ] && find "$composure_dir" -maxdepth 1 -name '*.inc'
}
Function Calls:
└─ _list_composure_files
└─ _get_composure_dir
>> _load_composed_functions():
function _load_composed_functions() {
if [ "$LOAD_COMPOSED_FUNCTIONS" = "0" ]; then
return # if you say so...
fi
typeset inc
for inc in $(_list_composure_files); do
. "$inc"
done
}
Function Calls:
└─ _load_composed_functions
└─ _list_composure_files
└─ _get_composure_dir
>> _strip_trailing_whitespace():
function _strip_trailing_whitespace() {
sed -e 's/ \+$//'
}
>> _strip_semicolons():
function _strip_semicolons() {
sed -e 's/;$//'
}
>> cite():
about: creates one or more meta keywords for use in your functions
param: one or more keywords
example:
$ cite url username
example:
$ url http://somewhere.com
example:
$ username alice
group: composure
function cite() {
if [ -z "$1" ]; then
printf '%s\n' 'missing parameter(s)'
reference cite
return
fi
typeset keyword
for keyword in "$@"; do
eval "$keyword() { :; }"
done
}
>> draft():
about: wraps command from history into a new function, default is last command
param: 1: name to give function
param: 2: optional history line number
example:
$ ls
example:
$ draft list
example:
$ draft newfunc 1120 # wraps command at history line 1120 in newfunc()
group: composure
about
param
example`
group
function draft() {
typeset func=$1
typeset num=$2
if [ -z "$func" ]; then
printf '%s\n' 'missing parameter(s)'
reference draft
return
fi
if type -a "$func" 2>/dev/null | grep -q 'is.*alias'; then
printf '%s\n' "sorry, $(type -a "$func"). please choose another name."
return
fi
typeset cmd
if [ -z "$num" ]; then
typeset lines=$(fc -ln -1 | grep -q draft && echo 2 || echo 1)
cmd=$(fc -ln -$lines | head -1 | sed 's/^[[:blank:]]*//')
else
cmd=$(eval "history | grep '^[[:blank:]]*$num' | head -1" | sed 's/^[[:blank:][:digit:]]*//')
fi
eval "function $func {
author '$(_get_author_name)'
$cmd;
}"
typeset file=$(_temp_filename_for draft)
typeset -f "$func" | _strip_trailing_whitespace | _strip_semicolons > "$file"
_transcribe "$func" "$file" Draft "Initial draft"
command rm "$file" 2>/dev/null
revise "$func"
}
Function Calls:
└─ draft
├─ _get_author_name
| └─ _get_composure_dir
├─ _temp_filename_for
├─ _transcribe
| ├─ _get_composure_dir
| └─ _add_composure_file
├─ _strip_trailing_whitespace
├─ _strip_semicolons
└─ revise
├─ _get_composure_dir
├─ _temp_filename_for
└─ _transcribe
>> glossary():
about: displays help summary for all functions, or summary for a group of functions
param: 1: optional, group name
example:
$ glossary
example:
$ glossary misc
group: composure
function glossary() {
typeset targetgroup=${1:-}
typeset functionlist="$(_typeset_functions_about)"
typeset maxwidth=$(_longest_function_name_length "$functionlist" | awk '{print $1 + 5}')
for func in $(echo $functionlist); do
if [ "X${targetgroup}X" != "XX" ]; then
typeset group="$(typeset -f -- $func | metafor group)"
if [ "$group" != "$targetgroup" ]; then
continue # skip non-matching groups, if specified
fi
fi
typeset about="$(typeset -f -- $func | metafor about)"
typeset aboutline=
echo "$about" | fmt | while read -r aboutline; do
_letterpress "$aboutline" "$func" "$maxwidth"
func=" " # only display function name once
done
done
}
Function Calls:
└─ glossary
├─ _letterpress
├─ _longest_function_name_length
├─ _typeset_functions_about
| └─ _typeset_functions
└─ metafor
└─ glossary
>> metafor():
about: prints function metadata associated with keyword
param: 1: meta keyword
example:
typeset -f glossary | metafor example
group: composure
function metafor() {
typeset keyword=$1
if [ -z "$keyword" ]; then
printf '%s\n' 'missing parameter(s)'
reference metafor
return
fi
sed -n "/$keyword / s/['\";]*\$//;s/^[ ]*$keyword ['\"]*\([^([].*\)*\$/\1/p"
}
Function Calls:
└─ metafor
└─ glossary
├─ _letterpress
├─ _longest_function_name_length
├─ _typeset_functions_about
└─ metafor
>> reference(){():
about: displays apidoc help for a specific function
param: 1: function name
example:
$ reference revise
group: composure
function reference(){
typeset func=$1
if [ -z "$func" ]; then
printf '%s\n' 'missing parameter(s)'
reference reference
return
fi
typeset line
typeset about="$(typeset -f "$func" | metafor about)"
_letterpress "$about" "$func"
typeset author="$(typeset -f $func | metafor author)"
if [ -n "$author" ]; then
_letterpress "$author" 'author:'
fi
typeset version="$(typeset -f $func | metafor version)"
if [ -n "$version" ]; then
_letterpress "$version" 'version:'
fi
if [ -n "$(typeset -f $func | metafor param)" ]; then
printf "parameters:\n"
typeset -f $func | metafor param | while read -r line
do
_letterpress "$line"
done
fi
if [ -n "$(typeset -f $func | metafor example)" ]; then
printf "examples:\n"
typeset -f $func | metafor example | while read -r line
do
_letterpress "$line"
done
fi
}
Function Calls:
└─ reference(){
├─ _letterpress
└─ metafor
└─ glossary
>> revise():
about: loads function into editor for revision
param:
-e: revise version stored in ENV param: 1: name of function
example:
$ revise myfunction
example:
$ revise -e myfunction
example:
save a zero-length file to abort revision
group: composure
function revise() {
typeset source='git'
if [ "$1" = '-e' ]; then
source='env'
shift
fi
typeset func=$1
if [ -z "$func" ]; then
printf '%s\n' 'missing parameter(s)'
reference revise
return
fi
typeset composure_dir=$(_get_composure_dir)
typeset temp=$(_temp_filename_for revise)
if [ "$source" = 'env' ] || [ ! -f "$composure_dir/$func.inc" ]; then
typeset -f $func > $temp
else
cat "$composure_dir/$func.inc" > "$temp"
fi
if [ -z "$EDITOR" ]
then
typeset EDITOR=vi
fi
$EDITOR "$temp"
if [ -s "$temp" ]; then
typeset edit='N'
. "$temp" || edit='Y'
while [ $edit = 'Y' ]; do
echo -n "Re-edit? Y/N: "
read -r edit
case $edit in
y|yes|Y|Yes|YES)
edit='Y'
$EDITOR "$temp"
. "$temp" && edit='N';;
*)
edit='N';;
esac
done
_transcribe "$func" "$temp" Revise
else
printf '%s\n' 'zero-length file, revision aborted!'
fi
command rm "$temp"
}
Function Calls:
└─ revise
├─ _get_composure_dir
├─ _temp_filename_for
└─ _transcribe
├─ _get_composure_dir
└─ _add_composure_file
>> write():
about: writes one or more composed function definitions to stdout
param: one or more function names
example:
$ write finddown foo
example:
$ write finddown
group: composure
function write() {
if [ -z "$1" ]; then
printf '%s\n' 'missing parameter(s)'
reference write
return
fi
echo "#!/usr/bin/env ${SHELL##*/}"
cat <<END
for f in $(_composure_keywords)
do
eval "\$f() { :; }"
done
unset f
END
typeset -f cite "$@"
cat <<END
main() {
echo "edit me to do something useful!"
exit 0
}
main \$*
END
}
_bootstrap_composure
: <<EOF
License: The MIT License
Copyright © 2012, 2016 Erich Smith
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
EOF
cite about-module
Function Calls:
└─ write
├─ _composure_keywords
└─ cite
Aliases
Alias Name | Code | Notes |
---|---|---|
cref | reference |