Skip to content
Binary file modified assets/dispatch_demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
62 changes: 60 additions & 2 deletions shifu
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,48 @@ _shifu_opt_build() {
done
}

_shifu_add_equals_case_arms() {
shifu_eq_target="$1"; shifu_eq_var="$2"
_shifu_set_for_looping shifu_eq_list shifu_eq_saved_args
for shifu_eq_flag in $shifu_eq_list; do
case "$shifu_eq_flag" in
--) break ;;
--*) _shifu_append_on_new_line "$shifu_eq_target" \
" $shifu_eq_flag=*) $shifu_eq_var=\\\${1#*=}; shift; _shifu_ack_arg ;;" ;;
esac
done
}

_shifu_add_equals_defer_case_arms() {
shifu_eq_var="$1"
_shifu_set_for_looping shifu_eq_list shifu_eq_saved_args
for shifu_eq_flag in $shifu_eq_list; do
case "$shifu_eq_flag" in
--) break ;;
--*) shifu_defer_case="$shifu_defer_case
$shifu_eq_flag=*) $shifu_eq_var=\\\${1#*=}; shift; _shifu_ack_arg ;;" ;;
esac
done
}

_shifu_add_comp_eq_patterns() {
if [ -n "${shifu_comp_eq_patterns:-}" ]; then
shifu_case_stmt="${shifu_case_stmt}${shifu_comp_eq_patterns}"
shifu_comp_eq_patterns=""
fi
}

_shifu_add_equals_comp_case_arms() {
shifu_eq_target="$1"
_shifu_set_for_looping shifu_eq_list shifu_eq_saved_args
for shifu_eq_flag in $shifu_eq_list; do
case "$shifu_eq_flag" in
--) break ;;
--*) _shifu_append_on_new_line "$shifu_eq_target" " $shifu_eq_flag=*) shift ;;" ;;
esac
done
}

_shifu_validate_flag() {
case "$1" in
-*) ;;
Expand Down Expand Up @@ -419,59 +461,71 @@ _shifu_cmd_optd_help() {
}

_shifu_cmd_optd_build_now() {
shifu_eq_saved_args="$*"
_shifu_opt_case_parse "$@"
shift $shifu_opt_count
_shifu_error_if_invalid_arg_order "$1" $shifu_parse_stage
_shifu_set_variable "$1" "$2"
_shifu_update_case_stmt_option_value_check
shifu_case_stmt="$shifu_case_stmt $1=\$2; shift 2; _shifu_ack_arg 2 ;;"
_shifu_add_equals_case_arms shifu_case_stmt "$1"
}

_shifu_cmd_optd_build_defer() {
shifu_eq_saved_args="$*"
_shifu_opt_defer_parse "$@"
shift $shifu_opt_count
_shifu_set_variable "$1" "$2"
_shifu_update_case_stmt_option_value_check defer
shifu_defer_case="$shifu_defer_case $1=\\\$2; shift 2; _shifu_ack_arg 2 ;;"
shifu_defer_help="${shifu_defer_help:-} [$1]\n $3\n Default: $2"
_shifu_add_equals_defer_case_arms "$1"
}

_shifu_cmd_optv_build_comp_now() {
shifu_eq_saved_args="$*"
_shifu_opt_comp_eager_parse "$@"
shift $shifu_opt_count
_shifu_error_if_invalid_arg_order "$1" $shifu_parse_stage
shifu_case_stmt="$shifu_case_stmt) shift;"
_shifu_add_equals_comp_case_arms shifu_comp_eq_patterns
}

_shifu_cmd_optv_build_comp_defer() {
shifu_eq_saved_args="$*"
_shifu_opt_build_comp_defer_parse "$@"
shift $shifu_opt_count
shifu_defer_comp_case="${shifu_defer_comp_case:-}) shift;"
_shifu_add_equals_comp_case_arms shifu_comp_eq_patterns
}

_shifu_cmd_optr_help() {
_shifu_opt_help_parse "$@"
shift $shifu_opt_count
_shifu_error_if_invalid_arg_order "$1" $shifu_help_stage
shifu_help_options="$shifu_help_options [$1]\n $2\n Required"
shifu_help_options="$shifu_help_options $1\n $2\n Required"
}

_shifu_cmd_optr_build_now() {
shifu_eq_saved_args="$*"
_shifu_opt_case_parse "$@"
shift $shifu_opt_count
_shifu_error_if_invalid_arg_order "$1" $shifu_parse_stage
_shifu_list_append shifu_required_variables "$1"
_shifu_update_case_stmt_option_value_check
shifu_case_stmt="$shifu_case_stmt $1=\$2; shift 2; _shifu_ack_arg 2 ;;"
_shifu_add_equals_case_arms shifu_case_stmt "$1"
}

_shifu_cmd_optr_build_defer() {
shifu_eq_saved_args="$*"
_shifu_opt_defer_parse "$@"
shift $shifu_opt_count
_shifu_list_append shifu_required_variables "$1"
_shifu_update_case_stmt_option_value_check defer
shifu_defer_case="$shifu_defer_case $1=\\\$2; shift 2; _shifu_ack_arg 2 ;;"
shifu_defer_help="${shifu_defer_help:-} [$1]\n $2\n Required"
shifu_defer_help="${shifu_defer_help:-} $1\n $2\n Required"
_shifu_add_equals_defer_case_arms "$1"
}

_shifu_cmd_optd_build_comp_now() { _shifu_cmd_optv_build_comp_now "$@"; }
Expand Down Expand Up @@ -505,6 +559,7 @@ _shifu_cmd_argr_build_comp_now() {
_shifu_opt_comp_preamble
if [ $shifu_parse_stage -eq 0 ]; then
shifu_parse_stage=1
_shifu_add_comp_eq_patterns
_shifu_append_on_new_line shifu_case_stmt " *)"
elif [ $shifu_parse_stage -gt 1 ]; then
_shifu_error "No arguments after remaining are declared: $1"
Expand All @@ -526,6 +581,7 @@ _shifu_cmd_args_build_now() {
_shifu_cmd_args_build_comp_now() {
_shifu_opt_comp_preamble
[ $shifu_parse_stage -eq 2 ] && _shifu_error "Can only declare remaining arguments once: $1"
[ $shifu_parse_stage -eq 0 ] && _shifu_add_comp_eq_patterns
shifu_parse_stage=2
}

Expand Down Expand Up @@ -705,6 +761,7 @@ _shifu_complete_func_args() {
shifu_parse_stage=0
shifu_parse_eager="$1"; shifu_cmd="$2"; shift 2
_shifu_args_parsed=0
shifu_comp_eq_patterns=""
shifu_case_stmt="case \"\${1:-}\" in "
if [ "$shifu_parse_eager" = false -a -n "${shifu_defer_comp_case:-}" ]; then
shifu_case_stmt="${shifu_case_stmt}
Expand All @@ -719,6 +776,7 @@ ${shifu_defer_comp_case:-}"
if [ $shifu_parse_stage -eq 0 -a $shifu_arg_completion_set = false ]; then
shifu_case_stmt="$shifu_case_stmt shift ;;"
fi
_shifu_add_comp_eq_patterns
if [ "$shifu_parse_eager" = true ]; then
_shifu_append_on_new_line shifu_case_stmt " *) _shifu_comp_done=true ;;"
elif [ $shifu_parse_stage -ne 0 ]; then
Expand Down
91 changes: 82 additions & 9 deletions tests/test_shifu.sh
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,69 @@ test_shifu_run_option_missing_value() {
-- short_option "-o"
}

test_shifu_run_optd_equals_value() {
run_test() {
shifu_test_params option expected -- "$@"
shifu_run shifu_test_all_options_cmd \
-a req_flag_value --option-req req_option_value \
--flag-option-req req_flag_option_value \
$option \
positional_arg_value_one positional_arg_value_two
shifu_assert_zero exit_code $?
shifu_assert_equal option_def "$OPTION_DEF" "$expected"
}
shifu_parameterize_test run_test \
-- value "--option-def=custom" "custom" \
-- nested "--option-def=key=value" "key=value" \
-- empty "--option-def=" ""
}

test_shifu_run_optr_equals_value() {
run_test() {
shifu_test_params option expected -- "$@"
shifu_run shifu_test_all_options_cmd \
-a req_flag_value --flag-option-req req_flag_option_value \
$option \
positional_arg_value_one positional_arg_value_two
shifu_assert_zero exit_code $?
shifu_assert_equal option_req "$OPTION_REQ" "$expected"
}
shifu_parameterize_test run_test \
-- value "--option-req=custom_req" "custom_req" \
-- nested "--option-req=key=value" "key=value" \
-- empty "--option-req=" ""
}

test_shifu_run_defer_and_eager_equals_value() {
run_test() {
shifu_test_params @cmd_args var expected -- "$@"
shifu_run shifu_test_root_cmd $cmd_args
shifu_assert_zero exit_code $?
eval "shifu_assert_equal $var \"\$$var\" \"$expected\""
}
shifu_parameterize_test run_test \
-- defer "sub-two leaf-three -g --defer-def=custom_defer one two" \
DEFER_DEF "custom_defer" \
-- eager "sub-two --eager-test=custom_eager leaf-three one two" \
EAGER_TEST "custom_eager"
}

test_shifu_run_short_flag_equals_errors() {
actual=$(shifu_run shifu_test_all_options_cmd -d=bad_value 2>&1)
shifu_assert_non_zero exit_code $?
shifu_assert_string_contains error_message "$actual" "Invalid option"
}

test_shifu_run_optb_equals_errors() {
actual=$(shifu_run shifu_test_all_options_cmd \
-a req_flag_value --option-req req_option_value \
--flag-option-req req_flag_option_value \
--option-bin=bad_value \
positional_arg_value_one positional_arg_value_two 2>&1)
shifu_assert_non_zero exit_code $?
shifu_assert_string_contains error_message "$actual" "Invalid option"
}

test_shifu_run_bad_first_cmd() {
expected="$(
echo 'Unknown command: bad'
Expand Down Expand Up @@ -540,7 +603,7 @@ Options
-f
binary flag help
Default: 0, set: 1
-a [FLAG_REQ]
-a FLAG_REQ
required flag help
Required
-d [FLAG_DEF]
Expand All @@ -549,7 +612,7 @@ Options
--option-bin
binary option help
Default: 0, set: 1
--option-req [OPTION_REQ]
--option-req OPTION_REQ
required option help
Required
--option-def [OPTION_DEF]
Expand All @@ -558,7 +621,7 @@ Options
-F, --flag-option-bin
binary flag/option help
Default: 0, set: 1
-A, --flag-option-req [FLAG_OPTION_REQ]
-A, --flag-option-req FLAG_OPTION_REQ
required flag/option help
Required
-D, --flag-option-def [FLAG_OPTION_DEF]
Expand Down Expand Up @@ -689,7 +752,13 @@ test_shifu_complete() {
"defer_one defer_two defer_three" \
-- nested_eager_at_multiple_levels \
shifu_test_eager_root_cmd "cur_word -r root_one sub-multi-eager -b -d data_one" \
"leaf-three leaf-four"
"leaf-three leaf-four" \
-- subcmds_after_eager_equals \
shifu_test_root_cmd "cur_word sub-two --eager-test=some_value" \
"leaf-three leaf-four" \
-- leaf_options_through_equals_arg \
shifu_test_root_cmd "--f sub-two --eager-test=some_value leaf-four" \
"--fake-arg"
}

test_shifu_complete_single_dash_with_config_shows_all_options() {
Expand Down Expand Up @@ -979,18 +1048,22 @@ shifu_parameterize_test() {
[ "$pt_arg" = "--" ] && break
pt_count=$((pt_count + 1))
done
pt_errors_in=$errors
pt_output_buffer=""
"$pt_test_name" "$@"
if [ $errors -eq $pt_errors_in ]; then
pt_case_output=$(
errors=0
unset pt_output_buffer
"$pt_test_name" "$@"
exit $errors
)
pt_case_errors=$?
if [ $pt_case_errors -eq 0 ]; then
pt_passed=$((pt_passed + 1))
if [ "${shifu_verbose_tests:-}" = true ]; then
printf " $shifu_green%-4s$shifu_reset%s\n" "+" "$pt_case_name"
fi
else
pt_failed=$((pt_failed + 1))
printf " $shifu_red%-4s$shifu_reset%s\n" "x" "$pt_case_name"
[ -n "$pt_output_buffer" ] && echo "$pt_output_buffer"
[ -n "$pt_case_output" ] && echo "$pt_case_output"
fi
shift $pt_count
done
Expand Down
Loading