-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconsole.sh
executable file
·278 lines (235 loc) · 10.6 KB
/
console.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
#!/bin/bash
#github-action genshdoc
# if already sourced, return
[[ -v _CONSOLE__LOADED ]] && return || _CONSOLE__LOADED=True
declare -ga _CONSOLE__CLASSES=(console)
# @file main.sh
# @brief Library for print messages to console.
# @description Contains functions for print messages to console and manage indentation.
# It contains the class `console`
#
# Use the command `module.doc <function_name>` to see the documentation for a function (see an [example](https://github.com/vargiuscuola/std-lib.bash#examples))
# @show-internal
shopt -s expand_aliases
module.import "trap"
module.import "main"
module.import "args"
############
#
# SETTINGS
#
# @constant-header Terminal color codes
# @constant Color_Off Disable color
Color_Off=$'\e[0m'
# @constant Black,Red,Green,Yellow,Blue,Purple,Cyan,Orange Regular Colors
Black=$'\e[0;30m' Red=$'\e[0;31m' Green=$'\e[0;32m' Yellow=$'\e[0;33m' Blue=$'\e[0;34m' Purple=$'\e[0;35m' Cyan=$'\e[0;36m' White=$'\e[0;37m' Orange=$'\e[38;5;208m'
# @constant BBlack,BRed,BGreen,BYellow,BBlue,BPurple,BCyan,BWhite Bold Colors
BBlack=$'\e[1;30m' BRed=$'\e[1;31m' BGreen=$'\e[1;32m' BYellow=$'\e[1;33m' BBlue=$'\e[1;34m' BPurple=$'\e[1;35m' BCyan=$'\e[1;36m' BWhite=$'\e[1;37m'
# @constant UBlack,URed,UGreen,UYellow,UBlue,UPurple,UCyan,UWhite Underlined Colors
UBlack=$'\e[4;30m' URed=$'\e[4;31m' UGreen=$'\e[4;32m' UYellow=$'\e[4;33m' UBlue=$'\e[4;34m' UPurple=$'\e[4;35m' UCyan=$'\e[4;36m' UWhite=$'\e[4;37m'
# @constant On_Black,On_Red,On_Green,On_Yellow,On_Blue,On_Purple,On_Cyan,On_White Background Colors
On_Black=$'\e[40m' On_Red=$'\e[41m' On_Green=$'\e[42m' On_Yellow=$'\e[43m' On_Blue=$'\e[44m' On_Purple=$'\e[45m' On_Cyan=$'\e[46m' On_White=$'\e[47m'
# @constant IBlack,IRed,IGreen,IYellow,IBlue,IPurple,ICyan,IWhite High Intensty Colors
IBlack=$'\e[0;90m' IRed=$'\e[0;91m' IGreen=$'\e[0;92m' IYellow=$'\e[0;93m' IBlue=$'\e[0;94m' IPurple=$'\e[0;95m' ICyan=$'\e[0;96m' IWhite=$'\e[0;97m'
# @constant BIBlack,BIRed,BIGreen,BIYellow,BIBlue,BIPurple,BICyan,BIWhite Bold High Intensity Colors
BIBlack=$'\e[1;90m' BIRed=$'\e[1;91m' BIGreen=$'\e[1;92m' BIYellow=$'\e[1;93m' BIBlue=$'\e[1;94m' BIPurple=$'\e[1;95m' BICyan=$'\e[1;96m' BIWhite=$'\e[1;97m'
# @constant On_IBlack,On_IRed,On_IGreen,On_IYellow,On_IBlue,On_IPurple,On_ICyan,On_IWhite High Intensty Background Colors
On_IBlack=$'\e[0;100m' On_IRed=$'\e[0;101m' On_IGreen=$'\e[0;102m' On_IYellow=$'\e[0;103m' On_IBlue=$'\e[0;104m' On_IPurple=$'\e[10;95m' On_ICyan=$'\e[0;106m' On_IWhite=$'\e[0;107m'
############
#
# GLOBALS
#
# @global _CONSOLE__INDENT_N Number Number of indentation levels
_CONSOLE__INDENT_N=0
# @global _CONSOLE__INDENT_NCH Number Number of characters per indentation
_CONSOLE__INDENT_NCH=4
# @global _CONSOLE__MSG_COLOR_TABLE Hash Associative array containing the color to use for every type of console message
declare -gA _CONSOLE__MSG_COLOR_TABLE=([ERROR]="$Red" [OK]="$BGreen" [WARNING]="$Yellow" [INFO]="$Cyan" [INPUT]=$'\e[38;5;141m' [TEST]="$Orange" [DEBUG]="$Orange")
############
#
# CONSOLE FUNCTIONS
#
############
console_set-indent-level() {
_CONSOLE__INDENT_N=$1
}
alias console.set-indent-level="console_set-indent-level"
# @description Set the indentation size (number of spaces).
# @arg $1 Number Number of spaces per indentation
console_set-indent-size() {
_CONSOLE__INDENT_NCH=$1
}
alias console.set-indent-size="console_set-indent-size"
# @description Add the indentation level.
# @arg $1 Number Number of indentation level to add
console_add-indent() {
(( _CONSOLE__INDENT_N += 1 ))
}
alias console.add-indent="console_add-indent"
# @description Subtract the indentation level.
# @arg $1 Number Number of indentation level to subtract
console_sub-indent() {
[ "$_CONSOLE__INDENT_N" -gt 0 ] && (( _CONSOLE__INDENT_N -= 1 ))
}
alias console.sub-indent="console_sub-indent"
# @description Print the spaces consistent to the current indentation level.
console_print-indent() {
local i indent_str
eval "printf ' %.0s' {1..$(($_CONSOLE__INDENT_NCH*$_CONSOLE__INDENT_N))}"
}
alias console.print-indent="console_print-indent"
# @description Get extended terminal color codes
#
# @arg $1 number Foreground color
# @arg $2 number Background color
#
# @example
# get_ext_color 208
# => \e[38;5;208m
#
# @exitcode NA
#
# @stdout Color code.
console_get-extended-color() {
declare -a colors
[ -n "$1" ] && colors+=("38;5;$1")
[ -n "$2" ] && colors+=("48;5;$1")
local bck_ifs="$IFS"
IFS=';'
declare -g __
printf -v __ "%b" "\e[${colors[*]}m"
IFS="$bck_ifs"
}
alias console.get-extended-color="console_get-extended-color"
# @description Print a message of the type provided.
# The format of the message is `[<message-type>] <msg>`. The message type is colorized with same default color specific for every type of message (it can be customized with the `--color` parameter).
# When piped, the function doesn't colorize the message type unless the settings COLORIZE_OUTPUT is enabled (`settings.enable COLORIZE_OUTPUT`).
# @alias console.msg
# @arg $1 The type of message (written in square brackets). If type is `ERROR`, then by default the message will be written to stderr (can be overriden by the `--stdout` option)
# @arg $2..@ The message to print
# @opt --show-function Prefix the message with the calling function
# @opt --exit <n> Exit the script with the <n> status code
# @opt -n Don't print the ending newline
# @opt -e Interpret special characters
# @opt --color <color> Print the type of message (first argument) with the color specified
# @opt --stderr Print the message to stderr (can't be set together with the `--stdout` parameter)
# @opt --stdout Print the message to stdout (can't be set together with the `--stderr` parameter)
# @opt --tty Print the message to console
# @opt --indent Prefix the message with the indentation
# @exitcodes Standard
# @stdout Print the message
console_msg() {
declare -A __opts
declare -a __args
args.parse __opts __args -- --show-function --exit: -n -e --color: --stderr --stdout --tty --indent -- "$@"
(( ${#__args[@]} < 1 )) && { errmsg "Missing the argument with the type of message" ; raise ; }
(( ${#__args[@]} < 2 )) && { errmsg "Missing the argument with the message to print" ; raise ; }
declare -a add_args=()
local type msg color exit_code is_stderr function_info
# if --show-function option, then add the function name to the message
[[ ${__opts[show-function]+x} ]] && function_info="${FUNCNAME[1]}()# "
type="${__args[0]}"
exit_code=${__opts[exit]}
[[ ${__opts[n]+x} ]] && add_args+=(-n)
[[ ${__opts[e]+x} ]] && add_args+=(-e)
color=${__opts[color]}
[ -z "$color" ] && color="${_CONSOLE__MSG_COLOR_TABLE[$type]}"
# check if message should be sent to stderr
[[ ( "$type" = ERROR || ${__opts[stderr]+x} ) && ! ${__opts[stdout]+x} ]] && is_stderr=1
# if tty or stderr option...
if [[ ${__opts[tty]+x} || "$is_stderr" = 1 ]]; then
fd.get_ ; local fd_stdout="$__"
if [[ ${__opts[tty]+x} ]]; then
eval "exec $fd_stdout>&1 >/dev/tty"
elif [ "$is_stderr" = 1 ]; then
eval "exec $fd_stdout>&1 >&2"
fi
fi
# add indentation if `--indent` parameter is set
[[ ${__opts[indent]+x} ]] && console.print-indent
# add message type with color or not depending on the `COLORIZE_OUTPUT` setting and/or the current script/function is piped
if settings.is-enabled COLORIZE_OUTPUT || [ -t 1 ]; then
echo -n "$color"[$type]"$Color_Off "
else
echo -n "[$type] "
fi
echo ${add_arg[@]} "${function_info}""${__args[@]:1}"
# restore the stdout and stderr if needed
[[ "$is_stderr" = 1 || ${__opts[tty]+x} ]] && eval "exec >&$fd_stdout $fd_stdout>&-" || true
# if exit code is set, then exit
[ -n "$exit_code" ] && exit "$exit_code" || return 0
}
alias console.msg="console_msg"
# define aliases for other types of messages
for _CONSOLE__TYPE_MSG in INPUT OK ERROR INFO WARN TEST DEBUG; do
[ "$_CONSOLE__TYPE_MSG" = INPUT ] && _CONSOLE__ADD_ARG="--tty " || _CONSOLE__ADD_ARG=""
alias console_${_CONSOLE__TYPE_MSG,,}="console_msg --color '${_CONSOLE__MSG_COLOR_TABLE[$_CONSOLE__TYPE_MSG]}' $_CONSOLE__ADD_ARG $_CONSOLE__TYPE_MSG"
alias console.${_CONSOLE__TYPE_MSG,,}="console_msg --color '${_CONSOLE__MSG_COLOR_TABLE[$_CONSOLE__TYPE_MSG]}' $_CONSOLE__ADD_ARG $_CONSOLE__TYPE_MSG"
done
# @description Print a message with printf syntax.
# The output is left untouched if the setting `COLORIZE_OUTPUT` is enabled (`settings.enable COLORIZE_OUTPUT`) or if the output is not piped, otherwise the color codes are removed.
# @stdout Print the message
console_printf() {
# is COLORIZE_OUTPUT is enabled or the output is not piped
if settings.is-enabled COLORIZE_OUTPUT || [ -t 1 ]; then
printf "$@"
# otherwise color codes are removed
else
printf "$@" | sed -r "s/\x1B\[([0-9]{1,3};){0,2}[0-9]{0,3}[mGK]//g"
fi
}
alias console.printf="console_printf"
# @description Used to restore the IFS and stty for non-blocking `console.readkeys` function.
# You need to call it after you finished to use the `console.readkeys` function.
# @alias console.finalize-readkeys
console_finalize-readkeys() {
[ -n "$_CONSOLE__IFS" ] && IFS="$_CONSOLE__IFS"
[ -n "$_CONSOLE__OLDSTTY" ] && { stty "$_CONSOLE__OLDSTTY" ; } </dev/tty
}
alias console.finalize-readkeys="console_finalize-readkeys"
# @description Needed to initialize the stty before using the `console.readkeys` function.
# @alias console.init-readkeys
console_init-readkeys() {
local char
trap.add-handler FINALIZE_READKEYS console_finalize-readkeys EXIT
{
declare -g _CONSOLE__OLDSTTY=`stty -g`
stty -icanon -echo
declare -g _CONSOLE__IFS="$IFS"
IFS=$'\0'
while read -t 0 -N 0; do
read -N 1 char
done
IFS="$_CONSOLE__IFS"
} </dev/tty
}
alias console.init-readkeys="console_init-readkeys"
# @description Read the pressed keys in non-blocking manner: it will return the keys pressed in the buffer.
# Before using this function you need to call the `console.init-readkeys` function and when done, you need to call the `console.finalize-readkeys` function.
# @alias console.readkeys
# @return The pressed key(s)
# @example
# while true; do
# echo -n .
# console.readkeys && { echo "pressed key=$__" ; break ; }
# sleep 1
# done
# console.finalize-readkeys
console_readkeys() {
local char ret=1
[ -z "$_CONSOLE__IFS" ] && declare -g _CONSOLE__IFS="$IFS"
IFS=$'\0'
{
if read -t 0 -N 0; then
declare -g __=""
while read -t 0 -N 0; do
read -N 1 -r char
__="$__$char"
done
ret=0
fi
} </dev/tty
IFS="$_CONSOLE__IFS"
return $ret
}
alias console.readkeys="console_readkeys"