export F_BOLD="\e[1m" export F_NONE="\e[0m" export C_NONE="\e[0m" export C_RED="\e[38;5;9m" export C_BLUE="\e[38;5;12m" export C_GREEN="\e[38;5;2m" export C_ORANGE="\e[38;5;208m" export C_YELLOW="\e[38;5;220m" export C_PURPLE="\e[38;5;5m" export S_DEBUG="${C_PURPLE}\u2691 [debug]${F_NONE} " export S_CRIT="${F_BOLD}${C_RED}\u2691 [critical]${F_NONE} " export S_ERROR="${C_RED}\u2691 [error]${F_NONE} " export S_WARN="${C_ORANGE}\u2691 [warning]${F_NONE} " export S_INFO="${F_BOLD}${C_BLUE}\u2691 [info]${F_NONE} " export S_NOTICE="${C_BLUE}\u2691 [notice]${F_NONE} " export S_SUCCESS="${F_BOLD}${C_GREEN}\u2691 [success]${F_NONE} " export U_ITEM="\u21e2" export U_TICK="\u2713" export U_FAIL="\u2715" #export COLS="$(( $(tput cols) - 1 ))" export EL=$(tput el) # Get the cursor current position and returns CURSOR_X, CURSOR_Y : "cli.get_cursor" cli.get_cursor() { local _xy echo -ne $"\e[6n" read -rsdR _xy _xy="${_xy#*[}" export CURSOR_X=${_xy/*;} export CURSOR_Y=${_xy/;*} } # Puts the cursor at x:y (defaults to 0:0) : "cli.set_cursor " cli.set_cursor() { printf "\e[%sH" "${2:0};${1:0}" } # Puts cursor N lines up : "cli.lineup []" cli.lineup() { printf "\e[%sA${EL}\e[0F" "${1:-1}" } # Puts cursor N lines down : "cli.linedown []" cli.linedown() { printf "\e[%sB${EL}\e[0F" "${1:-1}" } # Clears the screen below cursor position : "cli.clear" cli.clear() { cli.writeln cli.lineup cli.get_cursor local _lines=$((( $(tput lines) - ${CURSOR_Y} - 1 ))) for i in $(seq 1 ${_lines}); do cli.writeln done cli.set_cursor 0 ${CURSOR_Y} } # Just prints a blank line : "cli.writeln" cli.writeln() { cli.linedown printf "\n" } # Just like printf : "cli.print [] [ ...]" cli.print() { printf "${1:-}" ${@:2} } # Folds text at 'size' column : "cli.fold " cli.fold() { printf "%s" "${@:2}" | fold -sw ${1} } : "cli.status [] " cli.status() { local fmt="${2:-}" fmt="${fmt//\\n}" cli.writeln case "${1:-info}" in debug) printf "\e[0F${S_DEBUG}${fmt:-%s}${@:3}${EL}\n" ;; crit*) printf "\e[0F${S_CRIT}${fmt:-%s}${@:3}${EL}\n" ;; error) printf "\e[0F${S_ERROR}${fmt:-%s}${@:3}${EL}\n" ;; warn*) printf "\e[0F${S_WARN}${fmt:-%s}${@:3}${EL}\n" ;; info*) printf "\e[0F${S_INFO}${fmt:-%s}${@:3}${EL}\n" ;; noti*) printf "\e[0F${S_NOTICE}${fmt:-%s}${@:3}${EL}\n" ;; succ*) printf "\e[0F${S_SUCCESS}${fmt:-%s}${@:3}${EL}\n" ;; *) printf "\e[0F${S_INFO}${fmt:-%s}" "${@:3}" ;; esac } : "cli.color [] [ ...]" cli.color() { local fmt="${2:-}" fmt="${fmt//\\n}" case "${1:-}" in red) printf "${C_RED}${fmt:-%s}${C_NONE}" ${@:3} ;; blue) printf "${C_BLUE}${fmt:-%s}${C_NONE}" ${@:3} ;; green) printf "${C_GREEN}${fmt:-%s}${C_NONE}" ${@:3} ;; orange) printf "${C_ORANGE}${fmt:-%s}${C_NONE}" ${@:3} ;; yellow) printf "${C_YELLOW}${fmt:-%s}${C_NONE}" ${@:3} ;; purple) printf "${C_PURPLE}${fmt:-%s}${C_NONE}" ${@:3} ;; *) printf "${C_NONE}${fmt:-%s}${C_NONE}" ${@:3} ;; esac } : "cli.emphasis [] [ ...]" cli.emphasis() { local fmt="${2:-}" fmt="${fmt//\\n}" case "${1:-bold}" in red) printf "${C_RED}${F_BOLD}${fmt:-%s}${F_NONE}" "${@:3}" ;; blue) printf "${C_BLUE}${F_BOLD}${fmt:-%s}${F_NONE}" "${@:3}" ;; green) printf "${C_GREEN}${F_BOLD}${fmt:-%s}${F_NONE}" "${@:3}" ;; orange) printf "${C_ORANGE}${F_BOLD}${fmt:-%s}${F_NONE}" "${@:3}" ;; yellow) printf "${C_YELLOW}${F_BOLD}${fmt:-%s}${F_NONE}" "${@:3}" ;; purple) printf "${C_PURPLE}${F_BOLD}${fmt:-%s}${F_NONE}" "${@:3}" ;; bold|*) printf "${F_BOLD}${fmt:-%s}${F_NONE}" "${@:3}" ;; esac } : "cli.bold " cli.bold() { cli.emphasis bold "%s" "${@}" } : "cli.tab " cli.tab() { s=${1:-2} ! [[ -z "${s//[0-9]}" ]] && s=2 printf "%${s:-2}s" " " } : "cli.items [] [ ...]" cli.items() { printf "${U_ITEM} ${1:-%s}" "${@:2}" } : "cli.item " cli.item() { cli.items "%s\n" "${@}" | head -1 } : "cli.title " cli.title() { cli.items "%s" "$(cli.emphasis blue "%s" "${@^^}")" cli.line cli.writeln } : "cli.subtitle [noline]" cli.subtitle() { printf "%0.s\u2508%s" cli.bold " ${@^^} " cli.get_cursor for i in $(seq 0 $((( $(tput cols) - ${CURSOR_X} )))); do printf "%0.s\u2508" done cli.writeln } : "cli.prompt [] []" cli.prompt() { local k= _get_var() { : "${@:$#}"; echo "${_//-*/}"; } _get_opts() { echo "${@//${_var}/}"; } case ${#@} in 1) _prompt="$(cli.print "${1:-}")" _var=k _opts= ;; *) _prompt="$(cli.print "${1:-}")" _var=$(_get_var ${@:2}) _opts=$(_get_opts ${@:2}) ;; esac read -p "$(cli.print "${1:-}")" ${_opts} ${_var:-k} ! [[ -z "${k}" ]] && echo "${k}" || : } # Draws a horizontal line : "cli.line [nobreak]" cli.line() { [[ -z "${1:-}" ]] && cli.writeln for i in $(seq 1 $(tput cols)); do printf "%0.s\u2504" done [[ -z "${1:-}" ]] && cli.writeln } # Draws a thin horizontal divisor line : "cli.boldline" cli.boldline() { for i in $(seq 1 $(tput cols)); do printf "%0.s\u2581" done cli.writeln } cli.subprocess.output() { while readarray -t -n ${1:-10} buffer && ((${#buffer[@]})); do cli.set_cursor 0 ${CURSOR_Y} local _max_len=$(( $(tput cols) - 18 )) for line in "${buffer[@]}"; do ! [[ -z "${line}" ]] \ && cli.color purple " %s" "${line:0:${_max_len}}${EL}" \ && cli.writeln done done cli.set_cursor 0 ${CURSOR_Y} for _i in {1..${1}}; do cli.writeln done cli.set_cursor 0 ${CURSOR_Y} } cli.subprocess.success() { cli.set_cursor 0 ${CURSOR_Y} printf " ${S_SUCCESS}%s\n" "${@:1:1}${EL}" for p in ${@:2}; do cli.tab 2; cli.print "$( cli.color green "$(cli.item ${p}${EL})" )\n" done } cli.subprocess.failure() { cli.set_cursor 0 ${CURSOR_Y} printf " ${S_ERROR}%s\n" "${@:1:1}${EL}" if [[ -f "${2:-}" ]]; then tail -${4:-50} ${@:2:1} 2>/dev/null | while read line; do cli.tab 2; cli.print "$( cli.color red "${3:-Log}: ${line}${EL}" )\n" done else cli.lineup cli.clear fi } : "cli.section <subtitle> <content>" cli.section() { cli.set_cursor 0 0 __section.header() { __section.title() { printf $"${@:1:1}" \ $(echo -ne ${F_BOLD}${C_BLUE}${@:2:1}${F_NONE}) \ $(echo -ne ${C_ORANGE}${@:3}${F_NONE}) } __section.title.underline() { cli.boldline cli.writeln } __section.title "${@}" __section.title.underline } __section.content() { cli.linedown cli.fold $(tput cols) "${@}" cli.writeln } __section.footer() { __section.footer.line() { cli.line } __section.footer.line } cli.clear __section.header "${@:1:3}" ! [[ -z "${@:4}" ]] && __section.content "${@:4}" ! [[ -z "${@:4}" ]] && __section.footer } cli.self_compress() { cat cli.bash | \ gzip -c9 - | \ base64 -w77 | \ xargs printf ' %s \\\n' }