22
33# runfile.sh · v0.0.3
44
5+ trap " " SIGTSTP
6+
57function version() {
68 head -n 3 < " $0 " | tail -1 | cut -c3-
79}
@@ -201,14 +203,27 @@ function cd-to-nearest-file() { local lower='' upper='' title=''
201203 done
202204}
203205
206+ function ordinal() {
207+ case " $1 " in
208+ * 1[0-9] | * [04-9]) echo " $1 " th ;;
209+ * 1) echo " $1 " st ;;
210+ * 2) echo " $1 " nd ;;
211+ * 3) echo " $1 " rd ;;
212+ esac
213+ }
214+
215+ function bold() {
216+ echo " $( tput bold ) $* $( tput sgr0 ) "
217+ }
218+
204219function wizard() {
205- local state=' action1' prev_states=() prev_runfiles=()
220+ local state=' action1' action= ' ' actionidx=0 cmdidx=0 prev_states=() prev_runfiles=()
206221
207222 if [[ -e ' Runfile' ]]
208223 then
209224 while TRUE
210225 do
211- read -rsn1 -p ' · Runfile already exists. Overwrite? [y|N] · '
226+ read -rsn1 -p " · Runfile already exists. $( bold ' Overwrite?' ) · [ $( bold ' y ' ) | $( bold ' N ' ) ] · "
212227 if [[ " $REPLY " == ' y' || " $REPLY " == ' Y' ]]
213228 then
214229 rm Runfile
@@ -223,139 +238,164 @@ function wizard() {
223238 done
224239 fi
225240
226- read -rsn1 -p " · At each of the following prompts, press ENTER to continue · "
227- echo
228-
229- read -rsn1 -p " · At each of the following prompts, type BACK to return to previous step · "
230- echo
241+ function record-step() {
242+ prev_states=( " ${state} " " ${prev_states[@]} " )
243+ prev_actions=( " ${action} " " ${prev_actions[@]} " )
244+ prev_actionidxs=( " ${actionidx} " " ${prev_actionidxs[@]} " )
245+ prev_cmdidxs=( " ${cmdidx} " " ${prev_cmdidxs[@]} " )
246+ if [[ -f ' Runfile' ]]
247+ then
248+ prev_runfiles=( " $( cat Runfile ) " " ${prev_runfiles[@]} " )
249+ else
250+ prev_runfiles=( " " " ${prev_runfiles[@]} " )
251+ fi
252+ }
253+
254+ function undo-step() {
255+ cat << -EOF > Runfile
256+ ${prev_runfiles[0]}
257+ EOF
258+ state=" ${prev_states[0]} "
259+ action=" ${prev_actions[0]} "
260+ actionidx=" ${prev_actionidxs[0]} "
261+ cmdidx=" ${prev_cmdidxs[0]} "
262+ prev_states=( " ${prev_states[@]: 1} " )
263+ prev_runfiles=( " ${prev_runfiles[@]: 1} " )
264+ prev_actions=( " ${prev_actions[@]: 1} " )
265+ prev_actionidxs=( " ${prev_actionidxs[@]: 1} " )
266+ prev_cmdidxs=( " ${prev_cmdidxs[@]: 1} " )
267+ }
231268
232269 while TRUE
233270 do
234271 if [[ -f ' Runfile' ]]
235272 then
236273 echo
237274 echo ' ./Runfile'
238- echo ' ---------'
239- cat Runfile
240- [[ " ${state} " == ' description' ]] && echo
241- echo ' ---------'
242- echo " ${prev_states[@]} "
275+ echo -n ' ┌────┴'
276+ printf " ─%.0s" $( seq $(( "$( awk '{ print length }' Runfile | sort - n | tail - 1 )" - 8 )) )
277+ echo ' ─┐'
278+ echo
279+ bold " $( sed " s/#.*$/$( tput sgr0 ) &$( tput bold ) /" Runfile ) "
280+ echo
281+ echo -n ' └─────'
282+ printf " ─%.0s" $( seq $(( "$( awk '{ print length }' Runfile | sort - n | tail - 1 )" - 8 )) )
283+ echo ' ─┘'
243284 echo
244285 fi
245286
246- if [[ " ${state} " == ' action1 ' || " ${state} " == ' action2 ' ]]
287+ if [[ " ${state} " == ' finish ' ]]
247288 then
248- if [[ " ${state} " == ' action1' ]]
289+ echo ' Your Runfile has been created successfully!'
290+ echo " Start using it by typing $( bold ' run' ) to review available commands."
291+ echo
292+ break
293+ elif [[ " ${state} " == ' action1' || " ${state} " == ' action2' ]]
294+ then
295+ if [[ -z " ${action} " ]]
249296 then
250- read -rp " · Enter first run action name, or type DONE ·" $' \n ' " ··· "
297+ read -rp " · Enter $( bold " $( ordinal " $(( actionidx + 1 )) " ) " ) action name… ·" $' \n ' " $( bold ' ·· ' ) "
251298 else
252- read -rp " · Enter another run action name, or type DONE ·" $' \n ' " ··· "
299+ read -rp " · Enter $( bold " $( ordinal " $(( actionidx + 1 )) " ) " ) action name… · [ $( bold ' leave blank ' ) to continue | $( bold ' UNDO ' ) to go back ] ·" $' \n ' " $( bold ' ·· ' ) "
253300 fi
254- if [[ " $REPLY " == ' BACK ' ]]
301+ if [[ " $REPLY " == ' UNDO ' ]]
255302 then
256303 if (( ${# prev_states[@]} )) && (( ${# prev_runfiles[@]} ))
257304 then
258- echo " ${prev_runfiles[0]} " > Runfile
259- state=" ${prev_states[0]} "
260- prev_states=( " ${prev_states[@]: 1} " )
261- prev_runfiles=( " ${prev_runfiles[@]: 1} " )
305+ undo-step
262306 fi
263- elif [[ " $REPLY " == ' DONE ' ]]
307+ elif [[ " $REPLY " == ' ' && -n " ${action} " ]]
264308 then
265- break
309+ state= " finish "
266310 elif ! [[ " $REPLY " =~ ^[[:alnum:]_-]+$ ]]
267311 then
268- echo " · Run command names should only have characters a-z A-Z 0-9 _ - and no spaces ·"
269- echo " · Please try again ·"
270- echo
312+ if [[ -n " $REPLY " ]]
313+ then
314+ echo " · Run command names should only have characters a-z A-Z 0-9 _ - and no spaces · "
315+ echo " · $( bold ' Please try again' ) · "
316+ echo
317+ fi
271318 else
272- prev_states=( " ${state} " " ${prev_states[@]} " )
273- if [[ -f ' Runfile' ]]
319+ record-step
320+
321+ if grep -q ' [^[:space:]]' Runfile & > /dev/null
274322 then
275- prev_runfiles=( " $( cat Runfile ) " " ${prev_runfiles[@]} " )
323+ echo -n " $REPLY : " >> Runfile
276324 else
277- prev_runfiles=( " " " ${prev_runfiles[@]} " )
325+ echo -n " $REPLY : " > Runfile
278326 fi
279- echo -n " $REPLY : " >> Runfile
327+
280328 state=' description'
329+ action=" $REPLY "
330+ (( actionidx++ ))
331+ cmdidx=0
281332 fi
282333 elif [[ " ${state} " == ' description' ]]
283334 then
284- read -rp " · What does this action do? ( leave blank to skip) ·" $' \n ' " ··· "
285- if [[ " $REPLY " == ' BACK ' ]]
335+ read -rp " · What does $( bold " ${ action} " ) do? · [ $( bold ' leave blank' ) to skip | $( bold ' UNDO ' ) to go back ] ·" $' \n ' " $( bold ' ·· ' ) "
336+ if [[ " $REPLY " == ' UNDO ' ]]
286337 then
287- echo " PREV_STATES" " ${prev_states[@]} "
288338 if (( ${# prev_states[@]} )) && (( ${# prev_runfiles[@]} ))
289339 then
290- echo -n " ${prev_runfiles[0]} " > Runfile
291- state=" ${prev_states[0]} "
292- prev_states=( " ${prev_states[@]: 1} " )
293- prev_runfiles=( " ${prev_runfiles[@]: 1} " )
340+ undo-step
294341 fi
295342 else
296- prev_states=( " ${state} " " ${prev_states[@]} " )
297- prev_runfiles=( " $( cat Runfile ) " " ${prev_runfiles[@]} " )
298- state=' command1'
343+ record-step
344+
299345 if [[ -n " $REPLY " ]]
300346 then
301- echo " # $REPLY " >> Runfile
347+ # Append to last line of file:
348+ sed ' $s/$/' " # $REPLY " ' /' << -EOF > Runfile
349+ ${prev_runfiles[0]}
350+ EOF
302351 else
352+ # Append newline to file:
303353 echo >> Runfile
304354 fi
355+
356+ state=' command1'
305357 fi
306358 elif [[ " ${state} " == ' command1' ]]
307359 then
308- read -rp " · Enter the first shell command that should be run ·" $' \n ' " ··· "
309- if [[ " $REPLY " == ' BACK ' ]]
360+ read -rp " · Enter $( bold ' 1st ' ) command for $( bold " ${action} " ) … ·" $' \n ' " $( bold ' ·· ' ) "
361+ if [[ " $REPLY " == ' UNDO ' ]]
310362 then
311363 if (( ${# prev_states[@]} )) && (( ${# prev_runfiles[@]} ))
312364 then
313- echo " ${prev_runfiles[0]} " > Runfile
314- state=" ${prev_states[0]} "
315- prev_states=( " ${prev_states[@]: 1} " )
316- prev_runfiles=( " ${prev_runfiles[@]: 1} " )
365+ undo-step
317366 fi
318367 elif [[ -n " $REPLY " ]]
319368 then
320- prev_states=( " ${state} " " ${prev_states[@]} " )
321- prev_runfiles=( " $( cat Runfile ) " " ${prev_runfiles[@]} " )
322- state=' command2'
369+ record-step
370+
323371 echo " $REPLY " >> Runfile
372+
373+ state=' command2'
374+ (( cmdidx++ ))
324375 fi
325376 elif [[ " ${state} " == ' command2' ]]
326377 then
327- read -rp " · Enter another shell command that should be run, or type DONE ·" $' \n ' " ·· "
328- if [[ " $REPLY " == ' BACK ' ]]
378+ read -rp " · Enter $( bold " $( ordinal " $(( cmdidx + 1 )) " ) " ) command for $( bold " ${action} " ) … · [ $( bold ' leave blank ' ) to continue | $( bold ' UNDO ' ) to go back ] ·" $' \n ' " $( bold ' ·· ' ) "
379+ if [[ " $REPLY " == ' UNDO ' ]]
329380 then
330381 if (( ${# prev_states[@]} )) && (( ${# prev_runfiles[@]} ))
331382 then
332- echo " ${prev_runfiles[0]} " > Runfile
333- state=" ${prev_states[0]} "
334- prev_states=( " ${prev_states[@]: 1} " )
335- prev_runfiles=( " ${prev_runfiles[@]: 1} " )
383+ undo-step
336384 fi
337- elif [[ " $REPLY " == ' DONE ' ]]
385+ elif [[ " $REPLY " == ' ' ]]
338386 then
339- prev_states=( " ${state} " " ${prev_states[@]} " )
387+ record-step
388+
340389 state=' action2'
341390 else
342- prev_states=( " ${state} " " ${prev_states[@]} " )
343- prev_runfiles=( " $( cat Runfile ) " " ${prev_runfiles[@]} " )
391+ record-step
392+
344393 echo " $REPLY " >> Runfile
394+
395+ (( cmdidx++ ))
345396 fi
346397 fi
347398 done
348-
349- if [[ -f ' Runfile' ]]
350- then
351- echo
352- echo " ./Runfile"
353- cat Runfile
354- echo
355- echo ' Your Runfile has been created successfully!'
356- echo ' Type "run" to review available commands.'
357- echo
358- fi
359399}
360400
361401function run() ( set -euo pipefail
0 commit comments