diff --git a/bin/omarchy b/bin/omarchy index a48f0487..91c593cc 100755 --- a/bin/omarchy +++ b/bin/omarchy @@ -122,6 +122,31 @@ append_pipe_value() { fi } +# A route can resolve to a binary before all args are consumed (`update aur` only matches the `update` binary, leaving `aur` and `--help` as leftovers) +# --help must never be lost among those leftovers and get forwarded into the real command, so this checks the whole remainder rather than just the first token. +# A `--` marks everything after it as belonging to the command itself, so scanning stops there. +remaining_has_help_flag() { + local token="" + + for token in "$@"; do + [[ $token == "--" ]] && break + [[ $token == "--help" || $token == "-h" ]] && return 0 + done + + return 1 +} + +remaining_has_json_flag() { + local token="" + + for token in "$@"; do + [[ $token == "--" ]] && break + [[ $token == "--json" ]] && return 0 + done + + return 1 +} + register_route() { local route="$1" local key="$2" @@ -930,7 +955,7 @@ dispatch_fast_or_help() { remaining=("${args[@]:DIRECT_RESOLVED_COUNT}") binary_path="$OMARCHY_BIN_DIR/$DIRECT_RESOLVED_BINARY" - if (( ${#remaining[@]} > 0 )) && [[ ${remaining[0]} == "--help" || ${remaining[0]} == "-h" ]]; then + if remaining_has_help_flag "${remaining[@]}"; then if ! load_command_by_binary "$DIRECT_RESOLVED_BINARY"; then echo "Binary is missing or not executable: $DIRECT_RESOLVED_BINARY" >&2 return 127 @@ -941,7 +966,7 @@ dispatch_fast_or_help() { fi key="${BINARY_TO_KEY[$DIRECT_RESOLVED_BINARY]}" - if [[ " ${remaining[*]} " == *" --json "* ]]; then + if remaining_has_json_flag "${remaining[@]}"; then show_command_json "$key" else show_command_help "$key" @@ -994,8 +1019,8 @@ dispatch_or_help() { key="$RESOLVED_KEY" remaining=("${args[@]:RESOLVED_COUNT}") - if (( ${#remaining[@]} > 0 )) && [[ ${remaining[0]} == "--help" || ${remaining[0]} == "-h" ]]; then - if [[ " ${remaining[*]} " == *" --json "* ]]; then + if remaining_has_help_flag "${remaining[@]}"; then + if remaining_has_json_flag "${remaining[@]}"; then show_command_json "$key" else show_command_help "$key" diff --git a/test/cli b/test/cli index 1b85da83..c4cd45c0 100755 --- a/test/cli +++ b/test/cli @@ -755,3 +755,55 @@ assert_output_contains "partial metadata command dispatches" "$output" "partial- output=$("$TMPDIR/omarchy" body metadata test) assert_output_contains "body metadata command dispatches by filename" "$output" "body-metadata-ok" + +# A trailing --help must render help even when the route only partially +# resolves, leaving unresolved words ahead of the flag (e.g. `update aur --help` +# used to start a real update because only the first leftover token was checked). +{ + printf '#!/bin/bash\n\n' + printf '# omarchy:summary=Partial resolution help test parent\n' + printf '# omarchy:alias=omarchy parenthelp-alias\n' + printf 'echo "parenthelp-parent-ran args=[$*]"\n' +} >"$TMPDIR/omarchy-parenthelp" +chmod +x "$TMPDIR/omarchy-parenthelp" + +{ + printf '#!/bin/bash\n\n' + printf '# omarchy:summary=Partial resolution help test child\n' + printf 'echo parenthelp-child-ran\n' +} >"$TMPDIR/omarchy-parenthelp-child" +chmod +x "$TMPDIR/omarchy-parenthelp-child" + +output=$("$TMPDIR/omarchy" parenthelp bogus --help) +assert_output_contains "trailing --help after an unresolved word renders help" "$output" "omarchy-parenthelp" +assert_output_contains "partial resolution help lists related commands" "$output" "omarchy parenthelp child" +if [[ $output == *"parenthelp-parent-ran"* ]]; then + fail "trailing --help after an unresolved word does not execute the command" +fi +pass "trailing --help after an unresolved word does not execute the command" + +output=$("$TMPDIR/omarchy" parenthelp bogus -h) +assert_output_contains "trailing -h after an unresolved word renders help" "$output" "omarchy-parenthelp" + +output=$("$TMPDIR/omarchy" parenthelp-alias bogus --help) +assert_output_contains "trailing --help after an unresolved word renders help via alias route" "$output" "omarchy-parenthelp" +if [[ $output == *"parenthelp-parent-ran"* ]]; then + fail "trailing --help on an alias route does not execute the command" +fi +pass "trailing --help on an alias route does not execute the command" + +output=$("$TMPDIR/omarchy" parenthelp bogus --json --help) +grep -q '"ok": true' <<<"$output" || fail "--json with --help renders JSON help" +pass "--json with --help renders JSON help" + +output=$("$TMPDIR/omarchy" parenthelp "explain --json output" --help) +assert_output_contains "a --json embedded inside one argument does not switch help to JSON" "$output" "Partial resolution help test parent" + +output=$("$TMPDIR/omarchy" parenthelp bogus trailing) +assert_output_contains "leftover args without a help flag still forward" "$output" "parenthelp-parent-ran args=[bogus trailing]" + +output=$("$TMPDIR/omarchy" parenthelp run -- --help) +assert_output_contains "a --help behind -- belongs to the command and still forwards" "$output" "parenthelp-parent-ran args=[run -- --help]" + +output=$("$TMPDIR/omarchy" parenthelp --helpme x--help) +assert_output_contains "help lookalike tokens do not trigger help" "$output" "parenthelp-parent-ran args=[--helpme x--help]"