diff --git a/examples/completions/src/lib/send_completions.sh b/examples/completions/src/lib/send_completions.sh
index f7c799c2..b5800e2a 100644
--- a/examples/completions/src/lib/send_completions.sh
+++ b/examples/completions/src/lib/send_completions.sh
@@ -7,10 +7,9 @@ send_completions() {
echo $'# Modifying it manually is not recommended'
echo $''
echo $'_cli_completions_filter() {'
- echo $' local words=("$@")'
+ echo $' local words="$1"'
echo $' local cur=${COMP_WORDS[COMP_CWORD]}'
echo $' local result=()'
- echo $' local want_options=0'
echo $''
echo $' # words the user already typed (excluding the command itself)'
echo $' local used=()'
@@ -18,26 +17,28 @@ send_completions() {
echo $' used=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}")'
echo $' fi'
echo $''
- echo $' # Completing an option: offer everything.'
- echo $' # Completing a non-option: drop options and already-used words.'
- echo $' [[ "${cur:0:1}" == "-" ]] && want_options=1'
- echo $' for word in "${words[@]}"; do'
- echo $' if ((!want_options)); then'
+ 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}" == "-" ]] && continue'
echo $''
+ echo $' local seen=0'
echo $' for u in "${used[@]}"; do'
echo $' if [[ "$u" == "$word" ]]; then'
- echo $' continue 2'
+ echo $' seen=1'
+ echo $' break'
echo $' fi'
echo $' done'
- echo $' fi'
- echo $''
- echo $' # compgen -W expects shell-escaped words in one space-delimited string.'
- echo $' printf -v word \'%q\' "$word"'
- echo $' result+=("$word")'
- echo $' done'
+ echo $' ((!seen)) && result+=("$word")'
+ echo $' done'
echo $''
- echo $' echo "${result[*]}"'
+ echo $' echo "${result[*]}"'
+ echo $' fi'
echo $'}'
echo $''
echo $'_cli_completions() {'
@@ -52,7 +53,7 @@ send_completions() {
echo $''
echo $' case "$compline" in'
echo $' \'download\'*\'--handler\')'
- echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "curl" "wget")" -- "$cur")'
+ echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "curl wget")" -- "$cur")'
echo $' ;;'
echo $''
echo $' \'upload\'*\'--user\')'
@@ -60,11 +61,11 @@ send_completions() {
echo $' ;;'
echo $''
echo $' \'completions\'*)'
- echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help" "-h")" -- "$cur")'
+ echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help -h")" -- "$cur")'
echo $' ;;'
echo $''
echo $' \'d\'*\'--handler\')'
- echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "curl" "wget")" -- "$cur")'
+ echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "curl wget")" -- "$cur")'
echo $' ;;'
echo $''
echo $' \'upload\'*\'-u\')'
@@ -72,7 +73,8 @@ send_completions() {
echo $' ;;'
echo $''
echo $' \'download\'*)'
- echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A file -W "$(_cli_completions_filter "--force" "--handler" "--help" "-f" "-h")" -- "$cur")'
+ echo $' compopt -o filenames 2>/dev/null'
+ echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A file -W "$(_cli_completions_filter "--force --handler --help -f -h")" -- "$cur")'
echo $' ;;'
echo $''
echo $' \'u\'*\'--user\')'
@@ -80,7 +82,8 @@ send_completions() {
echo $' ;;'
echo $''
echo $' \'upload\'*)'
- echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A directory -A user -W "$(_cli_completions_filter "--help" "--password" "--user" "-h" "-p" "-u" "CHANGELOG.md" "README.md")" -- "$cur")'
+ echo $' compopt -o filenames 2>/dev/null'
+ echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A directory -A user -W "$(_cli_completions_filter "--help --password --user -h -p -u CHANGELOG.md README.md")" -- "$cur")'
echo $' ;;'
echo $''
echo $' \'u\'*\'-u\')'
@@ -88,15 +91,17 @@ send_completions() {
echo $' ;;'
echo $''
echo $' \'d\'*)'
- echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A file -W "$(_cli_completions_filter "--force" "--handler" "--help" "-f" "-h")" -- "$cur")'
+ echo $' compopt -o filenames 2>/dev/null'
+ echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A file -W "$(_cli_completions_filter "--force --handler --help -f -h")" -- "$cur")'
echo $' ;;'
echo $''
echo $' \'u\'*)'
- echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A directory -A user -W "$(_cli_completions_filter "--help" "--password" "--user" "-h" "-p" "-u" "CHANGELOG.md" "README.md")" -- "$cur")'
+ echo $' compopt -o filenames 2>/dev/null'
+ echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A directory -A user -W "$(_cli_completions_filter "--help --password --user -h -p -u CHANGELOG.md README.md")" -- "$cur")'
echo $' ;;'
echo $''
echo $' *)'
- echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help" "--version" "-h" "-v" "completions" "d" "download" "u" "upload")" -- "$cur")'
+ echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help --version -h -v completions d download u upload")" -- "$cur")'
echo $' ;;'
echo $''
echo $' esac'
diff --git a/examples/render-mandoc/docs/download.1 b/examples/render-mandoc/docs/download.1
index a7f1b1b0..2e24bee9 100644
--- a/examples/render-mandoc/docs/download.1
+++ b/examples/render-mandoc/docs/download.1
@@ -1,6 +1,6 @@
.\" Automatically generated by Pandoc 3.9
.\"
-.TH "download" "1" "February 2026" "Version 0.1.0" "Sample application"
+.TH "download" "1" "March 2026" "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 2e70d765..0a7df8d4 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
-% February 2026
+% March 2026
NAME
==================================================
diff --git a/lib/bashly/libraries/libraries.yml b/lib/bashly/libraries/libraries.yml
index 23187b08..c6afabf1 100644
--- a/lib/bashly/libraries/libraries.yml
+++ b/lib/bashly/libraries/libraries.yml
@@ -121,21 +121,6 @@ strings:
- source: "strings/strings.yml"
target: "%{user_source_dir}/bashly-strings.yml"
-test:
- help: Add approval testing.
- files:
- - source: "test/approvals.bash"
- target: "%{user_target_dir}/test/approvals.bash"
- - source: "test/approve"
- target: "%{user_target_dir}/test/approve"
-
- post_install_message: |
- Edit your tests in g`test/approve` and then run:
-
- m`$ test/approve`
-
- Docs: bu`https://github.com/DannyBen/approvals.bash`
-
validations:
help: Add argument validation functions to the lib directory.
files:
diff --git a/lib/bashly/libraries/test/approvals.bash b/lib/bashly/libraries/test/approvals.bash
deleted file mode 100644
index 9ee20d73..00000000
--- a/lib/bashly/libraries/test/approvals.bash
+++ /dev/null
@@ -1,172 +0,0 @@
-# approvals.bash v0.5.1
-#
-# Interactive approval testing for Bash.
-# https://github.com/DannyBen/approvals.bash
-#
-# shellcheck disable=SC2059
-# Disabling SC2059 (quoted format string) because we use dynamic format strings
-approve() {
- local expected approval approval_file actual cmd
- approvals_dir=${APPROVALS_DIR:=approvals}
-
- cmd=$1
- last_exit_code=0
- actual=$(eval "$cmd" 2>&1) || last_exit_code=$?
- if [[ -v allow_diff_regex && "$allow_diff_regex" ]]; then
- actual=$(echo "$actual" | sed -E "s/$allow_diff_regex/*/g")
- unset allow_diff_regex
- fi
- approval=$(printf "%b" "$cmd" | tr -s -c "[:alnum:]" _)
- approval_file="$approvals_dir/${2:-"$approval"}"
-
- [[ -d "$approvals_dir" ]] || mkdir "$approvals_dir"
-
- if [[ -f "$approval_file" ]]; then
- expected=$(cat "$approval_file")
- else
- printf -- "$new_diff_string\n" "$cmd"
- printf "%b\n" "$actual"
- printf -- "$new_diff_string\n" "$cmd"
- expected="$actual"
- user_approval "$cmd" "$actual" "$approval_file"
- return
- fi
-
- if [[ "$(printf "%b" "$actual")" = "$(printf "%b" "$expected")" ]]; then
- pass "$cmd"
- else
- printf -- "$changed_diff_string\n" "$cmd"
- $diff_cmd <(printf "%b" "$expected\n") <(printf "%b" "$actual\n") | tail -n +4
- printf -- "$changed_diff_string\n" "$cmd"
- user_approval "$cmd" "$actual" "$approval_file"
- fi
-}
-
-allow_diff() {
- allow_diff_regex="$1"
-}
-
-describe() {
- printf "$describe_string\n" "$*"
-}
-
-context() {
- printf "$context_string\n" "$*"
-}
-
-it() {
- printf "$it_string\n" "$*"
-}
-
-fail() {
- printf "$fail_string\n" "$*"
- exit 1
-}
-
-pass() {
- printf "$pass_string\n" "$*"
- return 0
-}
-
-expect_exit_code() {
- if [[ $last_exit_code == "$1" ]]; then
- pass "exit $last_exit_code"
- else
- fail "expected exit code $1, got $last_exit_code"
- fi
-}
-
-# Private
-
-print_in_color() {
- local color="$1"
- shift
- if [[ -z ${NO_COLOR+x} ]]; then
- printf "$color%b\e[0m\n" "$*"
- else
- printf "%b\n" "$*"
- fi
-}
-
-red() { print_in_color "\e[31m" "$*"; }
-green() { print_in_color "\e[32m" "$*"; }
-yellow() { print_in_color "\e[33m" "$*"; }
-blue() { print_in_color "\e[34m" "$*"; }
-magenta() { print_in_color "\e[35m" "$*"; }
-cyan() { print_in_color "\e[36m" "$*"; }
-bold() { print_in_color "\e[1m" "$*"; }
-underlined() { print_in_color "\e[4m" "$*"; }
-red_bold() { print_in_color "\e[1;31m" "$*"; }
-green_bold() { print_in_color "\e[1;32m" "$*"; }
-yellow_bold() { print_in_color "\e[1;33m" "$*"; }
-blue_bold() { print_in_color "\e[1;34m" "$*"; }
-magenta_bold() { print_in_color "\e[1;35m" "$*"; }
-cyan_bold() { print_in_color "\e[1;36m" "$*"; }
-red_underlined() { print_in_color "\e[4;31m" "$*"; }
-green_underlined() { print_in_color "\e[4;32m" "$*"; }
-yellow_underlined() { print_in_color "\e[4;33m" "$*"; }
-blue_underlined() { print_in_color "\e[4;34m" "$*"; }
-magenta_underlined() { print_in_color "\e[4;35m" "$*"; }
-cyan_underlined() { print_in_color "\e[4;36m" "$*"; }
-
-user_approval() {
- local cmd="$1"
- local actual="$2"
- local approval_file="$3"
-
- if [[ -v CI || -v GITHUB_ACTIONS ]] && [[ -z "${AUTO_APPROVE+x}" ]]; then
- fail "$cmd"
- fi
-
- if [[ -v AUTO_APPROVE ]]; then
- response=a
- else
- echo
- printf "$approval_string"
- response=$(bash -c "read -n 1 key; echo \$key")
- printf "\b%.s" $(seq 1 $((${#approval_string} + 1)))
- fi
-
- if [[ $response =~ [Aa] ]]; then
- printf "%b\n" "$actual" >"$approval_file"
- pass "$cmd"
- else
- fail "$cmd"
- fi
-}
-
-onexit() {
- exitcode=$?
- if [[ "$exitcode" == 0 ]]; then
- printf "$exit_success_string\n" "$0"
- else
- printf "$exit_failed_string\n" "$0"
- fi
- echo
- exit $exitcode
-}
-
-onerror() {
- fail "caller: $(caller)"
-}
-
-set -e
-trap 'onexit' EXIT
-trap 'onerror' ERR
-
-describe_string="$(bold ▌ describe) %s"
-context_string="$(bold ▌ context) %s"
-it_string="$(bold ▌ it) %s"
-fail_string=" $(red_bold failed) %s"
-pass_string=" $(green approved) %s"
-exit_success_string="$(green ▌ exit) $(bold %s finished successfully)"
-exit_failed_string="$(red_bold ▌ exit) $(bold %s finished with errors)"
-new_diff_string="────┤ $(yellow new): $(bold %s) ├────"
-changed_diff_string="────┤ $(blue changed): $(bold %s) ├────"
-approval_string="[A]pprove? "
-
-if diff --help | grep -- --color >/dev/null 2>&1; then
- diff_cmd="diff --unified --color=always"
-else
- diff_cmd="diff --unified"
-fi
diff --git a/lib/bashly/libraries/test/approve b/lib/bashly/libraries/test/approve
deleted file mode 100644
index cc90a0a7..00000000
--- a/lib/bashly/libraries/test/approve
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/env bash
-# Run this from the root directory
-
-cd ./test || exit
-source approvals.bash
-
-# Update me
-cli=./download
-
-# Tests (context, describe and indentation are optional)
-context "when DEBUG is on"
- export DEBUG=1
-
- describe "root command"
- approve "$cli"
- approve "$cli --help"
-
-context "when DEBUG is off"
- unset DEBUG
-
- describe "some other command"
- approve "$cli other"
- approve "$cli other --help"
-
-# ...more tests...
\ No newline at end of file
diff --git a/spec/approvals/cli/add/comp-function-file b/spec/approvals/cli/add/comp-function-file
index c39809fd..b1851a88 100644
--- a/spec/approvals/cli/add/comp-function-file
+++ b/spec/approvals/cli/add/comp-function-file
@@ -7,10 +7,9 @@ send_completions() {
echo $'# Modifying it manually is not recommended'
echo $''
echo $'_cli_completions_filter() {'
- echo $' local words=("$@")'
+ echo $' local words="$1"'
echo $' local cur=${COMP_WORDS[COMP_CWORD]}'
echo $' local result=()'
- echo $' local want_options=0'
echo $''
echo $' # words the user already typed (excluding the command itself)'
echo $' local used=()'
@@ -18,26 +17,28 @@ send_completions() {
echo $' used=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}")'
echo $' fi'
echo $''
- echo $' # Completing an option: offer everything.'
- echo $' # Completing a non-option: drop options and already-used words.'
- echo $' [[ "${cur:0:1}" == "-" ]] && want_options=1'
- echo $' for word in "${words[@]}"; do'
- echo $' if ((!want_options)); then'
+ 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}" == "-" ]] && continue'
echo $''
+ echo $' local seen=0'
echo $' for u in "${used[@]}"; do'
echo $' if [[ "$u" == "$word" ]]; then'
- echo $' continue 2'
+ echo $' seen=1'
+ echo $' break'
echo $' fi'
echo $' done'
- echo $' fi'
- echo $''
- echo $' # compgen -W expects shell-escaped words in one space-delimited string.'
- echo $' printf -v word \'%q\' "$word"'
- echo $' result+=("$word")'
- echo $' done'
+ echo $' ((!seen)) && result+=("$word")'
+ echo $' done'
echo $''
- echo $' echo "${result[*]}"'
+ echo $' echo "${result[*]}"'
+ echo $' fi'
echo $'}'
echo $''
echo $'_cli_completions() {'
@@ -52,23 +53,23 @@ send_completions() {
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")'
+ echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--force --help -f -h")" -- "$cur")'
echo $' ;;'
echo $''
echo $' \'upload\'*)'
- echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help" "--password" "--user" "-h" "-p" "-u")" -- "$cur")'
+ echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help --password --user -h -p -u")" -- "$cur")'
echo $' ;;'
echo $''
echo $' \'d\'*)'
- echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--force" "--help" "-f" "-h")" -- "$cur")'
+ echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--force --help -f -h")" -- "$cur")'
echo $' ;;'
echo $''
echo $' \'u\'*)'
- echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help" "--password" "--user" "-h" "-p" "-u")" -- "$cur")'
+ echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help --password --user -h -p -u")" -- "$cur")'
echo $' ;;'
echo $''
echo $' *)'
- echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help" "--version" "-h" "-v" "d" "download" "u" "upload")" -- "$cur")'
+ echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help --version -h -v d download u upload")" -- "$cur")'
echo $' ;;'
echo $''
echo $' esac'
diff --git a/spec/approvals/cli/add/comp-script-file b/spec/approvals/cli/add/comp-script-file
index b6f128fa..81a69f94 100644
--- a/spec/approvals/cli/add/comp-script-file
+++ b/spec/approvals/cli/add/comp-script-file
@@ -5,10 +5,9 @@
# Modifying it manually is not recommended
_cli_completions_filter() {
- local words=("$@")
+ local words="$1"
local cur=${COMP_WORDS[COMP_CWORD]}
local result=()
- local want_options=0
# words the user already typed (excluding the command itself)
local used=()
@@ -16,26 +15,28 @@ _cli_completions_filter() {
used=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}")
fi
- # Completing an option: offer everything.
- # Completing a non-option: drop options and already-used words.
- [[ "${cur:0:1}" == "-" ]] && want_options=1
- for word in "${words[@]}"; do
- if ((!want_options)); then
+ 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}" == "-" ]] && continue
+ local seen=0
for u in "${used[@]}"; do
if [[ "$u" == "$word" ]]; then
- continue 2
+ seen=1
+ break
fi
done
- fi
-
- # compgen -W expects shell-escaped words in one space-delimited string.
- printf -v word '%q' "$word"
- result+=("$word")
- done
+ ((!seen)) && result+=("$word")
+ done
- echo "${result[*]}"
+ echo "${result[*]}"
+ fi
}
_cli_completions() {
@@ -50,23 +51,23 @@ _cli_completions() {
case "$compline" in
'download'*)
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--force" "--help" "-f" "-h")" -- "$cur")
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--force --help -f -h")" -- "$cur")
;;
'upload'*)
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help" "--password" "--user" "-h" "-p" "-u")" -- "$cur")
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help --password --user -h -p -u")" -- "$cur")
;;
'd'*)
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--force" "--help" "-f" "-h")" -- "$cur")
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--force --help -f -h")" -- "$cur")
;;
'u'*)
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help" "--password" "--user" "-h" "-p" "-u")" -- "$cur")
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help --password --user -h -p -u")" -- "$cur")
;;
*)
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help" "--version" "-h" "-v" "d" "download" "u" "upload")" -- "$cur")
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help --version -h -v d download u upload")" -- "$cur")
;;
esac
diff --git a/spec/approvals/cli/add/list b/spec/approvals/cli/add/list
index fbdd60c5..ccde5e5c 100644
--- a/spec/approvals/cli/add/list
+++ b/spec/approvals/cli/add/list
@@ -49,9 +49,6 @@ strings
Copy an additional configuration file to your project, allowing you to
customize all the tips and error strings.
-test
- Add approval testing.
-
validations
Add argument validation functions to the lib directory.
diff --git a/spec/approvals/completions/function b/spec/approvals/completions/function
index a8831ded..7c865f25 100644
--- a/spec/approvals/completions/function
+++ b/spec/approvals/completions/function
@@ -6,10 +6,9 @@ custom_name() {
echo $'# Modifying it manually is not recommended'
echo $''
echo $'_get_completions_filter() {'
- echo $' local words=("$@")'
+ echo $' local words="$1"'
echo $' local cur=${COMP_WORDS[COMP_CWORD]}'
echo $' local result=()'
- echo $' local want_options=0'
echo $''
echo $' # words the user already typed (excluding the command itself)'
echo $' local used=()'
@@ -17,26 +16,28 @@ custom_name() {
echo $' used=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}")'
echo $' fi'
echo $''
- echo $' # Completing an option: offer everything.'
- echo $' # Completing a non-option: drop options and already-used words.'
- echo $' [[ "${cur:0:1}" == "-" ]] && want_options=1'
- echo $' for word in "${words[@]}"; do'
- echo $' if ((!want_options)); then'
+ 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}" == "-" ]] && continue'
echo $''
+ echo $' local seen=0'
echo $' for u in "${used[@]}"; do'
echo $' if [[ "$u" == "$word" ]]; then'
- echo $' continue 2'
+ echo $' seen=1'
+ echo $' break'
echo $' fi'
echo $' done'
- echo $' fi'
- echo $''
- echo $' # compgen -W expects shell-escaped words in one space-delimited string.'
- echo $' printf -v word \'%q\' "$word"'
- echo $' result+=("$word")'
- echo $' done'
+ echo $' ((!seen)) && result+=("$word")'
+ echo $' done'
echo $''
- echo $' echo "${result[*]}"'
+ echo $' echo "${result[*]}"'
+ echo $' fi'
echo $'}'
echo $''
echo $'_get_completions() {'
@@ -51,7 +52,8 @@ custom_name() {
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")'
+ echo $' compopt -o filenames 2>/dev/null'
+ echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A file -W "$(_get_completions_filter "--force --help --verbose --version -h -v")" -- "$cur")'
echo $' ;;'
echo $''
echo $' esac'
diff --git a/spec/approvals/completions/script b/spec/approvals/completions/script
index 68e0e75c..92a91a34 100644
--- a/spec/approvals/completions/script
+++ b/spec/approvals/completions/script
@@ -5,10 +5,9 @@
# Modifying it manually is not recommended
_say_completions_filter() {
- local words=("$@")
+ local words="$1"
local cur=${COMP_WORDS[COMP_CWORD]}
local result=()
- local want_options=0
# words the user already typed (excluding the command itself)
local used=()
@@ -16,26 +15,28 @@ _say_completions_filter() {
used=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}")
fi
- # Completing an option: offer everything.
- # Completing a non-option: drop options and already-used words.
- [[ "${cur:0:1}" == "-" ]] && want_options=1
- for word in "${words[@]}"; do
- if ((!want_options)); then
+ 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}" == "-" ]] && continue
+ local seen=0
for u in "${used[@]}"; do
if [[ "$u" == "$word" ]]; then
- continue 2
+ seen=1
+ break
fi
done
- fi
-
- # compgen -W expects shell-escaped words in one space-delimited string.
- printf -v word '%q' "$word"
- result+=("$word")
- done
+ ((!seen)) && result+=("$word")
+ done
- echo "${result[*]}"
+ echo "${result[*]}"
+ fi
}
_say_completions() {
@@ -50,35 +51,37 @@ _say_completions() {
case "$compline" in
'goodbye universe'*'--color')
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_say_completions_filter "green" "red")" -- "$cur")
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_say_completions_filter "green red")" -- "$cur")
;;
'goodbye universe'*'--path')
+ compopt -o filenames 2>/dev/null
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A file -- "$cur")
;;
'goodbye universe'*'-c')
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_say_completions_filter "green" "red")" -- "$cur")
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_say_completions_filter "green red")" -- "$cur")
;;
'goodbye universe'*)
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_say_completions_filter "$(git branch)" "--color" "--help" "--path" "--verbose" "-c" "-h" "-v")" -- "$cur")
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_say_completions_filter "$(git branch) --color --help --path --verbose -c -h -v")" -- "$cur")
;;
'hello world'*)
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A directory -A user -W "$(_say_completions_filter "--force" "--help" "--verbose" "-h")" -- "$cur")
+ compopt -o filenames 2>/dev/null
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A directory -A user -W "$(_say_completions_filter "--force --help --verbose -h")" -- "$cur")
;;
'goodbye'*)
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_say_completions_filter "--help" "-h" "universe")" -- "$cur")
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_say_completions_filter "--help -h universe")" -- "$cur")
;;
'hello'*)
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_say_completions_filter "--help" "-h" "world")" -- "$cur")
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_say_completions_filter "--help -h world")" -- "$cur")
;;
*)
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_say_completions_filter "--help" "--version" "-h" "-v" "goodbye" "hello")" -- "$cur")
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_say_completions_filter "--help --version -h -v goodbye hello")" -- "$cur")
;;
esac
diff --git a/spec/approvals/examples/completions b/spec/approvals/examples/completions
index dba6fd46..9dd2f329 100644
--- a/spec/approvals/examples/completions
+++ b/spec/approvals/examples/completions
@@ -69,10 +69,9 @@ Options:
# Modifying it manually is not recommended
_cli_completions_filter() {
- local words=("$@")
+ local words="$1"
local cur=${COMP_WORDS[COMP_CWORD]}
local result=()
- local want_options=0
# words the user already typed (excluding the command itself)
local used=()
@@ -80,26 +79,28 @@ _cli_completions_filter() {
used=("${COMP_WORDS[@]:1:$((COMP_CWORD - 1))}")
fi
- # Completing an option: offer everything.
- # Completing a non-option: drop options and already-used words.
- [[ "${cur:0:1}" == "-" ]] && want_options=1
- for word in "${words[@]}"; do
- if ((!want_options)); then
+ 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}" == "-" ]] && continue
+ local seen=0
for u in "${used[@]}"; do
if [[ "$u" == "$word" ]]; then
- continue 2
+ seen=1
+ break
fi
done
- fi
-
- # compgen -W expects shell-escaped words in one space-delimited string.
- printf -v word '%q' "$word"
- result+=("$word")
- done
+ ((!seen)) && result+=("$word")
+ done
- echo "${result[*]}"
+ echo "${result[*]}"
+ fi
}
_cli_completions() {
@@ -114,7 +115,7 @@ _cli_completions() {
case "$compline" in
'download'*'--handler')
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "curl" "wget")" -- "$cur")
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "curl wget")" -- "$cur")
;;
'upload'*'--user')
@@ -122,11 +123,11 @@ _cli_completions() {
;;
'completions'*)
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help" "-h")" -- "$cur")
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help -h")" -- "$cur")
;;
'd'*'--handler')
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "curl" "wget")" -- "$cur")
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "curl wget")" -- "$cur")
;;
'upload'*'-u')
@@ -134,7 +135,8 @@ _cli_completions() {
;;
'download'*)
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A file -W "$(_cli_completions_filter "--force" "--handler" "--help" "-f" "-h")" -- "$cur")
+ compopt -o filenames 2>/dev/null
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A file -W "$(_cli_completions_filter "--force --handler --help -f -h")" -- "$cur")
;;
'u'*'--user')
@@ -142,7 +144,8 @@ _cli_completions() {
;;
'upload'*)
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A directory -A user -W "$(_cli_completions_filter "--help" "--password" "--user" "-h" "-p" "-u" "CHANGELOG.md" "README.md")" -- "$cur")
+ compopt -o filenames 2>/dev/null
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A directory -A user -W "$(_cli_completions_filter "--help --password --user -h -p -u CHANGELOG.md README.md")" -- "$cur")
;;
'u'*'-u')
@@ -150,15 +153,17 @@ _cli_completions() {
;;
'd'*)
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A file -W "$(_cli_completions_filter "--force" "--handler" "--help" "-f" "-h")" -- "$cur")
+ compopt -o filenames 2>/dev/null
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A file -W "$(_cli_completions_filter "--force --handler --help -f -h")" -- "$cur")
;;
'u'*)
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A directory -A user -W "$(_cli_completions_filter "--help" "--password" "--user" "-h" "-p" "-u" "CHANGELOG.md" "README.md")" -- "$cur")
+ compopt -o filenames 2>/dev/null
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A directory -A user -W "$(_cli_completions_filter "--help --password --user -h -p -u CHANGELOG.md README.md")" -- "$cur")
;;
*)
- while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help" "--version" "-h" "-v" "completions" "d" "download" "u" "upload")" -- "$cur")
+ while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_cli_completions_filter "--help --version -h -v completions d download u upload")" -- "$cur")
;;
esac
diff --git a/spec/approvals/examples/render-mandoc b/spec/approvals/examples/render-mandoc
index cabe46c7..e3a8095f 100644
--- a/spec/approvals/examples/render-mandoc
+++ b/spec/approvals/examples/render-mandoc
@@ -3,45 +3,45 @@ saved docs/download.1
download(1) Sample application download(1)
NAME
- download - Sample application
+ download - Sample application
SYNOPSIS
- download SOURCE [TARGET...] OPTIONS
+ download SOURCE [TARGET...] OPTIONS
DESCRIPTION
- Sample application
+ Sample application
ARGUMENTS
SOURCE
- Source to download from
+ Source to download from
- • Required
+ • Required
- • Allowed Values: server1, server2
+ • Allowed Values: server1, server2
TARGET
- Target filename (default: same as source)
+ Target filename (default: same as source)
- • Repeatable
+ • Repeatable
OPTIONS
--force, -f
- Overwrite existing files
+ Overwrite existing files
--debug, -d
- Show debug information
+ Show debug information
DEPENDENCIES
aws-cli
- Download from
+ Download from
SEE ALSO
- docker(1), docker-compose.yml(5)
+ docker(1), docker-compose.yml(5)
ISSUE TRACKER
- Report issues at
+ Report issues at
AUTHORS
- Lana Lang.
+ Lana Lang.