# qpdf bash completion
#
# Most of this logic was generated by Anthropic Claude Opus 4.7. The
# tabular data is automatically generated.
#
# Design note: bash's default COMP_WORDBREAKS contains '=', which makes
# "--opt=<cursor>" awkward — bash thinks the current word is only the text
# after the '='. Rather than fight this with brittle quoting hacks, this
# completion accepts the default bash behavior:
#   * --opt=<TAB>        completes <value> against the option's value set
#   * --opt= <TAB>       (with an inserted space) falls through to bash's
#                        normal positional filename completion, which gets
#                        you $VAR and ~ expansion for free.
# The second form is the intended workaround for filename values in bash;
# zsh handles --opt=<TAB> filename completion natively and is the more
# functional of the two shells.

# Per-option attributes, keyed by "<table>.<option>".
# _QPDF_ARITY:  bare | opt | req
# _QPDF_VALUES: "none" | "file" | space-separated choice list
# _QPDF_NEXT:   "" | next-table | "@value" (value-dispatched)
# _QPDF_VNEXT:  "<table>.<option>.<value>" -> next table
declare -gA _QPDF_ARITY _QPDF_VALUES _QPDF_NEXT _QPDF_VNEXT

_qpdf_def() {
    _QPDF_ARITY["$1.$2"]=$3
    _QPDF_VALUES["$1.$2"]=$4
    _QPDF_NEXT["$1.$2"]=$5
}

# BEGIN GENERATED
declare -gA _QPDF_OPTS=(
    [help]="--version --copyright --show-crypto --job-json-help --zopfli --json-help --completion-bash --completion-zsh --help"
    [global]="--no-default-limits --parser-max-container-size --parser-max-container-size-damaged --parser-max-errors --parser-max-nesting --max-stream-filters"
    [main]="--add-attachment --allow-weak-crypto --check --check-linearization --coalesce-contents --copy-attachments-from --decrypt --deterministic-id --empty --encrypt --externalize-inline-images --filtered-stream-data --flatten-rotation --generate-appearances --global --ignore-xref-streams --is-encrypted --json-input --keep-inline-images --linearize --list-attachments --newline-before-endstream --no-original-object-ids --no-warn --optimize-images --overlay --pages --password-is-hex-key --preserve-unreferenced --preserve-unreferenced-resources --progress --qdf --raw-stream-data --recompress-flate --remove-acroform --remove-info --remove-metadata --remove-page-labels --remove-structure --replace-input --report-memory-usage --requires-password --remove-restrictions --set-page-labels --show-encryption --show-encryption-key --show-linearization --show-npages --show-pages --show-xref --static-aes-iv --static-id --suppress-password-recovery --suppress-recovery --test-json-schema --underlay --verbose --warning-exit-0 --with-images --compression-level --jpeg-quality --encryption-file-password --force-version --ii-min-bytes --json-object --keep-files-open-threshold --min-version --oi-min-area --oi-min-height --oi-min-width --password --remove-attachment --rotate --show-attachment --show-object --copy-encryption --job-json-file --linearize-pass1 --password-file --update-from-json --json-stream-prefix --collate --split-pages --compress-streams --decode-level --flatten-annotations --json-key --json-stream-data --keep-files-open --normalize-content --object-streams --password-mode --remove-unreferenced-resources --stream-data --json --json-output"
    [pages]="--range --password --file"
    [encryption]="--user-password --owner-password --bits"
    [40-bit-encryption]="--extract --annotate --print --modify"
    [128-bit-encryption]="--cleartext-metadata --force-V4 --accessibility --extract --print --assemble --annotate --form --modify-other --modify --use-aes"
    [256-bit-encryption]="--cleartext-metadata --force-R5 --allow-insecure --accessibility --extract --print --assemble --annotate --form --modify-other --modify"
    [underlay/overlay]="--to --from --repeat --password --file"
    [attachment]="--replace --key --filename --creationdate --moddate --mimetype --description"
    [copy-attachment]="--prefix --password"
    [set-page-labels]=""
)
_qpdf_def help --version bare "none" ""
_qpdf_def help --copyright bare "none" ""
_qpdf_def help --show-crypto bare "none" ""
_qpdf_def help --job-json-help bare "none" ""
_qpdf_def help --zopfli bare "none" ""
_qpdf_def help --json-help opt "1 2 latest" ""
_qpdf_def global --no-default-limits bare "none" ""
_qpdf_def global --parser-max-container-size req "none" ""
_qpdf_def global --parser-max-container-size-damaged req "none" ""
_qpdf_def global --parser-max-errors req "none" ""
_qpdf_def global --parser-max-nesting req "none" ""
_qpdf_def global --max-stream-filters req "none" ""
_qpdf_def main --add-attachment bare "none" "attachment"
_qpdf_def main --allow-weak-crypto bare "none" ""
_qpdf_def main --check bare "none" ""
_qpdf_def main --check-linearization bare "none" ""
_qpdf_def main --coalesce-contents bare "none" ""
_qpdf_def main --copy-attachments-from bare "none" "copy-attachment"
_qpdf_def main --decrypt bare "none" ""
_qpdf_def main --deterministic-id bare "none" ""
_qpdf_def main --empty bare "none" ""
_qpdf_def main --encrypt bare "none" "encryption"
_qpdf_def main --externalize-inline-images bare "none" ""
_qpdf_def main --filtered-stream-data bare "none" ""
_qpdf_def main --flatten-rotation bare "none" ""
_qpdf_def main --generate-appearances bare "none" ""
_qpdf_def main --global bare "none" ""
_qpdf_def main --ignore-xref-streams bare "none" ""
_qpdf_def main --is-encrypted bare "none" ""
_qpdf_def main --json-input bare "none" ""
_qpdf_def main --keep-inline-images bare "none" ""
_qpdf_def main --linearize bare "none" ""
_qpdf_def main --list-attachments bare "none" ""
_qpdf_def main --newline-before-endstream bare "none" ""
_qpdf_def main --no-original-object-ids bare "none" ""
_qpdf_def main --no-warn bare "none" ""
_qpdf_def main --optimize-images bare "none" ""
_qpdf_def main --overlay bare "none" "underlay/overlay"
_qpdf_def main --pages bare "none" "pages"
_qpdf_def main --password-is-hex-key bare "none" ""
_qpdf_def main --preserve-unreferenced bare "none" ""
_qpdf_def main --preserve-unreferenced-resources bare "none" ""
_qpdf_def main --progress bare "none" ""
_qpdf_def main --qdf bare "none" ""
_qpdf_def main --raw-stream-data bare "none" ""
_qpdf_def main --recompress-flate bare "none" ""
_qpdf_def main --remove-acroform bare "none" ""
_qpdf_def main --remove-info bare "none" ""
_qpdf_def main --remove-metadata bare "none" ""
_qpdf_def main --remove-page-labels bare "none" ""
_qpdf_def main --remove-structure bare "none" ""
_qpdf_def main --replace-input bare "none" ""
_qpdf_def main --report-memory-usage bare "none" ""
_qpdf_def main --requires-password bare "none" ""
_qpdf_def main --remove-restrictions bare "none" ""
_qpdf_def main --set-page-labels bare "none" "set-page-labels"
_qpdf_def main --show-encryption bare "none" ""
_qpdf_def main --show-encryption-key bare "none" ""
_qpdf_def main --show-linearization bare "none" ""
_qpdf_def main --show-npages bare "none" ""
_qpdf_def main --show-pages bare "none" ""
_qpdf_def main --show-xref bare "none" ""
_qpdf_def main --static-aes-iv bare "none" ""
_qpdf_def main --static-id bare "none" ""
_qpdf_def main --suppress-password-recovery bare "none" ""
_qpdf_def main --suppress-recovery bare "none" ""
_qpdf_def main --test-json-schema bare "none" ""
_qpdf_def main --underlay bare "none" "underlay/overlay"
_qpdf_def main --verbose bare "none" ""
_qpdf_def main --warning-exit-0 bare "none" ""
_qpdf_def main --with-images bare "none" ""
_qpdf_def main --compression-level req "none" ""
_qpdf_def main --jpeg-quality req "none" ""
_qpdf_def main --encryption-file-password req "none" ""
_qpdf_def main --force-version req "none" ""
_qpdf_def main --ii-min-bytes req "none" ""
_qpdf_def main --json-object req "none" ""
_qpdf_def main --keep-files-open-threshold req "none" ""
_qpdf_def main --min-version req "none" ""
_qpdf_def main --oi-min-area req "none" ""
_qpdf_def main --oi-min-height req "none" ""
_qpdf_def main --oi-min-width req "none" ""
_qpdf_def main --password req "none" ""
_qpdf_def main --remove-attachment req "none" ""
_qpdf_def main --rotate req "none" ""
_qpdf_def main --show-attachment req "none" ""
_qpdf_def main --show-object req "none" ""
_qpdf_def main --copy-encryption req "file" ""
_qpdf_def main --job-json-file req "file" ""
_qpdf_def main --linearize-pass1 req "file" ""
_qpdf_def main --password-file req "file" ""
_qpdf_def main --update-from-json req "file" ""
_qpdf_def main --json-stream-prefix req "file" ""
_qpdf_def main --collate opt "none" ""
_qpdf_def main --split-pages opt "none" ""
_qpdf_def main --compress-streams req "y n" ""
_qpdf_def main --decode-level req "none generalized specialized all" ""
_qpdf_def main --flatten-annotations req "all print screen" ""
_qpdf_def main --json-key req "acroform attachments encrypt objectinfo objects outlines pagelabels pages qpdf" ""
_qpdf_def main --json-stream-data req "none inline file" ""
_qpdf_def main --keep-files-open req "y n" ""
_qpdf_def main --normalize-content req "y n" ""
_qpdf_def main --object-streams req "disable preserve generate" ""
_qpdf_def main --password-mode req "bytes hex-bytes unicode auto" ""
_qpdf_def main --remove-unreferenced-resources req "auto yes no" ""
_qpdf_def main --stream-data req "compress preserve uncompress" ""
_qpdf_def main --json opt "1 2 latest" ""
_qpdf_def main --json-output opt "2 latest" ""
_qpdf_def pages --range req "none" ""
_qpdf_def pages --password req "none" ""
_qpdf_def pages --file req "file" ""
_qpdf_def encryption --user-password req "none" ""
_qpdf_def encryption --owner-password req "none" ""
_qpdf_def encryption --bits req "40 128 256" "@value"
_qpdf_def 40-bit-encryption --extract req "y n" ""
_qpdf_def 40-bit-encryption --annotate req "y n" ""
_qpdf_def 40-bit-encryption --print req "y n" ""
_qpdf_def 40-bit-encryption --modify req "y n" ""
_qpdf_def 128-bit-encryption --cleartext-metadata bare "none" ""
_qpdf_def 128-bit-encryption --force-V4 bare "none" ""
_qpdf_def 128-bit-encryption --accessibility req "y n" ""
_qpdf_def 128-bit-encryption --extract req "y n" ""
_qpdf_def 128-bit-encryption --print req "full low none" ""
_qpdf_def 128-bit-encryption --assemble req "y n" ""
_qpdf_def 128-bit-encryption --annotate req "y n" ""
_qpdf_def 128-bit-encryption --form req "y n" ""
_qpdf_def 128-bit-encryption --modify-other req "y n" ""
_qpdf_def 128-bit-encryption --modify req "all annotate form assembly none" ""
_qpdf_def 128-bit-encryption --use-aes req "y n" ""
_qpdf_def 256-bit-encryption --cleartext-metadata bare "none" ""
_qpdf_def 256-bit-encryption --force-R5 bare "none" ""
_qpdf_def 256-bit-encryption --allow-insecure bare "none" ""
_qpdf_def 256-bit-encryption --accessibility req "y n" ""
_qpdf_def 256-bit-encryption --extract req "y n" ""
_qpdf_def 256-bit-encryption --print req "full low none" ""
_qpdf_def 256-bit-encryption --assemble req "y n" ""
_qpdf_def 256-bit-encryption --annotate req "y n" ""
_qpdf_def 256-bit-encryption --form req "y n" ""
_qpdf_def 256-bit-encryption --modify-other req "y n" ""
_qpdf_def 256-bit-encryption --modify req "all annotate form assembly none" ""
_qpdf_def underlay/overlay --to req "none" ""
_qpdf_def underlay/overlay --from req "none" ""
_qpdf_def underlay/overlay --repeat req "none" ""
_qpdf_def underlay/overlay --password req "none" ""
_qpdf_def underlay/overlay --file req "file" ""
_qpdf_def attachment --replace bare "none" ""
_qpdf_def attachment --key req "none" ""
_qpdf_def attachment --filename req "none" ""
_qpdf_def attachment --creationdate req "none" ""
_qpdf_def attachment --moddate req "none" ""
_qpdf_def attachment --mimetype req "none" ""
_qpdf_def attachment --description req "none" ""
_qpdf_def copy-attachment --prefix req "none" ""
_qpdf_def copy-attachment --password req "none" ""
_qpdf_def help --help opt "--accessibility --add-attachment --allow-insecure --allow-weak-crypto --annotate --assemble --bits --check --check-linearization --cleartext-metadata --coalesce-contents --collate --completion-bash --completion-zsh --compress-streams --compression-level --copy-attachments-from --copy-encryption --copyright --creationdate --decode-level --decrypt --description --deterministic-id --empty --encrypt --encryption-file-password --externalize-inline-images --extract --file --filename --filtered-stream-data --flatten-annotations --flatten-rotation --force-R5 --force-V4 --force-version --form --from --generate-appearances --global --help --ignore-xref-streams --ii-min-bytes --is-encrypted --job-json-file --job-json-help --jpeg-quality --json --json-help --json-input --json-key --json-object --json-output --json-stream-data --json-stream-prefix --keep-files-open --keep-files-open-threshold --keep-inline-images --key --linearize --linearize-pass1 --list-attachments --max-stream-filters --mimetype --min-version --moddate --modify --modify-other --newline-before-endstream --no-default-limits --no-original-object-ids --no-warn --normalize-content --object-streams --oi-min-area --oi-min-height --oi-min-width --optimize-images --overlay --owner-password --pages --parser-max-container-size --parser-max-container-size-damaged --parser-max-errors --parser-max-nesting --password --password-file --password-is-hex-key --password-mode --prefix --preserve-unreferenced --preserve-unreferenced-resources --print --progress --qdf --range --raw-stream-data --recompress-flate --remove-acroform --remove-attachment --remove-info --remove-metadata --remove-page-labels --remove-restrictions --remove-structure --remove-unreferenced-resources --repeat --replace --replace-input --report-memory-usage --requires-password --rotate --set-page-labels --show-attachment --show-crypto --show-encryption --show-encryption-key --show-linearization --show-npages --show-object --show-pages --show-xref --split-pages --static-aes-iv --static-id --stream-data --suppress-password-recovery --suppress-recovery --test-json-schema --to --underlay --update-from-json --use-aes --user-password --verbose --version --warning-exit-0 --with-images --zopfli add-attachment advanced-control all attachments completion copy-attachments encryption exit-status general global help inspection json modification overlay-underlay page-ranges page-selection pdf-dates testing transformation usage" ""
_qpdf_def help --completion-bash bare "none" ""
_qpdf_def help --completion-zsh bare "none" ""
_QPDF_VNEXT[encryption.--bits.40]=40-bit-encryption
_QPDF_VNEXT[encryption.--bits.128]=128-bit-encryption
_QPDF_VNEXT[encryption.--bits.256]=256-bit-encryption
# END GENERATED

unset -f _qpdf_def

# Strip one layer of balanced surrounding "..." or '...' quotes.
_qpdf_unquote() {
    local s=$1
    if [[ ${#s} -ge 2 ]]; then
        if [[ $s == \"*\" ]]; then s=${s:1:${#s}-2}; fi
        if [[ $s == \'*\' ]]; then s=${s:1:${#s}-2}; fi
    fi
    printf '%s' "$s"
}

# ---- Completion function --------------------------------------------------
_qpdf() {
    # Reassemble COMP_WORDS so a triple "--opt" "=" "val" becomes one logical
    # token "--opt=<unquoted-val>". Needed because '=' is a wordbreak.
    local -a prior=()
    local -i j=0 limit=$COMP_CWORD
    local raw w val
    # If the current token is completing a value (cursor is at "=" after
    # --opt, or after "=" after --opt), exclude those tokens from the
    # prior-arg loop — they belong to the arg being completed, not to
    # already-processed prior args. Without this, --opt gets processed as
    # prior and merge_help is cleared before the current-token lookup
    # runs, which breaks fallback to the help.* table.
    if [[ ${COMP_WORDS[limit]} == "=" ]] && (( limit >= 1 )) \
         && [[ ${COMP_WORDS[limit-1]} == --* ]]; then
        limit=$((limit-1))
    elif (( limit >= 2 )) && [[ ${COMP_WORDS[limit-1]} == "=" ]] \
         && [[ ${COMP_WORDS[limit-2]} == --* ]]; then
        limit=$((limit-2))
    fi
    while (( j < limit )); do
        raw=${COMP_WORDS[j]}
        w=$(_qpdf_unquote "$raw")
        if [[ $w == --* ]] && (( j+1 < limit )) && [[ ${COMP_WORDS[j+1]} == "=" ]]; then
            if (( j+2 < limit )); then
                val=$(_qpdf_unquote "${COMP_WORDS[j+2]}")
                prior+=( "$w=$val" )
                j=$((j+3))
            else
                prior+=( "$w=" )
                j=$((j+2))
            fi
        else
            prior+=( "$w" )
            j=$((j+1))
        fi
    done
    prior=( "${prior[@]:1}" )   # drop argv[0]

    local cur_table=main
    local merge_help=1
    local i p opt key next vk
    for (( i=0; i<${#prior[@]}; i++ )); do
        p=${prior[i]}
        if [[ $p == "--" ]]; then
            cur_table=main; merge_help=0; continue
        fi
        if [[ $p == --*=* ]]; then
            opt=${p%%=*}; val=${p#*=}
        elif [[ $p == --* ]]; then
            opt=$p; val=""
        else
            merge_help=0; continue
        fi
        key="$cur_table.$opt"
        if [[ -z ${_QPDF_ARITY[$key]+x} ]] && (( merge_help )); then
            key="help.$opt"
        fi
        merge_help=0
        [[ -z ${_QPDF_ARITY[$key]+x} ]] && continue
        next=${_QPDF_NEXT[$key]}
        if [[ $next == "@value" ]]; then
            vk="$key.$val"
            [[ -n ${_QPDF_VNEXT[$vk]+x} ]] && cur_table=${_QPDF_VNEXT[$vk]}
        elif [[ -n $next ]]; then
            cur_table=$next
        fi
    done
    (( ${#prior[@]} == 0 )) && merge_help=1

    # Classify current position via COMP_WORDS (already split by bash).
    local raw_cur=${COMP_WORDS[COMP_CWORD]}
    local mode="" cur_opt=""
    if (( COMP_CWORD >= 2 ))          && [[ ${COMP_WORDS[COMP_CWORD-1]} == "=" ]] \
           && [[ $(_qpdf_unquote "${COMP_WORDS[COMP_CWORD-2]}") == --* ]]; then
        # Must be checked before the "--*" option branch: values for options
        # like --help start with "--" themselves (e.g. --help=--prefix).
        mode=value
        cur_opt=$(_qpdf_unquote "${COMP_WORDS[COMP_CWORD-2]}")
    elif [[ $raw_cur == --* && $raw_cur != *=* ]]; then
        mode=option
    elif [[ $raw_cur == "=" ]] && (( COMP_CWORD >= 1 )) \
             && [[ $(_qpdf_unquote "${COMP_WORDS[COMP_CWORD-1]}") == --* ]]; then
        mode=value
        cur_opt=$(_qpdf_unquote "${COMP_WORDS[COMP_CWORD-1]}")
        raw_cur=""
    elif [[ $raw_cur == --*=* ]]; then
        mode=value
        cur_opt=${raw_cur%%=*}
        raw_cur=${raw_cur#*=}
    else
        mode=positional
    fi

    COMPREPLY=()

    case $mode in
        option)
            local all=${_QPDF_OPTS[$cur_table]}
            (( merge_help )) && all+=" ${_QPDF_OPTS[help]}"
            local o a k
            for o in $all; do
                [[ $o != "$raw_cur"* ]] && continue
                k="$cur_table.$o"
                [[ -z ${_QPDF_ARITY[$k]+x} ]] && k="help.$o"
                a=${_QPDF_ARITY[$k]}
                case $a in
                    bare) COMPREPLY+=( "$o " ) ;;
                    req)  COMPREPLY+=( "$o=" ) ;;
                    opt)  COMPREPLY+=( "$o " "$o=" ) ;;
                esac
            done
            compopt -o nospace 2>/dev/null
            ;;
        value)
            local key="$cur_table.$cur_opt"
            if [[ -z ${_QPDF_ARITY[$key]+x} ]] && (( merge_help )); then
                key="help.$cur_opt"
            fi
            [[ -z ${_QPDF_ARITY[$key]+x} ]] && return 0
            local vs=${_QPDF_VALUES[$key]}
            case $vs in
                none) return 0 ;;
                file)
                    # Best-effort: bash's cur after '=' is just the path
                    # tail. No ~ / $VAR expansion here; see header comment.
                    COMPREPLY=( $(compgen -f -- "$raw_cur") )
                    compopt -o filenames 2>/dev/null
                    ;;
                *)
                    local c
                    for c in $vs; do
                        [[ $c == "$raw_cur"* ]] && COMPREPLY+=( "$c" )
                    done
                    ;;
            esac
            ;;
        positional)
            COMPREPLY=( $(compgen -f -- "$raw_cur") )
            compopt -o filenames 2>/dev/null
            ;;
    esac
    return 0
}

complete -F _qpdf qpdf
