mirror of
https://github.com/mjsarfatti/beddu.git
synced 2025-06-26 17:08:01 +02:00
Release v0.0.5
This commit is contained in:
parent
cb53800a20
commit
05f318b0f2
1 changed files with 310 additions and 0 deletions
310
dist/beddu.sh
vendored
Executable file
310
dist/beddu.sh
vendored
Executable file
|
@ -0,0 +1,310 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck disable=all
|
||||||
|
#
|
||||||
|
# beddu.sh - A lightweight bash framework for interactive scripts and pretty output
|
||||||
|
# https://github.com/mjsarfatti/beddu
|
||||||
|
#
|
||||||
|
# Version: v0.0.5
|
||||||
|
# Generated on: Sun May 11 13:37:32 CEST 2025
|
||||||
|
|
||||||
|
readonly _q='?'
|
||||||
|
readonly _a='❯'
|
||||||
|
readonly _o='◌'
|
||||||
|
readonly _O='●'
|
||||||
|
readonly _mark='✓'
|
||||||
|
readonly _warn='!'
|
||||||
|
readonly _cross='✗'
|
||||||
|
readonly _spinner='⣷⣯⣟⡿⢿⣻⣽⣾' # See for alternatives: https://antofthy.gitlab.io/info/ascii/Spinners.txt
|
||||||
|
readonly _spinner_frame_duration=0.1
|
||||||
|
|
||||||
|
up() {
|
||||||
|
printf "\033[A"
|
||||||
|
}
|
||||||
|
down() {
|
||||||
|
printf "\033[B"
|
||||||
|
}
|
||||||
|
bol() {
|
||||||
|
printf "\r"
|
||||||
|
}
|
||||||
|
eol() {
|
||||||
|
printf "\033[999C"
|
||||||
|
}
|
||||||
|
cl() {
|
||||||
|
printf "\033[2K"
|
||||||
|
}
|
||||||
|
upclear() {
|
||||||
|
up; bol; cl
|
||||||
|
}
|
||||||
|
line() {
|
||||||
|
printf "\n"
|
||||||
|
}
|
||||||
|
show_cursor() {
|
||||||
|
printf "\033[?25h"
|
||||||
|
}
|
||||||
|
hide_cursor() {
|
||||||
|
printf "\033[?25l"
|
||||||
|
}
|
||||||
|
|
||||||
|
pen() {
|
||||||
|
local new_line="\n"
|
||||||
|
local text="${*: -1}"
|
||||||
|
local args=("${@:1:$#-1}")
|
||||||
|
local format_code=""
|
||||||
|
local reset_code="\033[0m"
|
||||||
|
for arg in "${args[@]}"; do
|
||||||
|
arg=${arg,,}
|
||||||
|
case "$arg" in
|
||||||
|
-n) new_line="" ;;
|
||||||
|
bold) format_code+="\033[1m" ;;
|
||||||
|
italic) format_code+="\033[3m" ;;
|
||||||
|
underline) format_code+="\033[4m" ;;
|
||||||
|
black) format_code+="\033[30m" ;;
|
||||||
|
red) format_code+="\033[31m" ;;
|
||||||
|
green) format_code+="\033[32m" ;;
|
||||||
|
yellow) format_code+="\033[33m" ;;
|
||||||
|
blue) format_code+="\033[34m" ;;
|
||||||
|
purple) format_code+="\033[35m" ;;
|
||||||
|
cyan) format_code+="\033[36m" ;;
|
||||||
|
white) format_code+="\033[37m" ;;
|
||||||
|
grey | gray) format_code+="\033[90m" ;;
|
||||||
|
[0-9]*)
|
||||||
|
if [[ "$arg" =~ ^[0-9]+$ ]] && [ "$arg" -ge 0 ] && [ "$arg" -le 255 ]; then
|
||||||
|
format_code+="\033[38;5;${arg}m"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*) ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
printf "%b%s%b%b" "${format_code}" "${text}" "${reset_code}" "${new_line}"
|
||||||
|
}
|
||||||
|
|
||||||
|
run() {
|
||||||
|
local outvar_name errvar_name
|
||||||
|
local -n outvar errvar # Declare namerefs (will be assigned below if needed)
|
||||||
|
local cmd
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--out)
|
||||||
|
outvar_name="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--err)
|
||||||
|
errvar_name="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
cmd=("$@")
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
[[ -n "${outvar_name}" ]] && local -n outvar="${outvar_name}"
|
||||||
|
[[ -n "${errvar_name}" ]] && local -n errvar="${errvar_name}"
|
||||||
|
local stdout_file stderr_file
|
||||||
|
stdout_file=$(mktemp)
|
||||||
|
stderr_file=$(mktemp)
|
||||||
|
"${cmd[@]}" >"${stdout_file}" 2>"${stderr_file}"
|
||||||
|
local exit_code=$?
|
||||||
|
[[ -n "${outvar_name}" ]] && outvar="$(<"$stdout_file")"
|
||||||
|
[[ -n "${errvar_name}" ]] && errvar="$(<"$stderr_file")"
|
||||||
|
rm -f "${stdout_file}" "${stderr_file}"
|
||||||
|
return $exit_code
|
||||||
|
}
|
||||||
|
|
||||||
|
check() {
|
||||||
|
if spinning; then
|
||||||
|
spop
|
||||||
|
upclear
|
||||||
|
fi
|
||||||
|
pen -n green "${_mark:-✓} "
|
||||||
|
pen "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
repen() {
|
||||||
|
upclear
|
||||||
|
pen "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
trap spop EXIT INT TERM
|
||||||
|
_spinner_pid=""
|
||||||
|
_frame_duration="${_spinner_frame_duration:-0.1}"
|
||||||
|
spin() {
|
||||||
|
local message=("$@")
|
||||||
|
local spinner="${_spinner:-⣷⣯⣟⡿⢿⣻⣽⣾}"
|
||||||
|
if spinning; then
|
||||||
|
spop --keep-cursor-hidden
|
||||||
|
fi
|
||||||
|
(
|
||||||
|
hide_cursor
|
||||||
|
trap "show_cursor; exit 0" USR1
|
||||||
|
pen -n cyan "${spinner:0:1} "
|
||||||
|
pen "${message[@]}"
|
||||||
|
while true; do
|
||||||
|
for ((i = 0; i < ${#spinner}; i++)); do
|
||||||
|
frame="${spinner:$i:1}"
|
||||||
|
up
|
||||||
|
bol
|
||||||
|
pen -n cyan "${frame} "
|
||||||
|
pen "${message[@]}"
|
||||||
|
sleep "$_frame_duration"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
) &
|
||||||
|
_spinner_pid=$!
|
||||||
|
}
|
||||||
|
spop() {
|
||||||
|
local keep_cursor_hidden=false
|
||||||
|
[[ "$1" == "--keep-cursor-hidden" ]] && keep_cursor_hidden=true
|
||||||
|
if spinning; then
|
||||||
|
kill -USR1 "${_spinner_pid}" 2>/dev/null
|
||||||
|
sleep "$_frame_duration"
|
||||||
|
if ps -p "${_spinner_pid}" >/dev/null 2>&1; then
|
||||||
|
kill "${_spinner_pid}" 2>/dev/null
|
||||||
|
if [[ "$keep_cursor_hidden" == false ]]; then
|
||||||
|
show_cursor
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
_spinner_pid=""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
spinning() {
|
||||||
|
[[ -n "${_spinner_pid}" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
throw() {
|
||||||
|
if spinning; then
|
||||||
|
spop
|
||||||
|
upclear
|
||||||
|
fi
|
||||||
|
pen -n red "${_cross:-✗} "
|
||||||
|
pen "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
warn() {
|
||||||
|
if spinning; then
|
||||||
|
spop
|
||||||
|
upclear
|
||||||
|
fi
|
||||||
|
pen -n yellow bold italic "${_warn:-!} "
|
||||||
|
pen italic "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
ask() {
|
||||||
|
local -n outvar="$1"
|
||||||
|
local prompt
|
||||||
|
local answer
|
||||||
|
prompt=$(
|
||||||
|
pen -n blue "${_q:-?} "
|
||||||
|
pen "${2}"
|
||||||
|
pen -n blue "${_a:-❯} "
|
||||||
|
)
|
||||||
|
show_cursor
|
||||||
|
while true; do
|
||||||
|
read -r -p "$prompt" answer
|
||||||
|
case "$answer" in
|
||||||
|
"")
|
||||||
|
echo
|
||||||
|
warn "Please type your answer."
|
||||||
|
;;
|
||||||
|
*) break ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
outvar="$answer"
|
||||||
|
}
|
||||||
|
|
||||||
|
choose() {
|
||||||
|
local -n outvar="$1"
|
||||||
|
local prompt
|
||||||
|
local options=("${@:3}")
|
||||||
|
local current=0
|
||||||
|
local count=${#options[@]}
|
||||||
|
prompt=$(
|
||||||
|
pen -n blue "${_q:-?} "
|
||||||
|
pen -n "${2}"
|
||||||
|
pen gray "[↑↓]"
|
||||||
|
)
|
||||||
|
hide_cursor
|
||||||
|
trap 'show_cursor; return' INT TERM
|
||||||
|
pen "$prompt"
|
||||||
|
while true; do
|
||||||
|
local index=0
|
||||||
|
for item in "${options[@]}"; do
|
||||||
|
if ((index == current)); then
|
||||||
|
pen -n blue "${_O:-●} "
|
||||||
|
pen "${item}"
|
||||||
|
else
|
||||||
|
pen gray "${_o:-◌} ${item}"
|
||||||
|
fi
|
||||||
|
((index++))
|
||||||
|
done
|
||||||
|
read -s -r -n1 key
|
||||||
|
if [[ $key == $'\e' ]]; then
|
||||||
|
read -s -r -n2 -t 0.0001 escape
|
||||||
|
key+="$escape"
|
||||||
|
fi
|
||||||
|
case "$key" in
|
||||||
|
$'\e[A' | 'k')
|
||||||
|
((current--))
|
||||||
|
[[ $current -lt 0 ]] && current=$((count - 1))
|
||||||
|
;;
|
||||||
|
$'\e[B' | 'j')
|
||||||
|
((current++))
|
||||||
|
[[ $current -ge "$count" ]] && current=0
|
||||||
|
;;
|
||||||
|
'')
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo -en "\e[${count}A\e[J"
|
||||||
|
done
|
||||||
|
outvar="${options[$current]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
confirm() {
|
||||||
|
local default="y"
|
||||||
|
local hint="[Y/n]"
|
||||||
|
local prompt
|
||||||
|
local response
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--default-no)
|
||||||
|
default="n"
|
||||||
|
hint="[y/N]"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--default-yes)
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*) break ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
prompt=$(
|
||||||
|
pen -n blue "${_q:-?} "
|
||||||
|
pen -n "$1"
|
||||||
|
pen gray " $hint"
|
||||||
|
pen -n blue "${_a:-❯} "
|
||||||
|
)
|
||||||
|
show_cursor
|
||||||
|
while true; do
|
||||||
|
read -r -p "$prompt" response
|
||||||
|
response="${response:-$default}"
|
||||||
|
case "$response" in
|
||||||
|
[Yy] | [Yy][Ee][Ss])
|
||||||
|
upclear
|
||||||
|
pen -n blue "${_a:-❯} "
|
||||||
|
pen "yes"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
[Nn] | [Nn][Oo])
|
||||||
|
upclear
|
||||||
|
pen -n blue "${_a:-❯} "
|
||||||
|
pen "no"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo
|
||||||
|
warn "Please answer yes or no."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue