Skip to content

Commit

Permalink
progcomp: fix non-working "complete -C prog"
Browse files Browse the repository at this point in the history
  • Loading branch information
akinomyoga committed May 6, 2021
1 parent 9e786ae commit 026432d
Show file tree
Hide file tree
Showing 5 changed files with 285 additions and 71 deletions.
227 changes: 156 additions & 71 deletions lib/core-complete.sh
Expand Up @@ -1191,7 +1191,7 @@ function ble/complete/action:progcomp/complete {
if [[ $DATA == *:filenames:* ]]; then
ble/complete/action:file/complete
else
if [[ -d $CAND ]]; then
if [[ $DATA != *:no-mark-directories:* && -d $CAND ]]; then
ble/complete/action/util/complete.mark-directory
else
ble/complete/action:word/complete
Expand Down Expand Up @@ -2235,7 +2235,15 @@ function ble/complete/progcomp/.compgen-helper-prog {
local -x COMP_LINE COMP_POINT COMP_TYPE COMP_KEY
ble/complete/progcomp/.compvar-initialize
local cmd=${COMP_WORDS[0]} cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
"$comp_prog" "$cmd" "$cur" "$prev" < /dev/null

if [[ $comp_opts == *:prog-trim:* ]]; then
# WA: aws_completer
local compreply
ble/util/assign compreply '"$comp_prog" "$cmd" "$cur" "$prev" < /dev/null'
ble/bin/sed "s/[[:space:]]\{1,\}\$//" <<< "$compreply"
else
"$comp_prog" "$cmd" "$cur" "$prev" < /dev/null
fi
fi
}
# compopt に介入して -o/+o option を読み取る。
Expand Down Expand Up @@ -2304,6 +2312,116 @@ function ble/complete/progcomp/.compgen-helper-func {
fi
}

## @fn ble/complete/progcomp/.parse-complete/next
## @var[out] optarg
## @var[in,out] compdef
## @var[in] rex
function ble/complete/progcomp/.parse-complete/next {
if [[ $compdef =~ $rex ]]; then
builtin eval "arg=$BASH_REMATCH"
compdef=${compdef:${#BASH_REMATCH}}
return 0
elif [[ ${compdef%%' '*} ]]; then
# 本来此処には来ない筈
arg=${compdef%%' '*}
compdef=${compdef#*' '}
return 0
else
return 1
fi
}
function ble/complete/progcomp/.parse-complete/optarg {
optarg=
if ((ic+1<${#arg})); then
optarg=${arg:ic+1}
ic=${#arg}
return 0
elif [[ $compdef =~ $rex ]]; then
builtin eval "optarg=$BASH_REMATCH"
compdef=${compdef:${#BASH_REMATCH}}
return 0
else
return 2
fi
}
## @fn ble/complete/progcomp/.parse-complete compdef
## @param[in] compdef
## @var[in,out] comp_opts
## @var[out] compoptions comp_prog comp_func flag_noquote
function ble/complete/progcomp/.parse-complete {
compoptions=()
comp_prog=
comp_func=
flag_noquote=
local compdef=${1#'complete '}

local arg optarg rex='^([^][*?;&|[:space:]<>()\`$"'\''{}#^!]|\\.|'\''[^'\'']*'\'')+[[:space:]]+'
while ble/complete/progcomp/.parse-complete/next; do
case $arg in
(-*)
local ic c
for ((ic=1;ic<${#arg};ic++)); do
c=${arg:ic:1}
case "$c" in
([abcdefgjksuvE])
# Note: workaround #D0714 #M0009 #D0870
case $c in
(c) flag_noquote=1 ;;
(d) ((_ble_bash>=40300)) && flag_noquote=1 ;;
(f) ((40000<=_ble_bash&&_ble_bash<40200)) && flag_noquote=1 ;;
esac
ble/array#push compoptions "-$c" ;;
([pr])
;; # 無視 (-p 表示 -r 削除)
([AGWXPS])
# Note: workaround #D0714 #M0009 #D0870
ble/complete/progcomp/.parse-complete/optarg || break 2
if [[ $c == A ]]; then
case $optarg in
(command) flag_noquote=1 ;;
(directory) ((_ble_bash>=40300)) && flag_noquote=1 ;;
(file) ((40000<=_ble_bash&&_ble_bash<40200)) && flag_noquote=1 ;;
esac
fi
ble/array#push compoptions "-$c" "$optarg" ;;
(o)
ble/complete/progcomp/.parse-complete/optarg || break 2
comp_opts=${comp_opts//:"$optarg":/:}$optarg:
ble/array#push compoptions "-$c" "$optarg" ;;
(C)
if ((_ble_bash<40000)); then
# bash-3.2以下では -C は一番最後に出力される (unquoted)
comp_prog=${compdef%' '}
compdef=
else
# bash-4.0以降では -C は quoted
ble/complete/progcomp/.parse-complete/optarg || break 2
comp_prog=$optarg
fi
ble/array#push compoptions "-$c" ble/complete/progcomp/.compgen-helper-prog ;;
(F)
# unquoted optarg (bash-3.2 以下では続きに unquoted -C prog が来得る)
if ((_ble_bash<40000)) && [[ $compdef == *' -C '* ]]; then
comp_prog=${compdef#*' -C '}
comp_prog=${comp_prog%' '}
ble/array#push compoptions '-C' ble/complete/progcomp/.compgen-helper-prog
comp_func=${compdef%%' -C '*}
else
comp_func=${compdef%' '}
fi
compdef=

ble/array#push compoptions "-$c" ble/complete/progcomp/.compgen-helper-func ;;
(*)
# -D, -I, etc. just discard
esac
done ;;
(*)
;; # 無視
esac
done
}

## @fn ble/complete/progcomp/.compgen opts
##
## @param[in] opts
Expand All @@ -2328,7 +2446,6 @@ function ble/complete/progcomp/.compgen-helper-func {
function ble/complete/progcomp/.compgen {
local opts=$1

local comp_prog= comp_func=
local compcmd= is_default_completion= is_special_completion=
local -a alias_args=()
if [[ :$opts: == *:initial:* ]]; then
Expand All @@ -2343,77 +2460,45 @@ function ble/complete/progcomp/.compgen {
compcmd=${comp_words[0]}
fi

local -a compargs compoptions=()
local ret iarg=1 flag_noquote=
local compdef
if [[ $is_special_completion ]]; then
ble/util/assign ret 'builtin complete -p "$compcmd" 2>/dev/null'
# -I, -D, etc.
ble/util/assign compdef 'builtin complete -p "$compcmd" 2>/dev/null'
else
ble/util/assign ret 'builtin complete -p -- "$compcmd" 2>/dev/null'
ble/util/assign compdef 'builtin complete -p -- "$compcmd" 2>/dev/null'
fi
compdef=${compdef%"$compcmd"} # strip -I, -D, or command_name
compdef=${compdef%' '}' '

local comp_prog comp_func compoptions flag_noquote
ble/complete/progcomp/.parse-complete "$compdef"

# WA: Workarounds for third-party plugins
if [[ $comp_func ]]; then
# fzf
[[ $comp_func == _fzf_* ]] &&
ble-import contrib/fzf-completion

# bash_completion
if ble/is-function _quote_readline_by_ref; then
function _quote_readline_by_ref {
if [[ $1 == \'* ]]; then
printf -v "$2" %s "${1:1}"
else
printf -v "$2" %q "$1"
[[ ${!2} == \$* ]] && eval $2=${!2}
fi
}
ble/function#suppress-stderr _filedir
fi
fi
if [[ $comp_prog ]]; then
# aws
if [[ $comp_prog == aws_completer ]]; then
comp_opts=${comp_opts}no-mark-directories:prog-trim:
fi
fi
ble/string#split-words compargs "$ret"
while ((iarg<${#compargs[@]})); do
local arg=${compargs[iarg++]}
case "$arg" in
(-*)
local ic c
for ((ic=1;ic<${#arg};ic++)); do
c=${arg:ic:1}
case "$c" in
([abcdefgjksuvE])
# Note: workaround #D0714 #M0009 #D0870
case $c in
(c) flag_noquote=1 ;;
(d) ((_ble_bash>=40300)) && flag_noquote=1 ;;
(f) ((40000<=_ble_bash&&_ble_bash<40200)) && flag_noquote=1 ;;
esac
ble/array#push compoptions "-$c" ;;
([pr])
;; # 無視 (-p 表示 -r 削除)
([AGWXPS])
# Note: workaround #D0714 #M0009 #D0870
if [[ $c == A ]]; then
case ${compargs[iarg]} in
(command) flag_noquote=1 ;;
(directory) ((_ble_bash>=40300)) && flag_noquote=1 ;;
(file) ((40000<=_ble_bash&&_ble_bash<40200)) && flag_noquote=1 ;;
esac
fi
ble/array#push compoptions "-$c" "${compargs[iarg++]}" ;;
(o)
local o=${compargs[iarg++]}
comp_opts=${comp_opts//:"$o":/:}$o:
ble/array#push compoptions "-$c" "$o" ;;
(F)
comp_func=${compargs[iarg++]}

# Workarounds for third-party plugins
[[ $comp_func == _fzf_* ]] &&
ble-import contrib/fzf-completion
if ble/is-function _quote_readline_by_ref; then
# Fix bash_completion
function _quote_readline_by_ref {
if [[ $1 == \'* ]]; then
printf -v "$2" %s "${1:1}"
else
printf -v "$2" %q "$1"
[[ ${!2} == \$* ]] && eval $2=${!2}
fi
}
ble/function#suppress-stderr _filedir
fi

ble/array#push compoptions "-$c" ble/complete/progcomp/.compgen-helper-func ;;
(C)
comp_prog=${compargs[iarg++]}
ble/array#push compoptions "-$c" ble/complete/progcomp/.compgen-helper-prog ;;
(*)
# -D, -I, etc. just discard
esac
done ;;
(*)
;; # 無視
esac
done

ble/complete/check-cancel && return 148

Expand All @@ -2440,7 +2525,7 @@ function ble/complete/progcomp/.compgen {

[[ $compgen ]] || return 1

# Note: git の補完関数など勝手に末尾に space をつけ -o nospace を指定する物が存在する。
# WA: git の補完関数など勝手に末尾に space をつけ -o nospace を指定する物が存在する。
# 単語の後にスペースを挿入する事を意図していると思われるが、
# 通常 compgen (例: compgen -f) で生成される候補に含まれるスペースは、
# 挿入時のエスケープ対象であるので末尾の space もエスケープされてしまう。
Expand Down
1 change: 1 addition & 0 deletions memo/ChangeLog.md
Expand Up @@ -86,6 +86,7 @@
- edit, etc: add workarounds for `localvar_inherit` `#D1532` 0000000
- complete: work around bash-completion bugs `#D1533` 0000000
- main: work around MSYS2 .inputrc `#D1534` 0000000
- progcomp: fix non-working `complete -C prog` `#D1535` 0000000

## Compatibility

Expand Down
44 changes: 44 additions & 0 deletions memo/D1535.complete-p.sh
@@ -0,0 +1,44 @@


complete -C 'a' aws1
complete -C $'\n' aws2
complete -C $'\a' aws3
complete -C ''\''' aws4
complete -C ''\''hello'\''' aws5
complete -p
complete -r

complete -C a 'aws 1'
complete -C a 'aws'\''2'
complete -C a $'aws\n2'
complete -C a $'aws\a2'
complete -p
complete -r

complete -W 'a b' aws1
complete -W 'a'\''b' aws2
complete -W $'a\nb' aws3
complete -W $'a\ab' aws4
complete -p
complete -r

complete -G 'a b' -X 'a b' aws1
complete -G 'a'\''b' -X 'a'\''b' aws2
complete -G $'a\nb' -X $'a\nb' aws3
complete -G $'a\ab' -X $'a\ab' aws4
complete -p
complete -r

complete -P 'a b' -S 'a b' aws1
complete -P 'a'\''b' -S 'a'\''b' aws2
complete -P $'a\nb' -S $'a\nb' aws3
complete -P $'a\ab' -S $'a\ab' aws4
complete -p
complete -r

complete -o bashdefault -P P -S S -G G -X X -W W -A user -C callback -F func aws1
complete -o bashdefault -P P -S S -G G -X X -W W -A running -C callback -F func aws2
complete -o bashdefault -P P -S S -G G -X X -W W -A user -C callback -F func -D
complete -o bashdefault -P P -S S -G G -X X -W W -A user -C callback -F func -I
complete -p

8 changes: 8 additions & 0 deletions memo/D1535.completer.sh
@@ -0,0 +1,8 @@
#!/bin/bash

{
echo '[plain Bash]'
completer=(aws_completer "$@")
declare -p COMP_LINE COMP_POINT COMP_TYPE COMP_KEY completer
} >> b.txt
"${completer[@]}"

0 comments on commit 026432d

Please sign in to comment.