Skip to content

Commit

Permalink
complete: work around autoloaded "fzf" completion settings
Browse files Browse the repository at this point in the history
  • Loading branch information
akinomyoga committed Mar 9, 2021
1 parent 856cec2 commit 4fc51ae
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 17 deletions.
2 changes: 1 addition & 1 deletion contrib
36 changes: 21 additions & 15 deletions lib/core-complete.sh
Expand Up @@ -1935,7 +1935,7 @@ function ble/complete/source:tilde {

local old_cand_count=$cand_count
ble/complete/cand/yield-filenames tilde "${candidates[@]}"; local ext=$?
return $((ext?ext:cand_count==old_cand_count))
return $((ext?ext:cand_count>old_cand_count))
}

#------------------------------------------------------------------------------
Expand Down Expand Up @@ -2171,7 +2171,8 @@ function ble/complete/progcomp/.compvar-quote-subword {
## @var[out] progcomp_prefix
function ble/complete/progcomp/.compvar-initialize {
COMP_TYPE=9
COMP_KEY=${KEYS[${#KEYS[@]}-1]:-9} # KEYS defined in ble-decode/widget/.call-keyseq
COMP_KEY=9
((${#KEYS[@]})) && COMP_KEY=${KEYS[${#KEYS[@]}-1]:-9} # KEYS defined in ble-decode/widget/.call-keyseq

# Note: 以降の処理は基本的には comp_words, comp_line, comp_point, comp_cword を
# COMP_WORDS COMP_LINE COMP_POINT COMP_CWORD にコピーする。
Expand Down Expand Up @@ -2241,7 +2242,7 @@ 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
"$comp_prog" "$cmd" "$cur" "$prev" < /dev/null
fi
}
# compopt に介入して -o/+o option を読み取る。
Expand Down Expand Up @@ -2297,12 +2298,12 @@ function ble/complete/progcomp/.compgen-helper-func {
ble/complete/progcomp/.compvar-initialize

local progcomp_read_count=0
local _ble_builtin_read_hook='ble/complete/progcomp/.check-limits || return 148'
local _ble_builtin_read_hook='ble/complete/progcomp/.check-limits || { builtin read "$@" < /dev/null; return 148; }'

local fDefault=
local cmd=${COMP_WORDS[0]} cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
ble/function#push compopt 'ble/complete/progcomp/compopt "$@"'
builtin eval '"$comp_func" "$cmd" "$cur" "$prev"' < /dev/null; local ret=$?
builtin eval '"$comp_func" "$cmd" "$cur" "$prev"' < /dev/null > /dev/tty 2>&1; local ret=$?
ble/function#pop compopt

if [[ $is_default_completion && $ret == 124 ]]; then
Expand Down Expand Up @@ -2391,6 +2392,8 @@ function ble/complete/progcomp/.compgen {
ble/array#push compoptions "-$c" "$o" ;;
(F)
comp_func=${compargs[iarg++]}
[[ $comp_func == _fzf_* ]] &&
ble-import contrib/fzf-completion
ble/array#push compoptions "-$c" ble/complete/progcomp/.compgen-helper-func ;;
(C)
comp_prog=${compargs[iarg++]}
Expand Down Expand Up @@ -2490,7 +2493,7 @@ function ble/complete/progcomp/.compgen {
# Note: 重複候補や順序については考えていない
[[ $comp_opts == *:plusdirs:* ]] && ble/complete/source:dir

((cand_count!=old_cand_count))
((cand_count>old_cand_count))
}

## @fn ble/complete/progcomp/.compline-rewrite-command cmd [args...]
Expand Down Expand Up @@ -3319,6 +3322,13 @@ function ble/complete/candidates/.pick-nearest-sources {
fi
}

function ble/complete/candidates/clear {
cand_count=0
cand_cand=()
cand_word=()
cand_pack=()
}

## @fn ble/complete/candidates/.filter-by-command command
## 生成された候補 (cand_*) に対して指定したコマンドを実行し、
## 成功した候補のみを残して他を削除します。
Expand Down Expand Up @@ -3659,11 +3669,7 @@ function ble/complete/candidates/generate {
ble/complete/candidates/comp_type#read-rl-variables

local cand_iloop=0
cand_count=0
cand_cand=() # 候補文字列
cand_word=() # 挿入文字列 (~ エスケープされた候補文字列)
cand_pack=() # 候補の詳細データ

ble/complete/candidates/clear
ble/complete/candidates/generate-with-filter none "$opts" || return "$?"
((cand_count)) && return 0

Expand Down Expand Up @@ -4881,8 +4887,8 @@ function ble/widget/complete {

local COMP1 COMP2 COMPS COMPV
local comp_type comps_flags comps_fixed
local cand_count=0
local -a cand_cand cand_word cand_pack
local cand_count cand_cand cand_word cand_pack
ble/complete/candidates/clear
local cand_limit_reached=
if [[ $_ble_complete_menu_active && :$opts: != *:regenerate:* &&
:$opts: != *:context=*:* && ${#_ble_complete_menu_icons[@]} -gt 0 ]]
Expand Down Expand Up @@ -5974,8 +5980,8 @@ function ble/complete/sabbrev/expand {
local flag_source_filter=1

# construct cand_pack
local cand_count=0
local -a cand_cand=() cand_word=() cand_pack=()
local cand_count cand_cand cand_word cand_pack
ble/complete/candidates/clear
local cand COMP_PREFIX=

# local settings
Expand Down
3 changes: 2 additions & 1 deletion memo/ChangeLog.md
Expand Up @@ -10,7 +10,7 @@
- edit: support new options `bleopt edit_line_type={logical,graphical}` (motivated by 3ximus) `#D1442` 40ae242
- complete: support new options `bleopt complete_limit{,_auto}` (contributed by timjrd) `#D1445` b13f114 5504bbc
- complete: update the default value of `bleopt complete_limit{,auto}` `#D1500` aae553c
- complete: inject user interruption and complete limits into `bash-completion` through `read` (motivated by timjrd) `#D1504` 0000000
- complete: inject user interruption and complete limits into `bash-completion` through `read` (motivated by timjrd) `#D1504` 856cec2 `#D1507` 0000000
- edit (kill/copy): combine multiple kills and copies (suggested by 3ximus) `#D1443` 66564e1
- edit (`{kill,copy}-region-or`): fix unconditionally combined kills/copies (reported by 3ximus) `#D1447` 1631751
- canvas: update emoji database and support `bleopt emoji_version` (motivated by endorfina) `#D1454` d1f8c27
Expand Down Expand Up @@ -75,6 +75,7 @@
- term: support key sequences and control sequences of Solaris console `#D1481` 6ca0b8c
- term: work around Cygwin-console bug of bottom `IL`/`DL` `#D1482` 5dce0b8
- term: work around leaked <kbd>DA2R</kbd> in screen from outside terminal `#D1485` e130619
- complete: work around `fzf` completion settings loaded automatically `#D1508` 0000000

## Internal changes and fixes

Expand Down
133 changes: 133 additions & 0 deletions note.txt
Expand Up @@ -4008,6 +4008,139 @@ bash_tips
Done (実装ログ)
-------------------------------------------------------------------------------

2021-03-09

* COMPAT complete vs fzf: システムによってロードされた fzf で固まる [#D1508]

これは . /etc/bashrc を読み込むと強制的に読み込まれている設定である。ユーザー
が自分で入れた fzf に関しては contrib/fzf-completion を ble-import して貰う
事によって問題が起こらない様にしているが、システムによってロードされる fzf
に関しては内容を上書きする隙がない。仕方がないので、core-complete.sh で
_fzf_* が呼び出された時に contrib/fzf-completion を自動的にロードする様にす
る事にした。元より bash-completion を勝手に呼び出したりする様にしているので
他の framework ありきのコードがあっても気にしない。

これは正直 fzf が tty ではなくて stderr になにか出力しようとするのが行けな
い。/dev/tty に出力する様にして欲しい物である。

うーん。 fzf のページを見てもそれらしい物は存在しない。環境変数などで指定で
きれば良いのだが。man fzf を見てもそれらしい物は存在しない。そういう機能を
request して見ようと思ったが、考えてみれば自分で fzf を呼び出す時には
2>/dev/tty をつければ良いだけなので新しい機能として実装する意味がない。ユー
ザー経由で呼び出しているのであればユーザーにその様に指定する様にお願いする
べきなのである。

然し、ble.sh がやっているのは bash progcomp の模倣である。bash の方で問題が
ないのであれば、ble.sh の方で問題が起こるのは余り良くない。うーん。fzf につ
いて関数などで上書きして振る舞いを変える? うーん。それだと fzf-xxx の様な派
生コマンドを使われた時に対処できない。結局 bash progcomp を真似て 2 は tty
に繋いだ儘にしておくべきなのだろうか。うーん。

というかそもそも fzf が tty に出力する様にしたとして auto-complete に際して
期待通りに動くかどうかというのは非自明である。取り敢えず試してみる。
→試してみた所期待通りに動作しない。やはり fzf の設定をそのまま使うのは駄目。

? うーん。実行しても結果が反映されない。COMPREPLY をちゃんと設定しているか?

? redraw-line が正しく呼び出されていない。

% これは恐らく ESC [ が M-[ になって bind されているのが原因。CSI の構築に
% 失敗した時に M-[ と解釈するべきか或いは ESC [ と解釈するべきかは微妙な所
% である。然し、CSI を構築する ESC は isolated ESC ではなくて他の文字と一緒
% に受信した ESC であるべきと考えれば、やはり M-[ と解釈するべきだろうか。
% そうすると、CSI に失敗した時に 1 byte だけ切り取って ESC を key として生
% 成しているのを修正するべきである。

改めて確認した所、そもそも CSI 0 n は認識できないシーケンスとして捨てられ
ているという事が判明した。

? その他の問題として fzf を実行している間は modifyOtherKeys の設定によって
fzf の操作ができなくなっているという事がある。うーん。実際に端末に作用す
るかどうか分からないのに補完関数を呼び出す度に端末の状態を変更するという
のも変な感じがする。

面倒なので fzf が補完関数の名前に入っている時に限り特別の動作をする様にする?
取り敢えず、固まったりしない様に調整した。

% x fixed: CSI 5 n が候補の文字列に結合してしまっている。これは何故だろうか。
% COMPREPLY にはちゃんとした候補が入っている…気がする。
%
% →これは compgen の標準出力を読み取って候補としているのが原因。元の
% progcomp の -F の場合には標準出力はそのまま端末に繋がっている。それに倣う
% 様に修正した。
%
% x fixed: 候補が生成されない…と思ったら実は CSI 5 n に対する返答 CSI 0 n に
% よってユーザー入力に依る中断が入って処理がキャンセルされている。fzf の時
% にはどうにかしてこれに対する対策を行う必要がある。
%
% a CSI 0 n を受信しても処理を続行するというのは難しい。何故ならば受信した
% 段階ではそれがユーザー入力なのか応答なのか判定する方法がないので。受信
% して読み取ってから違ったら書き戻すというのも処理としては汚い。
%
% b それなら CSI 5 n がそもそも伝播しない様に抑える必要がある。うーん。幸い
% にして CSI 5 n は標準出力に、それ以外のメニューの描画は標準エラーに出力
% されている。従って、_fzf* に対しては標準出力を潰す様にするのが良い気が
% する。

色々対策してみたが実はこれらの対策は contrib/fzf-completion.bash と本質的に
同じであった。fzf-completion.bash を自動で load する方が良いのではないか。

x fixed: progcomp で単一候補を生成したとしても progcomp 以外に sabbrev も表
示されてしまって単一確定にならない。うーん。これは _fzf_* で成功して単一
確定の場合には既に生成した候補は全て削除するという事にすれば良いのでは。
→既存の候補は消去する様に実装した。

x そもそも既に入力済みの内容を無視している。normal bash で試してみると、既
に何か入力済みの物がある場合には fzf による completion は起動しない。空の
文字列の時にだけ fzf による選択が開始される。

→これは曖昧補完の為に空文字列で補完候補生成を要求するのが原因であった。
曖昧補完の時にはそもそも fzf を呼び出さない様に修正した。

* BUG progcomp: 現在 read に介入して中断する様にしているが [#D1507]

現在の実装だと

while read || [[ $REPLY ]]; do ... done

の様になっていると、無限ループになってしまう。
中断する時にも引数に指定した変数は全て空にしておく必要がある。

というより、現在の read の実装は普通に呼び出した時であってもちゃんと変数を
空にしてくれるのか?

% そもそも元の read の振る舞いが良く分からない。read line とした時にもう読み
% 取る内容がなかったとして line が空になるのかと思いきやそうでもない? と思っ
% たがこれは勘違いだった。試す時に : | read ... とすると subshell の中で値を
% 設定するので、外側の変数には影響が出なかっただけ。

うーん。取り敢えず中断の時には内部で </dev/null を builtin read に食わせて
処理する事にした。option -e が指定されていても /dev/null に繋がっている時に
は特に readline も起動せずに期待通りに動作する筈。

* [OK] edit: read -a ARRAY に対応していない? [#D1506]

と思ったが実はちゃんと対応していた。抑 -a ARRAY は bash-4.0 の時点でちゃん
と存在している。調べたら bash-2.0 で配列に対応した当初から存在している様で
ある。

対応していない様に見えたが実のところ read -e で読み取った結果を改めて
builtin read で解釈されているので特別に実装しなくてもちゃんと振る舞いを再現
できているのである。

* wiki: bleopt openat_base [#D1505]

現在は実は積極的には使われていないという事。
また、既に重複して開かない様に対策が為されているという事。

→どの時点で対策が導入されたか確認しようとしたら実は ble-0.1 の時からちゃん
と或る程度の衝突回避はある様だった。問題が発生するのは ble.sh が fd を使い
始めた後でユーザーがそれを上書きしてしまった場合である。この問題は今も依然
としてある。従って、現在の文章はそのままにする。但し、Bash 4.0 以下でしか使
われないという事は書いておいて良いだろう。

wiki を編集した。

2021-03-07

* progcomp: やはりファイルが大量にあるシステムで遅い (reported by timjrd) [#D1504]
Expand Down

0 comments on commit 4fc51ae

Please sign in to comment.