Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/bats/helpers
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ test_printf() {
printf "$@" >&2
fi
}
export -f test_printf

# Skips a test if `TEST_FILTER` is set but doesn't match `BATS_TEST_DESCRIPTION`
#
Expand Down
106 changes: 71 additions & 35 deletions lib/format
Original file line number Diff line number Diff line change
Expand Up @@ -3,77 +3,113 @@
# Text formatting utilities
#
# Exports:
# @go.array_printf
# Assigns `printf` transformations of its arguments to an array
#
# @go.pad_items
# Pads each string in an array to match the length of the longest element
# Right-pads each string with spaces to match the length of the longest
#
# @go.zip_items
# Concatenates parallel elements from each input array
#
# @go.strip_formatting_codes
# Strips ANSI escape codes of the form `\e[...(;...)m` from a string

# Pads each string in an array to match the length of the longest element
. "$_GO_USE_MODULES" 'strings' 'validation'

# Assigns `printf` transformations of its arguments to an array
#
# Since `printf -v` can't print to an array subscript prior to Bash 4.1, this
# provides a portable means of printing to an array variable while avoiding the
# use of `eval`.
#
# NOTE: By default, this function relies on the ASCII Record Separator character
# ($'\x1f') to delimit generated strings before splitting them into the result
# array. If you have strings containing this character, you can set a new
# delimiter via `_GO_ARRAY_PRINTF_DELIMITER`.
#
# Globals:
# _GO_ARRAY_PRINTF_DELIMITER:
# If set, used to separate generated strings prior to array assignment
#
# Arguments:
# result: Name of the caller-declared output array
# format: `printf`-style format specification
# ...: Items to pass to `printf` and store in `result`
@go.array_printf() {
@go.validate_identifier_or_die 'Result array name' "$1"
local __go_array_printf_delim="${_GO_ARRAY_PRINTF_DELIMITER:-$'\x1f'}"
local __tmp_go_array_printf
printf -v __tmp_go_array_printf -- "${2}${__go_array_printf_delim}" "${@:3}"
@go.split "$__go_array_printf_delim" "$__tmp_go_array_printf" "$1"
}

# Right-pads each string with spaces to match the length of the longest
#
# Globals:
# _GO_ARRAY_PRINTF_DELIMITER: See the comments for `@go.array_printf`
#
# Arguments:
# $1: Name of the input array in the caller's scope
# Outputs:
# __go_padded_result: The caller-declared array to which results are assigned
# result: Name of the caller-declared output array
# ...: Items to right-pad with spaces to match the longest one
@go.pad_items() {
local items_reference=("${1}[@]")
local item
local padding=''
local padding_len=0
@go.validate_identifier_or_die 'Result array name' "$1"
local __go_pad_items_items=("${@:2}")
local __item
local padding_size=0

for item in "${!items_reference}"; do
while [[ "${#padding}" -lt "${#item}" ]]; do
padding+=' '
for __item in "${__go_pad_items_items[@]}"; do
while [[ "$padding_size" -lt "${#__item}" ]]; do
padding_size="${#__item}"
done
done

for item in "${!items_reference}"; do
padding_len="$((${#padding} - ${#item}))"
__go_padded_result+=("${item}${padding:0:padding_len}")
done
@go.array_printf "$1" "%-${padding_size}s" "${__go_pad_items_items[@]}"
}

# Concatenates parallel elements from each input array
#
# Will produce a number of results matching that of the left-hand input array.
#
# Globals:
# _GO_ARRAY_PRINTF_DELIMITER: See the comments for `@go.array_printf`
#
# Arguments:
# $1: Name of the left-hand input array in the caller's scope
# $2: Name of the right-hand input array in the caller's scope
# $3: The string used as a delimiter between elements (defaults to two spaces)
# Outputs:
# __go_zipped_result: The caller-declared array to which results are assigned
# lhs: Name of the left-hand input array in the caller's scope
# rhs: Name of the right-hand input array in the caller's scope
# delim: String used as a delimiter between elements (default: two spaces)
# result: Name of the caller-declared output array
@go.zip_items() {
@go.validate_identifier_or_die 'Result array name' "$4"
local lhs_array_reference="${1}[@]"
local rhs_reference="$2"
local delimiter="${3:- }"
local rhs_item_ref
local item
local i=-1
local i=0
local __tmp_go_zip_items_result=()

for item in "${!lhs_array_reference}"; do
rhs_item_ref="${rhs_reference}[$((++i))]"
__go_zipped_result+=("${item}${delimiter}${!rhs_item_ref}")
rhs_item_ref="${2}[$((i++))]"
__tmp_go_zip_items_result+=("${item}${3}${!rhs_item_ref}")
done
@go.array_printf "$4" '%s' "${__tmp_go_zip_items_result[@]}"
}

# Strips ANSI escape codes of the form `\e[...(;...)m` from a string
# Strips ANSI escape codes from a string
#
# Used primarily by `@go.log`.
#
# Arguments:
# $1: The string to strip
# Outputs:
# __go_stripped_value: The caller-declared variable for the stripped result
# original: The string to strip
# result: Name of the caller-declared output variable
@go.strip_formatting_codes() {
__go_stripped_value="$1"
local format_pattern='\\e\[[0-9]{1,3}(;[0-9]{1,3})*m'
@go.validate_identifier_or_die 'Result variable name' "$2"
printf -v "$2" -- '%b' "$1"

if [[ -z "$__GO_STRIP_FORMATTING_PATTERN" ]]; then
printf -v __GO_STRIP_FORMATTING_PATTERN '%b' '\e[[0-9]{1,3}(;[0-9]{1,3})*m'
readonly __GO_STRIP_FORMATTING_PATTERN
fi

while [[ "$__go_stripped_value" =~ $format_pattern ]]; do
__go_stripped_value="${__go_stripped_value/"${BASH_REMATCH[0]}"}"
while [[ "${!2}" =~ $__GO_STRIP_FORMATTING_PATTERN ]]; do
printf -v "$2" -- '%s' "${!2/"${BASH_REMATCH[0]}"}"
done
}
8 changes: 4 additions & 4 deletions lib/log
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ readonly __GO_LOG_COMMAND_EXIT_PATTERN='^@go.log_command (exit|fatal):([0-9]+)$'
local log_level="${args[0]^^}"
local exit_status=0
local log_msg
local __go_stripped_value
local stripped_log_msg
local level_fd

unset 'args[0]'
Expand Down Expand Up @@ -266,10 +266,10 @@ readonly __GO_LOG_COMMAND_EXIT_PATTERN='^@go.log_command (exit|fatal):([0-9]+)$'
_@go.log_command_should_skip_file_descriptor "$level_fd"; then
continue
elif [[ ! -t "$level_fd" && -z "$_GO_LOG_FORMATTING" ]]; then
if [[ -z "$__go_stripped_value" ]]; then
@go.strip_formatting_codes "$log_msg"
if [[ -z "$stripped_log_msg" ]]; then
@go.strip_formatting_codes "$log_msg" 'stripped_log_msg'
fi
printf '%s\n' "$__go_stripped_value" >&"$level_fd"
printf '%s\n' "$stripped_log_msg" >&"$level_fd"
else
printf '%b\n' "$log_msg" >&"$level_fd"
fi
Expand Down
14 changes: 7 additions & 7 deletions libexec/modules
Original file line number Diff line number Diff line change
Expand Up @@ -151,31 +151,31 @@ _@go.modules_produce_listing() {

. "$_GO_CORE_DIR/lib/format"

local __go_padded_result=()
local __go_zipped_result=()
local padded_modules=()
local zipped_modules=()

@go.pad_items 'modules'
modules=("${__go_padded_result[@]}")
@go.pad_items padded_modules "${modules[@]}"
modules=("${padded_modules[@]}")

case "$action" in
paths)
local relative_paths=("${__go_modules[@]#$_GO_ROOTDIR/}")
@go.zip_items 'modules' 'relative_paths'
@go.zip_items modules relative_paths ' ' zipped_modules
;;
summaries)
local __go_modules_summaries=()
if ! _@go.modules_summaries; then
return 1
fi
@go.zip_items 'modules' '__go_modules_summaries'
@go.zip_items modules __go_modules_summaries ' ' zipped_modules
;;
*)
# Should only happen if _@go.modules is updated and this case statement
# isn't.
@go.printf 'ERROR: Unknown action: %s\n' "$action" >&2
return 1
esac
__go_modules_listing=("${__go_zipped_result[@]}")
__go_modules_listing=("${zipped_modules[@]}")
}

_@go.modules_search() {
Expand Down
1 change: 0 additions & 1 deletion tests/bats-helpers.bats
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ teardown() {

@test "$SUITE: test_printf" {
create_bats_test_script test-script \
". '$_GO_CORE_DIR/lib/bats/helpers'" \
"test_printf '%s\n' 'some test debug output'"

run "$BATS_TEST_ROOTDIR/test-script"
Expand Down
Loading