diff options
-rwxr-xr-x | bollux | 448 |
1 files changed, 232 insertions, 216 deletions
diff --git a/bollux b/bollux index 2de37ab..d51f444 100755 --- a/bollux +++ b/bollux | |||
@@ -62,139 +62,13 @@ usage: | |||
62 | flags: | 62 | flags: |
63 | -h show this help and exit | 63 | -h show this help and exit |
64 | -q be quiet: log no messages | 64 | -q be quiet: log no messages |
65 | -v verbose: log more messages | 65 | -v be verbose: log more messages |
66 | parameters: | 66 | parameters: |
67 | URL the URL to start in | 67 | URL the URL to start in |
68 | If not provided, the user will be prompted. | 68 | If not provided, the user will be prompted. |
69 | END | 69 | END |
70 | } | 70 | } |
71 | 71 | ||
72 | # UTILITY FUNCTIONS ############################################################ | ||
73 | |||
74 | # Run a command, but log it first. | ||
75 | # | ||
76 | # See `log' for the available levels. | ||
77 | run() { # run COMMAND... | ||
78 | # I have to add a `trap' here for SIGINT to work properly. | ||
79 | trap bollux_quit SIGINT | ||
80 | log debug "$*" | ||
81 | "$@" | ||
82 | } | ||
83 | |||
84 | # Exit with an error and a message describing it. | ||
85 | die() { # die EXIT_CODE MESSAGE | ||
86 | local ec="$1" | ||
87 | shift | ||
88 | log error "$*" | ||
89 | exit "$ec" | ||
90 | } | ||
91 | |||
92 | # Exit with success, printing a fun message. | ||
93 | # | ||
94 | # The default message is from the wonderful show "Cowboy Bebop." | ||
95 | bollux_quit() { | ||
96 | printf '\e[1m%s\e[0m:\t\e[3m%s\e[0m\n' "$PRGN" "$BOLLUX_BYEMSG" | ||
97 | exit | ||
98 | } | ||
99 | # SIGINT is C-c, and I want to make sure bollux quits when it's typed. | ||
100 | trap bollux_quit SIGINT | ||
101 | |||
102 | # Trim leading and trailing whitespace from a string. | ||
103 | # | ||
104 | # [1]: #trim-leading-and-trailing-white-space-from-string | ||
105 | trim_string() { # trim_string STRING | ||
106 | : "${1#"${1%%[![:space:]]*}"}" | ||
107 | : "${_%"${_##*[![:space:]]}"}" | ||
108 | printf '%s\n' "$_" | ||
109 | } | ||
110 | |||
111 | # Cycle a variable. | ||
112 | # | ||
113 | # e.g. 'cycle_list one,two,three' => 'two,three,one' | ||
114 | cycle_list() { # cycle_list LIST DELIM | ||
115 | local list="${!1}" delim="$2" | ||
116 | local first="${list%%${delim}*}" | ||
117 | local rest="${list#*${delim}}" | ||
118 | printf -v "$1" '%s%s%s' "${rest}" "${delim}" "${first}" | ||
119 | } | ||
120 | |||
121 | # Determine the first element of a delimited list. | ||
122 | # | ||
123 | # e.g. 'first one,two,three' => 'one' | ||
124 | first() { # first LIST DELIM | ||
125 | local list="${!1}" delim="$2" | ||
126 | printf '%s\n' "${list%%${delim}*}" | ||
127 | } | ||
128 | |||
129 | # Log a message to stderr (&2). | ||
130 | # | ||
131 | # TODO: document | ||
132 | log() { # log LEVEL MESSAGE | ||
133 | [[ "$BOLLUX_LOGLEVEL" == QUIET ]] && return | ||
134 | local fmt | ||
135 | |||
136 | case "$1" in | ||
137 | ([dD]*) # debug | ||
138 | [[ "$BOLLUX_LOGLEVEL" == DEBUG ]] || return | ||
139 | fmt=34 | ||
140 | ;; | ||
141 | ([eE]*) # error | ||
142 | fmt=31 | ||
143 | ;; | ||
144 | (*) fmt=1 ;; | ||
145 | esac | ||
146 | shift | ||
147 | |||
148 | printf >&2 '\e[%sm%s:%s:\e[0m\t%s\n' "$fmt" "$PRGN" "${FUNCNAME[1]}" "$*" | ||
149 | } | ||
150 | |||
151 | # Set the terminal title. | ||
152 | set_title() { # set_title STRING | ||
153 | printf '\e]2;%s\007' "$*" | ||
154 | } | ||
155 | |||
156 | # Prompt the user for input. | ||
157 | # | ||
158 | # This is a thin wrapper around `read', a bash built-in. Because of the | ||
159 | # way bollux messes around with stein and stdout, I need to read directly from | ||
160 | # the TTY with this function. | ||
161 | prompt() { # prompt [-u] PROMPT [READ_ARGS...] | ||
162 | local read_cmd=(read -e -r) | ||
163 | if [[ "$1" == "-u" ]]; then | ||
164 | read_cmd+=(-i "$BOLLUX_URL") | ||
165 | shift | ||
166 | fi | ||
167 | local prompt="$1" | ||
168 | shift | ||
169 | read_cmd+=(-p "$prompt> ") | ||
170 | "${read_cmd[@]}" </dev/tty "$@" | ||
171 | } | ||
172 | |||
173 | |||
174 | # Bash built-in replacement for `cat' | ||
175 | # | ||
176 | # One of the more pedantic bits of bollux (is 'pedantic' the right word?) -- | ||
177 | # `cat' is more than likely installed on any system with bash, so this function | ||
178 | # is really just here so I can say that bollux is written as purely in bash as | ||
179 | # possible. | ||
180 | passthru() { | ||
181 | while IFS= read -r; do | ||
182 | printf '%s\n' "$REPLY" | ||
183 | done | ||
184 | } | ||
185 | |||
186 | # Bash built-in replacement for `sleep' | ||
187 | # | ||
188 | # The commentary for `passthru' applies here as well, though I didn't write this | ||
189 | # function -- Dylan Araps did. | ||
190 | # | ||
191 | # [1]: #use-read-as-an-alternative-to-the-sleep-command | ||
192 | sleep() { # sleep SECONDS | ||
193 | read -rt "$1" <> <(:) || : | ||
194 | } | ||
195 | |||
196 | # MAIN BOLLUX DISPATCH FUNCTIONS ############################################### | ||
197 | |||
198 | # Main entry point into `bollux'. | 72 | # Main entry point into `bollux'. |
199 | # | 73 | # |
200 | # See the `if' block at the bottom of this script. | 74 | # See the `if' block at the bottom of this script. |
@@ -251,10 +125,15 @@ bollux_config() { | |||
251 | 125 | ||
252 | if [ -f "$BOLLUX_CONFIG" ]; then | 126 | if [ -f "$BOLLUX_CONFIG" ]; then |
253 | log debug "Loading config file '$BOLLUX_CONFIG'" | 127 | log debug "Loading config file '$BOLLUX_CONFIG'" |
128 | # Shellcheck gets mad when we try to source a file behind a | ||
129 | # variable -- it doesn't know where it is. This line ignores | ||
130 | # that warning, since the user can put $BOLLUX_CONFIG wherever. | ||
254 | # shellcheck disable=1090 | 131 | # shellcheck disable=1090 |
255 | . "$BOLLUX_CONFIG" | 132 | . "$BOLLUX_CONFIG" |
256 | else | 133 | else |
257 | log debug "Can't load config file '$BOLLUX_CONFIG'." | 134 | # It's an error if bollux can't find the config file, but I |
135 | # don't want to kill the program over it. | ||
136 | log error "Can't load config file '$BOLLUX_CONFIG'." | ||
258 | fi | 137 | fi |
259 | 138 | ||
260 | ## behavior | 139 | ## behavior |
@@ -301,67 +180,173 @@ bollux_config() { | |||
301 | UC_BLANK=':?:' # internal use only, should be non-URL chars | 180 | UC_BLANK=':?:' # internal use only, should be non-URL chars |
302 | } | 181 | } |
303 | 182 | ||
304 | # Load a URL. | 183 | # Initialize bollux state |
184 | bollux_init() { | ||
185 | # Trap cleanup | ||
186 | trap bollux_cleanup INT QUIT EXIT | ||
187 | # State | ||
188 | REDIRECTS=0 | ||
189 | set -f | ||
190 | # History | ||
191 | declare -a HISTORY # history is kept in an array | ||
192 | HN=0 # position of history in the array | ||
193 | run mkdir -p "${BOLLUX_HISTFILE%/*}" | ||
194 | # Remove $BOLLUX_LESSKEY and re-generate keybindings (to catch rebinds) | ||
195 | run rm -f "$BOLLUX_LESSKEY" | ||
196 | mklesskey | ||
197 | } | ||
198 | |||
199 | # Cleanup on exit | ||
200 | bollux_cleanup() { | ||
201 | # Stubbed in case of need in future | ||
202 | : | ||
203 | } | ||
204 | |||
205 | # Exit with success, printing a fun message. | ||
305 | # | 206 | # |
306 | # I was feeling fancy when I named this function -- a more descriptive name | 207 | # The default message is from the wonderful show "Cowboy Bebop." |
307 | # would be 'bollux_goto' or something. | 208 | bollux_quit() { |
308 | blastoff() { # blastoff [-u] URL | 209 | bollux_cleanup |
309 | local u | 210 | printf '\e[1m%s\e[0m:\t\e[3m%s\e[0m\n' "$PRGN" "$BOLLUX_BYEMSG" |
211 | exit | ||
212 | } | ||
213 | # SIGINT is C-c, and I want to make sure bollux quits when it's typed. | ||
214 | trap bollux_quit SIGINT | ||
310 | 215 | ||
311 | # `blastoff' assumes a "well-formed" URL by default -- i.e., a URL with | 216 | # UTILITY FUNCTIONS ############################################################ |
312 | # a protocol string and no extraneous whitespace. Since bollux can't | 217 | |
313 | # trust the user to input a proper URL at a prompt, nor capsule authors | 218 | # Run a command, but log it first. |
314 | # to fully-form their URLs, so the -u flag is necessary for those | 219 | # |
315 | # use-cases. Otherwise, bollux knows the URL is well-formed -- or | 220 | # See `log' for the available levels. |
316 | # should be, due to the Gemini specification. | 221 | run() { # run COMMAND... |
222 | # I have to add a `trap' here for SIGINT to work properly. | ||
223 | trap bollux_quit SIGINT | ||
224 | log debug "$*" | ||
225 | "$@" | ||
226 | } | ||
227 | |||
228 | |||
229 | # Log a message to stderr (&2). | ||
230 | # | ||
231 | # `log' in this script can take 3 different parameters: `d', `e', and `x', where | ||
232 | # `x' is any other string (though I usually use `x'), followed by the message to | ||
233 | # log. Most messages are either `d' (debug) level or `x' (diagnostic) level, | ||
234 | # meaning I want to show them all the time or only when bollux is called with | ||
235 | # `-v' (verbose). The levels are somewhat arbitrary, like I suspect all logging | ||
236 | # levels are, but you can read the rest of bollux to see what I've chosen to | ||
237 | # classify as what. | ||
238 | log() { # log LEVEL MESSAGE... | ||
239 | # 'QUIET' means don't log anything. | ||
240 | [[ "$BOLLUX_LOGLEVEL" == QUIET ]] && return | ||
241 | local fmt # ANSI escape code | ||
242 | |||
243 | case "$1" in | ||
244 | ([dD]*) # Debug level -- only print if bollux -v. | ||
245 | [[ "$BOLLUX_LOGLEVEL" == DEBUG ]] || return | ||
246 | fmt=34 # Blue | ||
247 | ;; | ||
248 | ([eE]*) # Error level -- always print. | ||
249 | fmt=31 # Red | ||
250 | ;; | ||
251 | (*) # Diagnostic level -- print unless QUIET. | ||
252 | fmt=1 # Bold | ||
253 | ;; | ||
254 | esac | ||
255 | shift | ||
256 | |||
257 | printf >&2 '\e[%sm%s:%s:\e[0m\t%s\n' \ | ||
258 | "$fmt" "$PRGN" "${FUNCNAME[1]}" "$*" | ||
259 | } | ||
260 | |||
261 | # Exit with an error and a message describing it. | ||
262 | die() { # die EXIT_CODE MESSAGE | ||
263 | local exit_code="$1" | ||
264 | shift | ||
265 | log error "$*" | ||
266 | exit "$exit_code" | ||
267 | } | ||
268 | |||
269 | # Trim leading and trailing whitespace from a string. | ||
270 | # | ||
271 | # [1]: #trim-leading-and-trailing-white-space-from-string | ||
272 | trim_string() { # trim_string STRING | ||
273 | : "${1#"${1%%[![:space:]]*}"}" | ||
274 | : "${_%"${_##*[![:space:]]}"}" | ||
275 | printf '%s\n' "$_" | ||
276 | } | ||
277 | |||
278 | # Cycle a variable in a list given a delimiter. | ||
279 | # | ||
280 | # e.g. 'list_cycle one,two,three ,' => 'two,three,one' | ||
281 | list_cycle() { # list_cycle LIST<string> DELIM | ||
282 | # I could've set up `list_cycle' to use an array instead of a delimited | ||
283 | # string, but the one variable this function is used for is | ||
284 | # T_PRE_DISPLAY, which is user-configurable. I wanted it to be as easy | ||
285 | # to configure for users who might not immediately know the bash array | ||
286 | # syntax, but can figure out 'variable=value' without much thought. | ||
287 | local list="${!1}" # Pass the list by name, not value | ||
288 | local delim="$2" # The delimiter of the string | ||
289 | local first="${list%%${delim}*}" # The first element | ||
290 | local rest="${list#*${delim}}" # The rest of the elements | ||
291 | # -v prints to the variable specified. | ||
292 | printf -v "$1" '%s%s%s' "${rest}" "${delim}" "${first}" | ||
293 | } | ||
294 | |||
295 | # Set the terminal title. | ||
296 | set_title() { # set_title TITLE... | ||
297 | printf '\e]2;%s\007' "$*" | ||
298 | } | ||
299 | |||
300 | # Prompt the user for input. | ||
301 | # | ||
302 | # This is a thin wrapper around `read', a bash built-in. Because of the | ||
303 | # way bollux messes around with stdin and stdout, I need to read directly from | ||
304 | # the TTY with this function. | ||
305 | prompt() { # prompt [-u] PROMPT [READ_ARGS...] | ||
306 | # `-e' gets the line "interactively", so it can see history and stuff | ||
307 | # `-r' reads a "raw" string, i.e., without backslash escaping | ||
308 | local read_cmd=(read -e -r) | ||
317 | if [[ "$1" == "-u" ]]; then | 309 | if [[ "$1" == "-u" ]]; then |
318 | u="$(run uwellform "$2")" | 310 | # `-i TEXT' uses TEXT as the initial text for `read' |
319 | else | 311 | read_cmd+=(-i "$BOLLUX_URL") |
320 | u="$1" | 312 | shift |
321 | fi | 313 | fi |
314 | local prompt="$1" # How to prompt the user | ||
315 | shift | ||
316 | read_cmd+=(-p "$prompt> ") | ||
317 | "${read_cmd[@]}" </dev/tty "$@" | ||
318 | } | ||
322 | 319 | ||
323 | # After ensuring the URL is well-formed, `blastoff' needs to transform | 320 | # Bash built-in replacement for `cat' |
324 | # it according to the transform rules of RFC 3986 (see §5.2.2), which | 321 | # |
325 | # turns relative references into absolute references that bollux can use | 322 | # One of the more pedantic bits of bollux (is 'pedantic' the right word?) -- |
326 | # in its request to the server. That's followed by a check that the | 323 | # `cat' is more than likely installed on any system with bash, so this function |
327 | # protocol is set, defaulting to Gemini if it isn't. | 324 | # is really just here so I can say that bollux is written as purely in bash as |
328 | # | 325 | # possible. |
329 | # Implementation detail: because Bash is really stupid when it comes to | 326 | passthru() { |
330 | # arrays, the URL functions u* (see below) work with an array defined | 327 | while IFS= read -r; do |
331 | # with `local -a' and passed by name, not by value. Thus, the | 328 | printf '%s\n' "$REPLY" |
332 | # `urltransform url ...' instead of `urltransform "${url[@]}"' or | 329 | done |
333 | # similar. In addition, the `ucdef' and `ucset' functions take the name | 330 | } |
334 | # of the array element as parameters, not the element itself. | ||
335 | local -a url | ||
336 | run utransform url "$BOLLUX_URL" "$u" | ||
337 | if ! ucdef url[1]; then | ||
338 | run ucset url[1] "$BOLLUX_PROTO" | ||
339 | fi | ||
340 | 331 | ||
341 | # To try and keep `bollux' as extensible as possible, I've written it | 332 | # Bash built-in replacement for `sleep' |
342 | # only to expect two functions for every protocol it supports: | 333 | # |
343 | # `x_request' and `x_response', where `x' is the name of the protocol | 334 | # The commentary for `passthru' applies here as well, though I didn't write this |
344 | # (the first element of the built `url' array). `declare -F' looks only | 335 | # function -- Dylan Araps did. |
345 | # for functions in the current scope, failing if it doesn't exist. | 336 | # |
346 | # | 337 | # [1]: #use-read-as-an-alternative-to-the-sleep-command |
347 | # In between `x_request' and `x_response', `blastoff' normalizes the | 338 | sleep() { # sleep SECONDS |
348 | # line endings to UNIX-style (LF) for ease of display. | 339 | read -rt "$1" <> <(:) || : |
349 | { | 340 | } |
350 | if declare -F "${url[1]}_request" >/dev/null 2>&1; then | 341 | |
351 | run "${url[1]}_request" "$url" | 342 | # Normalize files. |
352 | else | 343 | normalize() { |
353 | die 99 "No request handler for '${url[1]}'" | 344 | shopt -s extglob |
354 | fi | 345 | while IFS= read -r; do |
355 | } | run normalize | { | 346 | # Normalize line endings to Unix-style (LF) |
356 | if declare -F "${url[1]}_response" >/dev/null 2>&1; then | 347 | printf '%s\n' "${REPLY//$'\r'?($'\n')/}" |
357 | run "${url[1]}_response" "$url" | 348 | done |
358 | else | 349 | shopt -u extglob |
359 | log d \ | ||
360 | "No response handler for '${url[1]}';" \ | ||
361 | " passing thru" | ||
362 | passthru | ||
363 | fi | ||
364 | } | ||
365 | } | 350 | } |
366 | 351 | ||
367 | # URLS ######################################################################### | 352 | # URLS ######################################################################### |
@@ -1156,16 +1141,6 @@ END | |||
1156 | fi | 1141 | fi |
1157 | } | 1142 | } |
1158 | 1143 | ||
1159 | # normalize files | ||
1160 | normalize() { | ||
1161 | shopt -s extglob | ||
1162 | while IFS= read -r; do | ||
1163 | # normalize line endings | ||
1164 | printf '%s\n' "${REPLY//$'\r'?($'\n')/}" | ||
1165 | done | ||
1166 | shopt -u extglob | ||
1167 | } | ||
1168 | |||
1169 | # typeset a text/gemini document | 1144 | # typeset a text/gemini document |
1170 | typeset_gemini() { | 1145 | typeset_gemini() { |
1171 | local pre=false | 1146 | local pre=false |
@@ -1411,7 +1386,7 @@ handle_keypress() { # handle_keypress CODE | |||
1411 | run blastoff -u "$REPLY" | 1386 | run blastoff -u "$REPLY" |
1412 | ;; | 1387 | ;; |
1413 | (54) # ` - change alt-text visibility and refresh | 1388 | (54) # ` - change alt-text visibility and refresh |
1414 | run cycle_list T_PRE_DISPLAY , | 1389 | run list_cycle T_PRE_DISPLAY , |
1415 | run blastoff "$BOLLUX_URL" | 1390 | run blastoff "$BOLLUX_URL" |
1416 | ;; | 1391 | ;; |
1417 | (55) # 55-57 -- still available for binding | 1392 | (55) # 55-57 -- still available for binding |
@@ -1472,28 +1447,6 @@ download() { | |||
1472 | fi | 1447 | fi |
1473 | } | 1448 | } |
1474 | 1449 | ||
1475 | # initialize bollux | ||
1476 | bollux_init() { | ||
1477 | # Trap cleanup | ||
1478 | trap bollux_cleanup INT QUIT EXIT | ||
1479 | # State | ||
1480 | REDIRECTS=0 | ||
1481 | set -f | ||
1482 | # History | ||
1483 | declare -a HISTORY # history is kept in an array | ||
1484 | HN=0 # position of history in the array | ||
1485 | run mkdir -p "${BOLLUX_HISTFILE%/*}" | ||
1486 | # Remove $BOLLUX_LESSKEY and re-generate keybindings (to catch rebinds) | ||
1487 | run rm -f "$BOLLUX_LESSKEY" | ||
1488 | mklesskey | ||
1489 | } | ||
1490 | |||
1491 | # clean up on exit | ||
1492 | bollux_cleanup() { | ||
1493 | # Stubbed in case of need in future | ||
1494 | : | ||
1495 | } | ||
1496 | |||
1497 | # append a URL to history | 1450 | # append a URL to history |
1498 | history_append() { # history_append URL TITLE | 1451 | history_append() { # history_append URL TITLE |
1499 | BOLLUX_URL="$1" | 1452 | BOLLUX_URL="$1" |
@@ -1526,6 +1479,69 @@ history_forward() { | |||
1526 | run blastoff "${HISTORY[$HN]}" | 1479 | run blastoff "${HISTORY[$HN]}" |
1527 | } | 1480 | } |
1528 | 1481 | ||
1482 | # Load a URL. | ||
1483 | # | ||
1484 | # I was feeling fancy when I named this function -- a more descriptive name | ||
1485 | # would be 'bollux_goto' or something. | ||
1486 | blastoff() { # blastoff [-u] URL | ||
1487 | local u | ||
1488 | |||
1489 | # `blastoff' assumes a "well-formed" URL by default -- i.e., a URL with | ||
1490 | # a protocol string and no extraneous whitespace. Since bollux can't | ||
1491 | # trust the user to input a proper URL at a prompt, nor capsule authors | ||
1492 | # to fully-form their URLs, so the -u flag is necessary for those | ||
1493 | # use-cases. Otherwise, bollux knows the URL is well-formed -- or | ||
1494 | # should be, due to the Gemini specification. | ||
1495 | if [[ "$1" == "-u" ]]; then | ||
1496 | u="$(run uwellform "$2")" | ||
1497 | else | ||
1498 | u="$1" | ||
1499 | fi | ||
1500 | |||
1501 | # After ensuring the URL is well-formed, `blastoff' needs to transform | ||
1502 | # it according to the transform rules of RFC 3986 (see §5.2.2), which | ||
1503 | # turns relative references into absolute references that bollux can use | ||
1504 | # in its request to the server. That's followed by a check that the | ||
1505 | # protocol is set, defaulting to Gemini if it isn't. | ||
1506 | # | ||
1507 | # Implementation detail: because Bash is really stupid when it comes to | ||
1508 | # arrays, the URL functions u* (see below) work with an array defined | ||
1509 | # with `local -a' and passed by name, not by value. Thus, the | ||
1510 | # `urltransform url ...' instead of `urltransform "${url[@]}"' or | ||
1511 | # similar. In addition, the `ucdef' and `ucset' functions take the name | ||
1512 | # of the array element as parameters, not the element itself. | ||
1513 | local -a url | ||
1514 | run utransform url "$BOLLUX_URL" "$u" | ||
1515 | if ! ucdef url[1]; then | ||
1516 | run ucset url[1] "$BOLLUX_PROTO" | ||
1517 | fi | ||
1518 | |||
1519 | # To try and keep `bollux' as extensible as possible, I've written it | ||
1520 | # only to expect two functions for every protocol it supports: | ||
1521 | # `x_request' and `x_response', where `x' is the name of the protocol | ||
1522 | # (the first element of the built `url' array). `declare -F' looks only | ||
1523 | # for functions in the current scope, failing if it doesn't exist. | ||
1524 | # | ||
1525 | # In between `x_request' and `x_response', `blastoff' normalizes the | ||
1526 | # line endings to UNIX-style (LF) for ease of display. | ||
1527 | { | ||
1528 | if declare -F "${url[1]}_request" >/dev/null 2>&1; then | ||
1529 | run "${url[1]}_request" "$url" | ||
1530 | else | ||
1531 | die 99 "No request handler for '${url[1]}'" | ||
1532 | fi | ||
1533 | } | run normalize | { | ||
1534 | if declare -F "${url[1]}_response" >/dev/null 2>&1; then | ||
1535 | run "${url[1]}_response" "$url" | ||
1536 | else | ||
1537 | log d \ | ||
1538 | "No response handler for '${url[1]}';" \ | ||
1539 | " passing thru" | ||
1540 | passthru | ||
1541 | fi | ||
1542 | } | ||
1543 | } | ||
1544 | |||
1529 | if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then | 1545 | if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then |
1530 | ${DEBUG:-false} && set -x | 1546 | ${DEBUG:-false} && set -x |
1531 | run bollux "$@" | 1547 | run bollux "$@" |