blob: 1bbf400dde4ce083c7baaac0dc68bd3d198c80cc [file] [log] [blame]
Travis Swicegood3e7c0fb2012-05-04 16:30:22 -05001# composure - by erichs
2# light-hearted shell functions for intuitive shell programming
Erich Smitha8fcf9f2012-04-27 15:07:04 -04003
Travis Swicegood3e7c0fb2012-05-04 16:30:22 -05004# install: source this script in your ~/.profile or ~/.${SHELL}rc script
Erich Smitha8fcf9f2012-04-27 15:07:04 -04005
6# latest source available at http://git.io/composure
Travis Swicegood3e7c0fb2012-05-04 16:30:22 -05007# known to work on bash, zsh, and ksh93
Erich Smitha8fcf9f2012-04-27 15:07:04 -04008
Travis Swicegood3e7c0fb2012-05-04 16:30:22 -05009# define default metadata keywords:
10about () { :; }
11group () { :; }
12param () { :; }
13author () { :; }
14example () { :; }
15
16cite ()
Erich Smitha8fcf9f2012-04-27 15:07:04 -040017{
Travis Swicegood3e7c0fb2012-05-04 16:30:22 -050018 about creates a new meta keyword for use in your functions
19 param 1: keyword
20 example $ cite url
21 example $ url http://somewhere.com
22 group composure
23
24 # this is the storage half of the 'metadata' system:
25 # we create dynamic metadata keywords with function wrappers around
26 # the NOP command, ':'
27
28 # anything following a keyword will get parsed as a positional
29 # parameter, but stay resident in the ENV. As opposed to shell
30 # comments, '#', which do not get parsed, thus are not available
31 # at runtime.
32
33 # a BIG caveat--your metadata must be roughly parsable: do not use
34 # contractions, and consider single or double quoting if it contains
35 # non-alphanumeric characters
36
37 typeset keyword
38 for keyword in $*; do
39 eval "function $keyword { :; }"
40 done
41}
42
43draft ()
44{
45 about wraps last command into a new function
46 param 1: name to give function
47 example $ ls
48 example $ draft list
49 example $ list
50 group composure
51
52 typeset func=$1
53 eval 'function ' $func ' { ' $(fc -ln -1) '; }'
54 typeset file=$(mktemp /tmp/draft.XXXX)
55 typeset -f $func > $file
56 transcribe $func $file draft
57 rm $file 2>/dev/null
58}
59
60glossary ()
61{
62 about displays help summary for all functions, or summary for a group of functions
63 param 1: optional, group name
64 example $ glossary
65 example $ glossary misc
66 group composure
67
68 typeset targetgroup=${1:-}
69
70 for func in $(listfunctions); do
71 typeset about="$(metafor $func about)"
72 if [ -n "$targetgroup" ]; then
73 typeset group="$(metafor $func group)"
74 if [ "$group" != "$targetgroup" ]; then
75 continue # skip non-matching groups, if specified
76 fi
77 fi
78 letterpress "$about" $func
79 done
80}
81
82letterpress ()
83{
84 typeset metadata=$1 leftcol=${2:- } rightcol
85
86 if [ -z "$metadata" ]; then
87 return
88 fi
89
90 OLD=$IFS; IFS=$'\n'
91 for rightcol in $metadata; do
92 printf "%-20s%s\n" $leftcol $rightcol
93 done
94 IFS=$OLD
95}
96
97listfunctions ()
98{
99 # unfortunately, there does not seem to be a easy, portable way to list just the
100 # names of the defined shell functions...
101
102 # here's a hack I modified from a StackOverflow post:
103 # we loop over the ps listing for the current process ($$), and print the last column (CMD)
104 # stripping any leading hyphens bash sometimes throws in there
105
106 typeset x ans
107 typeset this=$(for x in $(ps -p $$); do ans=$x; done; printf "%s\n" $ans | sed 's/^-*//')
108 case "$this" in
109 bash)
110 typeset -F | awk '{print $3}'
111 ;;
112 *)
113 # trim everything following '()' in ksh
114 typeset +f | sed 's/().*$//'
115 ;;
116 esac
117}
118
119metafor ()
120{
121 about prints function metadata associated with keyword
122 param 1: function name
123 param 2: meta keyword
124 example $ metafor glossary example
125 group composure
126 typeset func=$1 keyword=$2
127
128 # this sed-fu is the retrieval half of the 'metadata' system:
129 # first 'cat' the function definition,
130 # then 'grep' for the metadata keyword, and
131 # then parse and massage the matching line
132 typeset -f $func | sed -n "s/;$//;s/^[ ]*$keyword \([^([].*\)*$/\1/p"
133}
134
135reference ()
136{
137 about displays apidoc help for a specific function
138 param 1: function name
139 example $ reference revise
140 group composure
141
142 typeset func=$1
143
144 typeset about="$(metafor $func about)"
145 letterpress "$about" $func
146
147 typeset params="$(metafor $func param)"
148 if [ -n "$params" ]; then
149 printf "parameters:\n"
150 letterpress "$params"
151 fi
152
153 typeset examples="$(metafor $func example)"
154 if [ -n "$examples" ]; then
155 printf "examples:\n"
156 letterpress "$examples"
157 fi
158}
159
160revise ()
161{
162 about loads function into editor for revision
163 param 1: name of function
164 example $ revise myfunction
165 group composure
166
167 typeset func=$1
168 typeset temp=$(mktemp /tmp/revise.XXXX)
169
170 # populate tempfile...
171 if [ -f ~/.composure/$func.inc ]; then
172 # ...with contents of latest git revision...
173 cat ~/.composure/$func.inc >> $temp
174 else
175 # ...or from ENV if not previously versioned
176 typeset -f $func >> $temp
177 fi
178
Erich Smitha8fcf9f2012-04-27 15:07:04 -0400179 if [ -z "$EDITOR" ]
180 then
Travis Swicegood3e7c0fb2012-05-04 16:30:22 -0500181 typeset EDITOR=vi
Erich Smitha8fcf9f2012-04-27 15:07:04 -0400182 fi
183
Travis Swicegood3e7c0fb2012-05-04 16:30:22 -0500184 $EDITOR $temp
185 source $temp
Erich Smitha8fcf9f2012-04-27 15:07:04 -0400186
Travis Swicegood3e7c0fb2012-05-04 16:30:22 -0500187 transcribe $func $temp revise
188 rm $temp
Erich Smitha8fcf9f2012-04-27 15:07:04 -0400189}
190
Travis Swicegood3e7c0fb2012-05-04 16:30:22 -0500191transcribe ()
Erich Smitha8fcf9f2012-04-27 15:07:04 -0400192{
Travis Swicegood3e7c0fb2012-05-04 16:30:22 -0500193 typeset func=$1
194 typeset file=$2
195 typeset operation="$3"
Erich Smitha8fcf9f2012-04-27 15:07:04 -0400196
Travis Swicegood3e7c0fb2012-05-04 16:30:22 -0500197 if git --version >/dev/null 2>&1; then
198 if [ -d ~/.composure ]; then
199 (
200 cd ~/.composure
201 if git rev-parse 2>/dev/null; then
202 if [ ! -f $file ]; then
203 printf "%s\n" "Oops! Couldn't find $file to version it for you..."
204 return
205 fi
206 cp $file ~/.composure/$func.inc
207 git add --all .
208 git commit -m "$operation $func"
209 fi
210 )
211 else
212 if [ "$USE_COMPOSURE_REPO" = "0" ]; then
213 return # if you say so...
214 fi
215 printf "%s\n" "I see you don't have a ~/.composure repo..."
216 typeset input
217 typeset valid=0
218 while [ $valid != 1 ]; do
219 printf "\n%s" 'would you like to create one? y/n: '
220 read input
221 case $input in
222 y|yes|Y|Yes|YES)
223 (
224 echo 'creating git repository for your functions...'
225 mkdir ~/.composure
226 cd ~/.composure
227 git init
228 echo "composure stores your function definitions here" > README.txt
229 git add README.txt
230 git commit -m 'initial commit'
231 )
232 # if at first you don't succeed...
233 transcribe "$func" "$file" "$operation"
234 valid=1
235 ;;
236 n|no|N|No|NO)
237 printf "%s\n" "ok. add 'export USE_COMPOSURE_REPO=0' to your startup script to disable this message."
238 valid=1
239 ;;
240 *)
241 printf "%s\n" "sorry, didn't get that..."
242 ;;
243 esac
244 done
245 fi
Erich Smitha8fcf9f2012-04-27 15:07:04 -0400246 fi
Erich Smitha8fcf9f2012-04-27 15:07:04 -0400247}
248
Erich Smitha8fcf9f2012-04-27 15:07:04 -0400249: <<EOF
250License: The MIT License
251
252Copyright © 2012 Erich Smith
253
254Permission is hereby granted, free of charge, to any person obtaining a copy of this
255software and associated documentation files (the "Software"), to deal in the Software
256without restriction, including without limitation the rights to use, copy, modify,
257merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
258permit persons to whom the Software is furnished to do so, subject to the following
259conditions:
260
261The above copyright notice and this permission notice shall be included in all copies
262or substantial portions of the Software.
263
264THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
265INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
266PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
267HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
268CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
269OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
270EOF