diff --git a/examples/completions/src/lib/send_completions.sh b/examples/completions/src/lib/send_completions.sh index f11beac3..d05952c6 100644 --- a/examples/completions/src/lib/send_completions.sh +++ b/examples/completions/src/lib/send_completions.sh @@ -11,24 +11,46 @@ send_completions() { echo $' local cur=${COMP_WORDS[COMP_CWORD]}' echo $' local result=()' echo $'' + echo $' # words the user already typed (excluding the command itself)' + echo $' local used=()' + echo $' if ((COMP_CWORD > 1)); then' + echo $' used=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}")' + echo $' fi' + echo $'' echo $' if [[ "${cur:0:1}" == "-" ]]; then' + echo $' # Completing an option: offer everything (including options)' echo $' echo "$words"' echo $'' echo $' else' + echo $' # Completing a non-option: offer only non-options,' + echo $' # and don\'t re-offer ones already used earlier in the line.' echo $' for word in $words; do' - echo $' [[ "${word:0:1}" != "-" ]] && result+=("$word")' + echo $' [[ "${word:0:1}" == "-" ]] && continue' + echo $'' + echo $' local seen=0' + echo $' for u in "${used[@]}"; do' + echo $' if [[ "$u" == "$word" ]]; then' + echo $' seen=1' + echo $' break' + echo $' fi' + echo $' done' + echo $' ((!seen)) && result+=("$word")' echo $' done' echo $'' echo $' echo "${result[*]}"' - echo $'' echo $' fi' echo $'}' echo $'' echo $'_cli_completions() {' echo $' local cur=${COMP_WORDS[COMP_CWORD]}' - echo $' local compwords=("${COMP_WORDS[@]:1:$COMP_CWORD-1}")' + echo $' local compwords=()' + echo $' if ((COMP_CWORD > 0)); then' + echo $' compwords=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}")' + echo $' fi' echo $' local compline="${compwords[*]}"' echo $'' + echo $' COMPREPLY=()' + echo $'' echo $' case "$compline" in' echo $' \'download\'*\'--handler\')' echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "curl wget")" -- "$cur")' diff --git a/examples/render-mandoc/docs/download.1 b/examples/render-mandoc/docs/download.1 index 3303044c..0994956e 100644 --- a/examples/render-mandoc/docs/download.1 +++ b/examples/render-mandoc/docs/download.1 @@ -1,6 +1,6 @@ .\" Automatically generated by Pandoc 3.2 .\" -.TH "download" "1" "August 2025" "Version 0.1.0" "Sample application" +.TH "download" "1" "September 2025" "Version 0.1.0" "Sample application" .SH NAME \f[B]download\f[R] \- Sample application .SH SYNOPSIS diff --git a/examples/render-mandoc/docs/download.md b/examples/render-mandoc/docs/download.md index b4f08c4a..706412b8 100644 --- a/examples/render-mandoc/docs/download.md +++ b/examples/render-mandoc/docs/download.md @@ -1,6 +1,6 @@ % download(1) Version 0.1.0 | Sample application % Lana Lang -% August 2025 +% September 2025 NAME ================================================== diff --git a/spec/approvals/cli/add/comp-function-file b/spec/approvals/cli/add/comp-function-file index e2853585..b1851a88 100644 --- a/spec/approvals/cli/add/comp-function-file +++ b/spec/approvals/cli/add/comp-function-file @@ -11,24 +11,46 @@ send_completions() { echo $' local cur=${COMP_WORDS[COMP_CWORD]}' echo $' local result=()' echo $'' + echo $' # words the user already typed (excluding the command itself)' + echo $' local used=()' + echo $' if ((COMP_CWORD > 1)); then' + echo $' used=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}")' + echo $' fi' + echo $'' echo $' if [[ "${cur:0:1}" == "-" ]]; then' + echo $' # Completing an option: offer everything (including options)' echo $' echo "$words"' echo $'' echo $' else' + echo $' # Completing a non-option: offer only non-options,' + echo $' # and don\'t re-offer ones already used earlier in the line.' echo $' for word in $words; do' - echo $' [[ "${word:0:1}" != "-" ]] && result+=("$word")' + echo $' [[ "${word:0:1}" == "-" ]] && continue' + echo $'' + echo $' local seen=0' + echo $' for u in "${used[@]}"; do' + echo $' if [[ "$u" == "$word" ]]; then' + echo $' seen=1' + echo $' break' + echo $' fi' + echo $' done' + echo $' ((!seen)) && result+=("$word")' echo $' done' echo $'' echo $' echo "${result[*]}"' - echo $'' echo $' fi' echo $'}' echo $'' echo $'_cli_completions() {' echo $' local cur=${COMP_WORDS[COMP_CWORD]}' - echo $' local compwords=("${COMP_WORDS[@]:1:$COMP_CWORD-1}")' + echo $' local compwords=()' + echo $' if ((COMP_CWORD > 0)); then' + echo $' compwords=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}")' + echo $' fi' echo $' local compline="${compwords[*]}"' echo $'' + echo $' COMPREPLY=()' + echo $'' echo $' case "$compline" in' echo $' \'download\'*)' echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--force --help -f -h")" -- "$cur")' diff --git a/spec/approvals/cli/add/comp-script-file b/spec/approvals/cli/add/comp-script-file index d36b3c3f..81a69f94 100644 --- a/spec/approvals/cli/add/comp-script-file +++ b/spec/approvals/cli/add/comp-script-file @@ -9,24 +9,46 @@ _cli_completions_filter() { local cur=${COMP_WORDS[COMP_CWORD]} local result=() + # words the user already typed (excluding the command itself) + local used=() + if ((COMP_CWORD > 1)); then + used=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}") + fi + if [[ "${cur:0:1}" == "-" ]]; then + # Completing an option: offer everything (including options) echo "$words" else + # Completing a non-option: offer only non-options, + # and don't re-offer ones already used earlier in the line. for word in $words; do - [[ "${word:0:1}" != "-" ]] && result+=("$word") + [[ "${word:0:1}" == "-" ]] && continue + + local seen=0 + for u in "${used[@]}"; do + if [[ "$u" == "$word" ]]; then + seen=1 + break + fi + done + ((!seen)) && result+=("$word") done echo "${result[*]}" - fi } _cli_completions() { local cur=${COMP_WORDS[COMP_CWORD]} - local compwords=("${COMP_WORDS[@]:1:$COMP_CWORD-1}") + local compwords=() + if ((COMP_CWORD > 0)); then + compwords=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}") + fi local compline="${compwords[*]}" + COMPREPLY=() + case "$compline" in 'download'*) while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--force --help -f -h")" -- "$cur") diff --git a/spec/approvals/completions/function b/spec/approvals/completions/function index d819e5c4..27bfbac8 100644 --- a/spec/approvals/completions/function +++ b/spec/approvals/completions/function @@ -10,24 +10,46 @@ custom_name() { echo $' local cur=${COMP_WORDS[COMP_CWORD]}' echo $' local result=()' echo $'' + echo $' # words the user already typed (excluding the command itself)' + echo $' local used=()' + echo $' if ((COMP_CWORD > 1)); then' + echo $' used=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}")' + echo $' fi' + echo $'' echo $' if [[ "${cur:0:1}" == "-" ]]; then' + echo $' # Completing an option: offer everything (including options)' echo $' echo "$words"' echo $'' echo $' else' + echo $' # Completing a non-option: offer only non-options,' + echo $' # and don\'t re-offer ones already used earlier in the line.' echo $' for word in $words; do' - echo $' [[ "${word:0:1}" != "-" ]] && result+=("$word")' + echo $' [[ "${word:0:1}" == "-" ]] && continue' + echo $'' + echo $' local seen=0' + echo $' for u in "${used[@]}"; do' + echo $' if [[ "$u" == "$word" ]]; then' + echo $' seen=1' + echo $' break' + echo $' fi' + echo $' done' + echo $' ((!seen)) && result+=("$word")' echo $' done' echo $'' echo $' echo "${result[*]}"' - echo $'' echo $' fi' echo $'}' echo $'' echo $'_get_completions() {' echo $' local cur=${COMP_WORDS[COMP_CWORD]}' - echo $' local compwords=("${COMP_WORDS[@]:1:$COMP_CWORD-1}")' + echo $' local compwords=()' + echo $' if ((COMP_CWORD > 0)); then' + echo $' compwords=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}")' + echo $' fi' echo $' local compline="${compwords[*]}"' echo $'' + echo $' COMPREPLY=()' + echo $'' echo $' case "$compline" in' echo $' *)' echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A file -W "$(_get_completions_filter "--force --help --verbose --version -h -v")" -- "$cur")' diff --git a/spec/approvals/completions/script b/spec/approvals/completions/script index ee1a8696..05c8b539 100644 --- a/spec/approvals/completions/script +++ b/spec/approvals/completions/script @@ -9,24 +9,46 @@ _say_completions_filter() { local cur=${COMP_WORDS[COMP_CWORD]} local result=() + # words the user already typed (excluding the command itself) + local used=() + if ((COMP_CWORD > 1)); then + used=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}") + fi + if [[ "${cur:0:1}" == "-" ]]; then + # Completing an option: offer everything (including options) echo "$words" else + # Completing a non-option: offer only non-options, + # and don't re-offer ones already used earlier in the line. for word in $words; do - [[ "${word:0:1}" != "-" ]] && result+=("$word") + [[ "${word:0:1}" == "-" ]] && continue + + local seen=0 + for u in "${used[@]}"; do + if [[ "$u" == "$word" ]]; then + seen=1 + break + fi + done + ((!seen)) && result+=("$word") done echo "${result[*]}" - fi } _say_completions() { local cur=${COMP_WORDS[COMP_CWORD]} - local compwords=("${COMP_WORDS[@]:1:$COMP_CWORD-1}") + local compwords=() + if ((COMP_CWORD > 0)); then + compwords=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}") + fi local compline="${compwords[*]}" + COMPREPLY=() + case "$compline" in 'goodbye universe'*'--color') while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_say_completions_filter "green red")" -- "$cur") diff --git a/spec/approvals/examples/completions b/spec/approvals/examples/completions index c5824e43..cd33c4a3 100644 --- a/spec/approvals/examples/completions +++ b/spec/approvals/examples/completions @@ -73,24 +73,46 @@ _cli_completions_filter() { local cur=${COMP_WORDS[COMP_CWORD]} local result=() + # words the user already typed (excluding the command itself) + local used=() + if ((COMP_CWORD > 1)); then + used=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}") + fi + if [[ "${cur:0:1}" == "-" ]]; then + # Completing an option: offer everything (including options) echo "$words" else + # Completing a non-option: offer only non-options, + # and don't re-offer ones already used earlier in the line. for word in $words; do - [[ "${word:0:1}" != "-" ]] && result+=("$word") + [[ "${word:0:1}" == "-" ]] && continue + + local seen=0 + for u in "${used[@]}"; do + if [[ "$u" == "$word" ]]; then + seen=1 + break + fi + done + ((!seen)) && result+=("$word") done echo "${result[*]}" - fi } _cli_completions() { local cur=${COMP_WORDS[COMP_CWORD]} - local compwords=("${COMP_WORDS[@]:1:$COMP_CWORD-1}") + local compwords=() + if ((COMP_CWORD > 0)); then + compwords=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}") + fi local compline="${compwords[*]}" + COMPREPLY=() + case "$compline" in 'download'*'--handler') while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "curl wget")" -- "$cur") diff --git a/spec/approvals/libraries/completions_function/files b/spec/approvals/libraries/completions_function/files index c0d97332..8964f90c 100644 --- a/spec/approvals/libraries/completions_function/files +++ b/spec/approvals/libraries/completions_function/files @@ -14,24 +14,46 @@ echo $' local cur=${COMP_WORDS[COMP_CWORD]}' echo $' local result=()' echo $'' + echo $' # words the user already typed (excluding the command itself)' + echo $' local used=()' + echo $' if ((COMP_CWORD > 1)); then' + echo $' used=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}")' + echo $' fi' + echo $'' echo $' if [[ "${cur:0:1}" == "-" ]]; then' + echo $' # Completing an option: offer everything (including options)' echo $' echo "$words"' echo $'' echo $' else' + echo $' # Completing a non-option: offer only non-options,' + echo $' # and don\'t re-offer ones already used earlier in the line.' echo $' for word in $words; do' - echo $' [[ "${word:0:1}" != "-" ]] && result+=("$word")' + echo $' [[ "${word:0:1}" == "-" ]] && continue' + echo $'' + echo $' local seen=0' + echo $' for u in "${used[@]}"; do' + echo $' if [[ "$u" == "$word" ]]; then' + echo $' seen=1' + echo $' break' + echo $' fi' + echo $' done' + echo $' ((!seen)) && result+=("$word")' echo $' done' echo $'' echo $' echo "${result[*]}"' - echo $'' echo $' fi' echo $'}' echo $'' echo $'_download_completions() {' echo $' local cur=${COMP_WORDS[COMP_CWORD]}' - echo $' local compwords=("${COMP_WORDS[@]:1:$COMP_CWORD-1}")' + echo $' local compwords=()' + echo $' if ((COMP_CWORD > 0)); then' + echo $' compwords=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}")' + echo $' fi' echo $' local compline="${compwords[*]}"' echo $'' + echo $' COMPREPLY=()' + echo $'' echo $' case "$compline" in' echo $' *)' echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_download_completions_filter "--force --help --version -f -h -v")" -- "$cur")' diff --git a/spec/approvals/libraries/completions_script/files b/spec/approvals/libraries/completions_script/files index 3a676602..518775c7 100644 --- a/spec/approvals/libraries/completions_script/files +++ b/spec/approvals/libraries/completions_script/files @@ -12,24 +12,46 @@ local cur=${COMP_WORDS[COMP_CWORD]} local result=() + # words the user already typed (excluding the command itself) + local used=() + if ((COMP_CWORD > 1)); then + used=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}") + fi + if [[ "${cur:0:1}" == "-" ]]; then + # Completing an option: offer everything (including options) echo "$words" else + # Completing a non-option: offer only non-options, + # and don't re-offer ones already used earlier in the line. for word in $words; do - [[ "${word:0:1}" != "-" ]] && result+=("$word") + [[ "${word:0:1}" == "-" ]] && continue + + local seen=0 + for u in "${used[@]}"; do + if [[ "$u" == "$word" ]]; then + seen=1 + break + fi + done + ((!seen)) && result+=("$word") done echo "${result[*]}" - fi } _download_completions() { local cur=${COMP_WORDS[COMP_CWORD]} - local compwords=("${COMP_WORDS[@]:1:$COMP_CWORD-1}") + local compwords=() + if ((COMP_CWORD > 0)); then + compwords=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}") + fi local compline="${compwords[*]}" + COMPREPLY=() + case "$compline" in *) while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_download_completions_filter "--force --help --version -f -h -v")" -- "$cur")