#!/usr/bin/env zsh # patterns for option matching boolpat='^(true|yes|on|1|false|no|off|0)$' booltpat='^(true|yes|on|1)$' boolfpat='^(false|no|off|0)$' intpat='^[-+]?[0-9]+$' unsignedpat='^[0-9]+$' posunsignedpat='^[1-9][0-9]*$' floatpat='^[-+]?[0-9]+(\.[0-9]*|e(0|[-+]?[1-9][0-9]*)|\.[0-9]*e(0|[-+]?[1-9][0-9]*$' termcolourpat='^(black|light_black|red|light_red|green|light_green|yellow|light_yellow|blue|light_blue|magenta|light_magenta|cyan|light_cyan|white|light_white)$' # $1 - colour termcolourpat2escape() { [[ $#@ -eq 1 ]] || {echo 'badcolour'; return 1} [[ $1 =~ $termcolourpat ]] || {echo 'badcolour'; return 1} case $1 in 'black') printf '\e[30m' ;; 'light_black') printf '\e[1;30m' ;; 'red') printf '\e[31m' ;; 'light_red') printf '\e[1;31m' ;; 'green') printf '\e[32m' ;; 'light_green') printf '\e[1;32m' ;; 'yellow') printf '\e[33m' ;; 'light_yellow') printf '\e[1;33m' ;; 'blue') printf '\e[34m' ;; 'light_blue') printf '\e[1;34m' ;; 'magenta') printf '\e[35m' ;; 'light_magenta') printf '\e[1;35m' ;; 'cyan') printf '\e[36m' ;; 'light_cyan') printf '\e[1;36m' ;; 'white') printf '\e[37m' ;; 'light_white') printf '\e[1;37m' ;; esac } # $1 - message print-error() { 1>&2 echo "\e[1;31merror:\e[0m $1" } # $1 - message abort() { print-error $1 exit 1 } # $1 - seconds sec2time() { zmodload zsh/datetime || return 1 if [[ $1 -lt 0 ]]; then printf "??:??:??" return 0 fi if [[ $1 -lt 86400 ]]; then TZ=UTC strftime '%H:%M:%S' $1 return 0 fi if [[ $1 -ge 8640000 ]]; then printf "forever?" return 0 fi printf "~%02d days" "$(($1 / 86400))" } # $1 - count # $2 - message (opt) # $3 - colour (opt) progress-bar() { zmodload zsh/mathfunc zsh/datetime || return 1 [[ $#@ -ne 0 ]] && [[ $#@ -lt 4 ]] || return 1 local count [[ $1 =~ $posunsignedpat ]] && count=$1 || return 1 [[ ! -z $3 ]] && { [[ $3 =~ $termcolourpat ]] || return 1 } local message local colour [[ -z $2 ]] && message='waiting' || message=$2 [[ -z $3 ]] && colour='yellow' || colour=$3 colour=$(termcolourpat2escape $colour) local i=0 local starttime=$EPOCHREALTIME local lasttime=$starttime local thistime=$starttime local now=$starttime local elapsed=0 while true; do [[ $i -eq $count ]] && break now=$EPOCHREALTIME local width=$COLUMNS local statwidth=$(( ($#count * 2) + 35)) local progwidth=$(($width - $statwidth - 3)) [[ $progwidth -gt 30 || $progwidth -le 1 ]] && progwidth=30 if [[ $i -eq 0 ]]; then eta='??:??:??' else eta=$(sec2time ${$(( ceil( ($count - $i) * ($elapsed / $i) - ($now - $lasttime) ) )):s/\./}) fi local rt=$(sec2time ${$(( floor( ($now - $starttime) ) )):s/\./} ) local fpart="" local epart="" local progress=$(($i * $progwidth / $count)) repeat $progress fpart="$fpart#" repeat $(($progwidth - $progress)) epart="$epart-" printf \ "\e[G\e[K$colour%s...\e[0m\n[%${#count}s/$count] [rt: $rt] [eta: $eta] [$fpart$epart]\e[J" \ $message \ $i \ read -t 0.2 \ && thistime=$EPOCHREALTIME \ && elapsed=$(($elapsed - $lasttime + $thistime)) \ && lasttime=$thistime \ && i=$(($i + 1)) printf "\e[F" done [[ $i -eq $count ]] \ && echo "\e[G\e[32m$message... done in $(sec2time ${$(( floor($elapsed) )):s/\./})\e[0m\e[J" \ || echo "\e[G\e[31m$message... failed!\e[0m\e[J" } # $1 - pid # $2 - message (opt) # $3 - colour (opt) wait-anim() { [[ $#@ -ne 0 ]] && [[ $#@ -lt 4 ]] || return 1 [[ $1 =~ $posunsignedpat ]] || return 1 [[ ! -z $3 ]] && { [[ $3 =~ $termcolourpat ]] || return 1 } local message local colour [[ -z $2 ]] && message='waiting' || message=$2 [[ -z $3 ]] && colour='yellow' || colour=$3 colour=$(termcolourpat2escape $colour) local frames case $(($RANDOM % 7)) in 0) frames=('▁' '▂' '▃' '▄' '▅' '▆' '▇' '█' '▇' '▆' '▅' '▄' '▃' '▂') ;; 1) frames=(' ' '▖' '▚' '▝' ' ' '▘' '▞' '▗') ;; 2) frames=('╀' '╂' '╁' '┼' '┽' '┿' '┾' '┼' '╁' '╂' '╀' '┼' '┾' '┿' '┽' '┼') ;; 3) frames=('─' '└' '│' '┌' '─' '┐' '│' '┘') ;; 4) frames=('.' '。' '×' ':' '*' '.' '°' '♪' '×' '♫' '°' '♡') ;; 5) frames=(' ' ' ' '░' '░' '▒' '▒' '▓' '▓' '█' '█' '▓' '▓' '▒' '▒' '░' '░') ;; 6) frames=('O' 'o' '.' 'o') ;; esac local curframe coproc while true; do [[ -z $curframe ]] && curframe=0 printf "\e[G\e[K|\e[1;32m${frames[$(($curframe + 1))]}\e[0m| $colour$message...\e[0m\n" curframe=$(( ($curframe + 1) % $#frames )) read -t 0.2 && break done while read -p line; do printf $line done & local printer=$! local rval 2>/dev/null wait $1 && rval=$? && echo "done" >&p 2>/dev/null wait $printer [[ $rval -eq 0 ]] && printf "\e[G\e[K\e[32m$message... done!\e[0m\n" \ || printf "\e[G\e[K\e[31m$message... failed!\e[0m\n" return $rval }