mirror of
https://github.com/denisidoro/navi.git
synced 2024-11-12 22:34:38 +03:00
parent
13ddc7c226
commit
6129d9e954
2
navi
2
navi
@ -37,7 +37,7 @@ source "${SCRIPT_DIR}/src/main.sh"
|
||||
##? full docs
|
||||
##? Please refer to the README at https://github.com/denisidoro/navi
|
||||
|
||||
VERSION="0.11.1"
|
||||
VERSION="0.12.0"
|
||||
NAVI_ENV="${NAVI_ENV:-prod}"
|
||||
|
||||
opts::eval "$@"
|
||||
|
35
src/arg.sh
35
src/arg.sh
@ -1,13 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
ARG_REGEX_WITHOUT_BRACKETS="[a-zA-Z_]+([- ]?\w+)*"
|
||||
ARG_REGEX="<${ARG_REGEX_WITHOUT_BRACKETS}>"
|
||||
ARG_DELIMITER="\f"
|
||||
ARG_DELIMITER_2="\v"
|
||||
ARG_DELIMITER_3="\r"
|
||||
ARG_REGEX="<[a-zA-Z_]+([- ]?\w+)*>"
|
||||
|
||||
arg::dict() {
|
||||
local -r input="$(cat | sed 's/\\n/\\f/g')"
|
||||
local -r input="$(cat)"
|
||||
|
||||
local -r fn="$(echo "$input" | awk -F'---' '{print $1}')"
|
||||
local -r opts="$(echo "$input" | awk -F'---' '{print $2}')"
|
||||
@ -15,6 +11,12 @@ arg::dict() {
|
||||
dict::new fn "$fn" opts "$opts"
|
||||
}
|
||||
|
||||
arg::escape() {
|
||||
echo "$*" \
|
||||
| tr '-' '_' \
|
||||
| tr ' ' '_'
|
||||
}
|
||||
|
||||
arg::interpolate() {
|
||||
local -r arg="$1"
|
||||
local -r value="$2"
|
||||
@ -40,12 +42,19 @@ arg::deserialize() {
|
||||
|
||||
arg="${arg:1:${#arg}-2}"
|
||||
echo "$arg" \
|
||||
| tr "${ARG_DELIMITER}" " " \
|
||||
| tr "${ARG_DELIMITER_2}" "'" \
|
||||
| tr "${ARG_DELIMITER_3}" '"'
|
||||
| tr "${ESCAPE_CHAR}" " " \
|
||||
| tr "${ESCAPE_CHAR_2}" "'" \
|
||||
| tr "${ESCAPE_CHAR_3}" '"'
|
||||
}
|
||||
|
||||
arg::serialize_code() {
|
||||
printf "tr ' ' '${ESCAPE_CHAR}'"
|
||||
printf " | "
|
||||
printf "tr \"'\" '${ESCAPE_CHAR_2}'"
|
||||
printf " | "
|
||||
printf "tr '\"' '${ESCAPE_CHAR_3}'"
|
||||
}
|
||||
|
||||
# TODO: separation of concerns
|
||||
arg::pick() {
|
||||
local -r arg="$1"
|
||||
local -r cheat="$2"
|
||||
@ -54,7 +63,7 @@ arg::pick() {
|
||||
local -r length="$(echo "$prefix" | str::length)"
|
||||
local -r arg_dict="$(echo "$cheat" | grep "$prefix" | str::sub $((length + 1)) | arg::dict)"
|
||||
|
||||
local -r fn="$(dict::get "$arg_dict" fn | sed 's/\\f/\\n/g')"
|
||||
local -r fn="$(dict::get "$arg_dict" fn)"
|
||||
local -r args_str="$(dict::get "$arg_dict" opts)"
|
||||
local arg_name=""
|
||||
|
||||
@ -70,10 +79,10 @@ arg::pick() {
|
||||
if [ -n "$fn" ]; then
|
||||
local suggestions="$(eval "$fn" 2>/dev/null)"
|
||||
if [ -n "$suggestions" ]; then
|
||||
echo "$suggestions" | ui::pick --prompt "$arg: " --header-lines "${headers:-0}" | str::column "${column:-}"
|
||||
echo "$suggestions" | ui::fzf --prompt "$arg: " --header-lines "${headers:-0}" | str::column "${column:-}"
|
||||
fi
|
||||
elif ${NAVI_USE_FZF_ALL_INPUTS:-false}; then
|
||||
echo "" | ui::pick --prompt "$arg: " --print-query --no-select-1 --height 1
|
||||
echo "" | ui::fzf --prompt "$arg: " --print-query --no-select-1 --height 1
|
||||
else
|
||||
printf "\033[0;36m${arg}:\033[0;0m " > /dev/tty
|
||||
read -r value
|
||||
|
37
src/cheat.sh
37
src/cheat.sh
@ -6,25 +6,26 @@ cheat::find() {
|
||||
done
|
||||
}
|
||||
|
||||
cheat::_join_multiline_using_sed() {
|
||||
tr '\n' '\f' \
|
||||
| sed -E 's/\\\f *//g' \
|
||||
| tr '\f' '\n'
|
||||
cheat::export_cache() {
|
||||
if [ -z "${NAVI_CACHE:-}" ]; then
|
||||
export NAVI_CACHE="$*"
|
||||
fi
|
||||
}
|
||||
|
||||
cheat::_join_multiline() {
|
||||
if ${NAVI_USE_PERL:-false}; then
|
||||
perl -0pe 's/\\\n *//g' \
|
||||
|| cheat::_join_multiline_using_sed
|
||||
cheat::join_lines() {
|
||||
if command_exists perl; then
|
||||
perl -0pe 's/\\\n *//g'
|
||||
else
|
||||
cheat::_join_multiline_using_sed
|
||||
tr '\n' "$ESCAPE_CHAR" \
|
||||
| sed -E 's/\\'$(printf "$ESCAPE_CHAR")' *//g' \
|
||||
| tr "$ESCAPE_CHAR" '\n'
|
||||
fi
|
||||
}
|
||||
|
||||
cheat::read_all() {
|
||||
for cheat in $(cheat::find); do
|
||||
echo
|
||||
cat "$cheat" | cheat::_join_multiline
|
||||
cat "$cheat"
|
||||
echo
|
||||
done
|
||||
}
|
||||
@ -34,16 +35,13 @@ cheat::memoized_read_all() {
|
||||
echo "$NAVI_CACHE"
|
||||
return
|
||||
fi
|
||||
if command_exists perl; then
|
||||
export NAVI_USE_PERL=true
|
||||
else
|
||||
export NAVI_USE_PERL=false
|
||||
fi
|
||||
|
||||
local -r cheats="$(cheat::read_all)"
|
||||
echo "$cheats"
|
||||
echo "$cheats" \
|
||||
| cheat::join_lines
|
||||
}
|
||||
|
||||
cheat::pretty() {
|
||||
cheat::prettify() {
|
||||
awk 'function color(c,s) {
|
||||
printf("\033[%dm%s\033[0m",30+c,s)
|
||||
}
|
||||
@ -54,7 +52,7 @@ cheat::pretty() {
|
||||
NF { print color(7, $0) color(60, tags); next }'
|
||||
}
|
||||
|
||||
cheat::_until_percentage() {
|
||||
cheat::until_percentage() {
|
||||
awk 'BEGIN { count=0; }
|
||||
|
||||
/^%/ { if (count >= 1) exit;
|
||||
@ -70,6 +68,5 @@ cheat::from_selection() {
|
||||
|
||||
echo "$cheats" \
|
||||
| grep "% ${tags}" -A99999 \
|
||||
| cheat::_until_percentage \
|
||||
|| (echoerr "No valid cheatsheet!"; exit 67)
|
||||
| cheat::until_percentage
|
||||
}
|
||||
|
41
src/cmd.sh
Normal file
41
src/cmd.sh
Normal file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cmd::loop() {
|
||||
local -r cmd="$1"
|
||||
local -r cheat="$2"
|
||||
|
||||
local arg escaped_arg value escaped_cmd
|
||||
|
||||
arg="$(echo "$cmd" | arg::next)"
|
||||
if [ -z "$arg" ]; then
|
||||
dict::new cmd "$cmd"
|
||||
return
|
||||
fi
|
||||
|
||||
escaped_arg="$(arg::escape "$arg")"
|
||||
|
||||
escaped_cmd="$(echo "$cmd" | sed "s|<${arg}>|<${escaped_arg}>|g")"
|
||||
arg="$escaped_arg"
|
||||
|
||||
local -r values="$(dict::get "$OPTIONS" values)"
|
||||
value="$(echo "$values" | coll::get $i)"
|
||||
[ -z "$value" ] && value="$(arg::pick "$arg" "$cheat")"
|
||||
|
||||
dict::new \
|
||||
cmd "${escaped_cmd:-}" \
|
||||
value "$value" \
|
||||
arg "$arg"
|
||||
}
|
||||
|
||||
cmd::finish() {
|
||||
local -r cmd="$1"
|
||||
|
||||
local -r unresolved_arg="$(echo "$cmd" | arg::next)"
|
||||
|
||||
local -r print="$(dict::get "$OPTIONS" print)"
|
||||
if $print || [ -n "$unresolved_arg" ]; then
|
||||
echo "$cmd"
|
||||
else
|
||||
eval "$cmd"
|
||||
fi
|
||||
}
|
@ -38,7 +38,7 @@ coll::remove() {
|
||||
done
|
||||
}
|
||||
|
||||
coll::_without_empty_line() {
|
||||
coll::without_empty_line() {
|
||||
local -r input="$(cat)"
|
||||
local -r words="$(echo "$input" | wc -w | xargs)"
|
||||
if [[ $words > 0 ]]; then
|
||||
@ -47,7 +47,7 @@ coll::_without_empty_line() {
|
||||
}
|
||||
|
||||
coll::add() {
|
||||
cat | coll::_without_empty_line
|
||||
cat | coll::without_empty_line
|
||||
for x in "$@"; do
|
||||
echo "$x"
|
||||
done
|
||||
|
27
src/dict.sh
27
src/dict.sh
@ -7,13 +7,11 @@
|
||||
# values with non-trivial whitespaces (newlines, subsequent spaces, etc)
|
||||
# aren't handled very well
|
||||
|
||||
DICT_DELIMITER='\f'
|
||||
|
||||
dict::new() {
|
||||
if [ $# = 0 ]; then
|
||||
echo ""
|
||||
else
|
||||
echo "" | dict::assoc "$@" | sed '/^$/d'
|
||||
echo "" | dict::assoc "$@" | str::remove_empty_lines
|
||||
fi
|
||||
}
|
||||
|
||||
@ -23,17 +21,17 @@ dict::dissoc() {
|
||||
grep -Ev "^[\s]*${key}[^:]*:"
|
||||
}
|
||||
|
||||
dict::_escape_value() {
|
||||
tr '\n' "$DICT_DELIMITER" | sed "s/\\n/${DICT_DELIMITER}/g"
|
||||
dict::escape_value() {
|
||||
tr '\n' "$ESCAPE_CHAR" | sed 's/\\n/'$(printf "$ESCAPE_CHAR")'/g'
|
||||
}
|
||||
|
||||
str::_without_trailing_newline() {
|
||||
str::without_trailing_newline() {
|
||||
printf "%s" "$(cat)"
|
||||
echo
|
||||
}
|
||||
|
||||
dict::_unescape_value() {
|
||||
tr "$DICT_DELIMITER" '\n' | str::_without_trailing_newline
|
||||
dict::unescape_value() {
|
||||
tr "$ESCAPE_CHAR" '\n' | str::without_trailing_newline
|
||||
}
|
||||
|
||||
dict::assoc() {
|
||||
@ -41,11 +39,11 @@ dict::assoc() {
|
||||
local -r input="$(cat)"
|
||||
|
||||
if [ -z $key ]; then
|
||||
printf "$(echo "$input" | tr '%' '\v')" | tr '\v' '%'
|
||||
printf "$(echo "$input" | tr '%' "$ESCAPE_CHAR_2")" | tr "$ESCAPE_CHAR_2" '%'
|
||||
return
|
||||
fi
|
||||
|
||||
local -r value="$(echo "${2:-}" | dict::_escape_value)"
|
||||
local -r value="$(echo "${2:-}" | dict::escape_value)"
|
||||
|
||||
shift 2
|
||||
echo "$(echo "$input" | dict::dissoc "$key")${key}: ${value}\n" | dict::assoc "$@"
|
||||
@ -65,9 +63,9 @@ dict::get() {
|
||||
local -r matches="$(echo "$result" | wc -l || echo 0)"
|
||||
|
||||
if [ $matches -gt 1 ]; then
|
||||
echo "$result" | dict::_unescape_value
|
||||
echo "$result" | dict::unescape_value
|
||||
else
|
||||
echo "$result" | sed -E "s/${prefix}//" | dict::_unescape_value
|
||||
echo "$result" | sed -E "s/${prefix}//" | dict::unescape_value
|
||||
fi
|
||||
}
|
||||
|
||||
@ -81,11 +79,6 @@ dict::values() {
|
||||
| cut -c3-
|
||||
}
|
||||
|
||||
dict::merge() {
|
||||
awk -F':' '{$1=""; print $0}' \
|
||||
| cut -c3-
|
||||
}
|
||||
|
||||
dict::zipmap() {
|
||||
IFS='\n'
|
||||
|
||||
|
77
src/main.sh
77
src/main.sh
@ -6,6 +6,7 @@ fi
|
||||
|
||||
source "${SCRIPT_DIR}/src/arg.sh"
|
||||
source "${SCRIPT_DIR}/src/cheat.sh"
|
||||
source "${SCRIPT_DIR}/src/cmd.sh"
|
||||
source "${SCRIPT_DIR}/src/coll.sh"
|
||||
source "${SCRIPT_DIR}/src/dict.sh"
|
||||
source "${SCRIPT_DIR}/src/health.sh"
|
||||
@ -18,44 +19,25 @@ source "${SCRIPT_DIR}/src/ui.sh"
|
||||
|
||||
handler::main() {
|
||||
local -r cheats="$(cheat::memoized_read_all)"
|
||||
|
||||
if [ -z "${NAVI_CACHE:-}" ]; then
|
||||
export NAVI_CACHE="$cheats"
|
||||
fi
|
||||
|
||||
cheat::export_cache "$cheats"
|
||||
local -r selection="$(ui::select "$cheats")"
|
||||
local -r cheat="$(cheat::from_selection "$cheats" "$selection")"
|
||||
|
||||
[ -z "$cheat" ] && exit 67
|
||||
[ -z "$cheat" ] && die "No valid cheatsheet!"
|
||||
|
||||
local -r interpolation="$(dict::get "$OPTIONS" interpolation)"
|
||||
local cmd="$(selection::cmd "$selection" "$cheat")"
|
||||
local arg value
|
||||
|
||||
local -r args="$(dict::get "$OPTIONS" args)"
|
||||
local cmd="$(selection::cmd "$selection" "$cheat")"
|
||||
local result arg value
|
||||
|
||||
local i=0
|
||||
while $interpolation; do
|
||||
arg="$(echo "$cmd" | arg::next || echo "")"
|
||||
if [ -z "$arg" ]; then
|
||||
break
|
||||
fi
|
||||
result="$(cmd::loop "$cmd" "$cheat")"
|
||||
arg="$(dict::get "$result" arg)"
|
||||
value="$(dict::get "$result" value)"
|
||||
cmd="$(dict::get "$result" cmd)"
|
||||
|
||||
escaped_arg="$(echo "$arg" | tr '-' '_' | tr ' ' '_')"
|
||||
if ! [[ $escaped_arg =~ $ARG_REGEX_WITHOUT_BRACKETS ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cmd="$(echo "$cmd" | sed "s|<${arg}>|<${escaped_arg}>|g")"
|
||||
arg="$escaped_arg"
|
||||
|
||||
value="$(echo "$args" | coll::get $i)"
|
||||
[ -z "$value" ] && value="$(arg::pick "$arg" "$cheat")"
|
||||
|
||||
if [ -z "$value" ]; then
|
||||
echoerr "Unable to fetch suggestions for '$arg'!"
|
||||
exit 1
|
||||
fi
|
||||
[ -z "$arg" ] && break
|
||||
[ -z "$value" ] && die "Unable to fetch suggestions for '$arg'!"
|
||||
|
||||
eval "local $arg"='$value'
|
||||
cmd="$(echo "$cmd" | arg::interpolate "$arg" "$value")"
|
||||
@ -63,14 +45,7 @@ handler::main() {
|
||||
i=$((i+1))
|
||||
done
|
||||
|
||||
local -r unresolved_arg="$(echo "$cmd" | arg::next || echo "")"
|
||||
|
||||
local -r print="$(dict::get "$OPTIONS" print)"
|
||||
if $print || [ -n "$unresolved_arg" ]; then
|
||||
echo "$cmd"
|
||||
else
|
||||
eval "$cmd"
|
||||
fi
|
||||
cmd::finish "$cmd"
|
||||
}
|
||||
|
||||
handler::preview() {
|
||||
@ -82,7 +57,7 @@ handler::preview() {
|
||||
}
|
||||
|
||||
handler::help() {
|
||||
echo "$TEXT"
|
||||
opts::extract_help "$0"
|
||||
}
|
||||
|
||||
handler::version() {
|
||||
@ -92,7 +67,8 @@ handler::version() {
|
||||
|
||||
if $full; then
|
||||
source "${SCRIPT_DIR}/src/version.sh"
|
||||
version::code 2>/dev/null || echo "unknown code"
|
||||
version::code 2>/dev/null \
|
||||
|| die "unknown code"
|
||||
fi
|
||||
}
|
||||
|
||||
@ -106,18 +82,23 @@ handler::home() {
|
||||
|
||||
handler::widget() {
|
||||
local widget
|
||||
local -r print="$(dict::get "$OPTIONS" print)"
|
||||
|
||||
case "$SH" in
|
||||
zsh) widget="${SCRIPT_DIR}/navi.plugin.zsh" ;;
|
||||
bash) widget="${SCRIPT_DIR}/navi.plugin.bash" ;;
|
||||
*) echoerr "Invalid shell: $SH"; exit 1 ;;
|
||||
*) die "Invalid shell: $SH" ;;
|
||||
esac
|
||||
|
||||
if "$(dict::get "$OPTIONS" print)"; then
|
||||
cat "$widget"
|
||||
else
|
||||
echo "$widget"
|
||||
fi
|
||||
$print \
|
||||
&& cat "$widget" \
|
||||
|| echo "$widget"
|
||||
}
|
||||
|
||||
handler::search() {
|
||||
local -r query="$(dict::get "$OPTIONS" query)"
|
||||
search::save "$query" || true
|
||||
handler::main
|
||||
}
|
||||
|
||||
main() {
|
||||
@ -125,13 +106,11 @@ main() {
|
||||
preview)
|
||||
local -r query="$(dict::get "$OPTIONS" query)"
|
||||
handler::preview "$query" \
|
||||
|| echo "Unable to find command for '$query'"
|
||||
|| echoerr "Unable to find command for '$query'"
|
||||
;;
|
||||
search)
|
||||
health::fzf
|
||||
local -r query="$(dict::get "$OPTIONS" query)"
|
||||
search::save "$query" || true
|
||||
handler::main
|
||||
handler::search
|
||||
;;
|
||||
version)
|
||||
handler::version false
|
||||
|
@ -10,6 +10,7 @@ command_exists() {
|
||||
}
|
||||
|
||||
platform::existing_command() {
|
||||
local cmd
|
||||
for cmd in "$@"; do
|
||||
if command_exists "$cmd"; then
|
||||
echo "$cmd"
|
||||
@ -25,11 +26,16 @@ echoerr() {
|
||||
|
||||
url::open() {
|
||||
local -r cmd="$(platform::existing_command "${BROWSER:-}" xdg-open open google-chrome firefox)"
|
||||
"$cmd" "$@"
|
||||
"$cmd" "$@" & disown
|
||||
}
|
||||
|
||||
tap() {
|
||||
local -r input="$(cat)"
|
||||
echoerr "$input"
|
||||
echo "$input"
|
||||
}
|
||||
|
||||
die() {
|
||||
echoerr "$@"
|
||||
exit 42
|
||||
}
|
@ -16,12 +16,12 @@ opts::eval() {
|
||||
local autoselect=true
|
||||
local best=false
|
||||
local query=""
|
||||
local args=""
|
||||
local values=""
|
||||
|
||||
case "${1:-}" in
|
||||
--version|version) entry_point="version"; shift ;;
|
||||
--full-version|full-version) entry_point="full-version"; shift ;;
|
||||
--help|help) entry_point="help"; TEXT="$(opts::extract_help "$0")"; shift ;;
|
||||
--help|help) entry_point="help"; shift ;;
|
||||
search) entry_point="search"; wait_for="search"; shift ;;
|
||||
preview) entry_point="preview"; wait_for="preview"; shift ;;
|
||||
query|q) wait_for="query"; shift ;;
|
||||
@ -46,7 +46,7 @@ opts::eval() {
|
||||
--no-preview) preview=false ;;
|
||||
--path|--dir) wait_for="path" ;;
|
||||
--no-autoselect) autoselect=false ;;
|
||||
*) args="$(echo "$args" | coll::add "$arg")" ;;
|
||||
*) values="$(echo "$values" | coll::add "$arg")" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
@ -58,7 +58,7 @@ opts::eval() {
|
||||
autoselect "$autoselect" \
|
||||
query "$query" \
|
||||
best "$best" \
|
||||
args "$args")"
|
||||
values "$values")"
|
||||
|
||||
export NAVI_PATH="$path"
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
ESCAPE_CHAR="\034"
|
||||
ESCAPE_CHAR_2="\035"
|
||||
ESCAPE_CHAR_3="\036"
|
||||
|
||||
str::length() {
|
||||
awk '{print length}'
|
||||
}
|
||||
@ -54,4 +58,8 @@ str::not_empty() {
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
str::remove_empty_lines() {
|
||||
sed '/^$/d'
|
||||
}
|
21
src/ui.sh
21
src/ui.sh
@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
ui::pick() {
|
||||
ui::fzf() {
|
||||
local -r autoselect="$(dict::get "$OPTIONS" autoselect)"
|
||||
|
||||
declare -a args
|
||||
local args
|
||||
args+=("--height")
|
||||
args+=("100%")
|
||||
if ${autoselect:-false}; then
|
||||
@ -14,12 +14,11 @@ ui::pick() {
|
||||
"$fzf_cmd" "${args[@]:-}" --inline-info "$@"
|
||||
}
|
||||
|
||||
# TODO: separation of concerns
|
||||
ui::select() {
|
||||
local -r cheats="$1"
|
||||
|
||||
local -r script_path="${SCRIPT_DIR}/navi"
|
||||
local -r preview_cmd="echo \'{}\' | tr \"'\" '${ARG_DELIMITER_2}' | tr ' ' '${ARG_DELIMITER}' | tr '\"' '${ARG_DELIMITER_3}' | xargs -I% \"${script_path}\" preview %"
|
||||
local -r preview_cmd="echo \'{}\' | $(arg::serialize_code) | xargs -I% \"${script_path}\" preview %"
|
||||
|
||||
local -r query="$(dict::get "$OPTIONS" query)"
|
||||
local -r entry_point="$(dict::get "$OPTIONS" entry_point)"
|
||||
@ -42,18 +41,10 @@ ui::select() {
|
||||
args+=("--header"); args+=("Displaying online results. Please refer to 'navi --help' for details")
|
||||
fi
|
||||
|
||||
ui::_select_post() {
|
||||
if $best; then
|
||||
head -n1
|
||||
else
|
||||
cat
|
||||
fi
|
||||
}
|
||||
|
||||
echo "$cheats" \
|
||||
| cheat::pretty \
|
||||
| ui::pick "${args[@]}" \
|
||||
| ui::_select_post \
|
||||
| cheat::prettify \
|
||||
| ui::fzf "${args[@]}" \
|
||||
| ($best && head -n1 || cat) \
|
||||
| selection::dict
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,8 @@ inc() {
|
||||
}
|
||||
|
||||
test::map_equals() {
|
||||
local -r actual="$(cat | dict::_unescape_value | sort)"
|
||||
local -r expected="$(dict::new "$@" | dict::_unescape_value | sort)"
|
||||
local -r actual="$(cat | dict::unescape_value | sort)"
|
||||
local -r expected="$(dict::new "$@" | dict::unescape_value | sort)"
|
||||
|
||||
echo "$actual" | test::equals "$expected"
|
||||
}
|
||||
@ -15,7 +15,9 @@ test::map_equals() {
|
||||
dict_assoc() {
|
||||
dict::new \
|
||||
| dict::assoc "foo" "42" \
|
||||
| tr -d '\f' \
|
||||
| tr -d "$ESCAPE_CHAR" \
|
||||
| tr -d "$ESCAPE_CHAR_2" \
|
||||
| tr -d "$ESCAPE_CHAR_3" \
|
||||
| test::equals "foo: 42"
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user