Skip to content

Commit

Permalink
complete (action:file): support "ble/syntax-raw" in the filename extr…
Browse files Browse the repository at this point in the history
…action
  • Loading branch information
akinomyoga committed Dec 15, 2022
1 parent a410b03 commit 32277da
Show file tree
Hide file tree
Showing 4 changed files with 307 additions and 7 deletions.
2 changes: 1 addition & 1 deletion docs/ChangeLog.md
Expand Up @@ -332,7 +332,7 @@
- prompt: fix the marker position for the readline variable `show-mode-in-prompt` (reported by Strykar) `#D1903` 09bb4d3
- highlight: fix a bug that `bleopt filename_ls_colors` is not working (reported by qoreQyaS) `#D1919` b568ade
- bind: fix <kbd>M-C-@</kbd>, <kbd>C-x C-@</kbd>, and <kbd>M-C-x</kbd> (`bash-4.2 -o emacs`) `#D1920` xxxxxxx

- complete (action:file): support `ble/syntax-raw` in the filename extraction (reported by qoreQyaS) `#D1921` xxxxxxx

## Documentation

Expand Down
32 changes: 26 additions & 6 deletions lib/core-complete.sh
Expand Up @@ -1639,6 +1639,21 @@ function ble/complete/action:word/get-desc {

# action:file
# action:file_rhs (source:argument 内部使用)

## @fn ble/complete/action:file/.get-filename word
## "comopt -o ble/syntax-raw" の場合も考慮してファイル名を抽出する。
## Bash の振る舞いを見るとチルダ展開だけを実行する様だ。
## @var[in] CAND DATA
function ble/complete/action:file/.get-filename {
ret=$CAND
if [[ $ACTION == progcomp && :$DATA: == *:ble/syntax-raw:* && $ret == '~'* ]]; then
local tilde=${ret%%/*} chars='\ "'\''`$|&;<>()!^*?[=:{,}'
[[ $tilde == *["$chars"]* ]] && return 0
builtin eval "local expand=$tilde"
[[ $expand == "$tilde" ]] && return 0
ret=$expand${ret:${#tilde}}
fi
}
function ble/complete/action:file/initialize {
ble/complete/action/quote-insert
}
Expand All @@ -1647,24 +1662,29 @@ function ble/complete/action:file/initialize.batch {
}
function ble/complete/action:file/complete {
ble/complete/action/requote-final-insert
if [[ -e $CAND || -h $CAND ]]; then
if [[ -d $CAND ]]; then

local ret
ble/complete/action:file/.get-filename
if [[ -e $ret || -h $ret ]]; then
if [[ -d $ret ]]; then
ble/complete/action/complete.mark-directory
else
ble/complete/action:word/complete
fi
fi
}
function ble/complete/action:file/init-menu-item {
ble/syntax/highlight/getg-from-filename "$CAND"
local ret
ble/complete/action:file/.get-filename; local file=$ret
ble/syntax/highlight/getg-from-filename "$file"
[[ $g ]] || { local ret; ble/color/face2g filename_warning; g=$ret; }

if [[ :$comp_type: == *:vstat:* ]]; then
if [[ -h $CAND ]]; then
if [[ -h $file ]]; then
suffix='@'
elif [[ -d $CAND ]]; then
elif [[ -d $file ]]; then
suffix='/'
elif [[ -x $CAND ]]; then
elif [[ -x $file ]]; then
suffix='*'
fi
fi
Expand Down
171 changes: 171 additions & 0 deletions memo/D1921.bashrc
@@ -0,0 +1,171 @@
# bashrc -*- mode: sh ; mode: sh-bash -*-

#------------------------------------------------------------------------------
# 1. 最初の疑惑は complete -p ls の結果が何だか少ない事による問題の可能性。
#
# 然し、実際に ble.sh ありなし両方試しても同じ結果だった。更に、手動で complete
# -F _fzf_path_completion ls を実行して試してみてもちゃんと期待通りに動く。また、
# 報告を見る限りは -o bashdefault -o default が指定されている物 (view) であって
# も問題が生じる様である。何が別の要因で動いたり動かなかったりするのだろう。

# source ~/.fzf.bash
# complete -p ls

# Result: complete -o bashdefault -o default -F _fzf_path_completion ls

# source out/ble.sh --norc
# ble-import fzf-completion
# ble-import fzf-key-bindings
# complete -p ls

# Result: complete -o bashdefault -o default -F _fzf_path_completion ls

#------------------------------------------------------------------------------
# 2. 次の可能性は bind -v の違いによる物
#
# これも違う様だ。

# source out/ble.sh --norc
# ble-import fzf-completion
# ble-import fzf-key-bindings
# bind -v > a.txt

# $ bash
# $ bind -v > b.txt

# Result:
#
# --- a.txt^I2022-12-13 19:43:56.254801647 +0900
# +++ b.txt^I2022-12-13 19:44:32.487842792 +0900
# @@ -36,10 +36,10 @@
# set completion-display-width -1
# set completion-prefix-display-length 0
# set completion-query-items 100
# -set editing-mode emacs
# +set editing-mode vi
# set emacs-mode-string @
# set history-size 0
# -set keymap emacs
# -set keyseq-timeout 500
# +set keymap vi-insert
# +set keyseq-timeout 1
# set vi-cmd-mode-string (cmd)
# set vi-ins-mode-string (ins)

#------------------------------------------------------------------------------
# 3. 或いは -o emacs か -o vi で違うのだろうか。
#
# 関係なかった。

# $ bash
# $ set -o emacs
# $ ls ~/opt[TAB]

#------------------------------------------------------------------------------
# 4. 遅延で fzf をロードした時の問題?
#
# 関係なかった。

# source out/ble.sh --norc
# ble-import -d fzf-completion
# ble-import -d fzf-key-bindings

#------------------------------------------------------------------------------
# 5. .blerc が悪い?
#
# 関係なかった。

# source out/ble.sh --rcfile ~/.blerc

#------------------------------------------------------------------------------
# 6. .bashrc が悪い?
#
# 取り敢えずこれで再現する。というか分かった。単に bash-completion をロードして
# いるかしていないかの違いだった。

# source out/ble.sh --norc
# ble-import fzf-completion
# ble-import fzf-key-bindings

# $ NOBLE=1 bash --norc
# $ source bashrc.gh264

# source ~/.mwg/git/scop/bash-completion/bash_completion
# source out/ble.sh --norc
# ble-import fzf-completion
# ble-import fzf-key-bindings

#------------------------------------------------------------------------------
# 8. 念の為 bash-completion + fzf (without ble.sh) で動くか試す
#
# ちゃんと動いている

# source ~/.mwg/git/scop/bash-completion/bash_completion
# source ~/.fzf.bash

#------------------------------------------------------------------------------
# 7. 何が起こっているのかについて詳細に調べる

# source ~/.mwg/git/scop/bash-completion/bash_completion
# source out/ble.sh --norc
# ble-import fzf-completion
# ble-import fzf-key-bindings

# source ~/.mwg/git/scop/bash-completion/bash_completion
# source ~/.fzf.bash

# echo --------------------------------------- >> a.txt
# function compopt {
# local IFS=$' \t\n'
# echo "compopt $*"
# printf 'args: '
# printf '<%s>' "$@"
# printf '\n'
# builtin compopt "$@"
# } >> a.txt
# function _test1() {
# echo "[start _fzf_path_completion $*]" >> a.txt
# _fzf_path_completion "$@"; local ext=$?
# declare -p COMPREPLY >> a.txt 2>&1
# echo "[end _fzf_path_completion $*] $ext" >> a.txt
# return "$ext"
# }
# # complete -p ls # →この時点では complete -F _fzf_path_completion ls
# complete -F _test1 ls

# 基本的には以下を呼び出している
#
# compopt -o ble/syntax-raw # fzf integration の時のみ
# compopt -o filenames
# COMPREPLY=("~/opt")
#
#------------------
# 次はこれだけを直接呼び出す設定で確認を行う
#
# → うーん。以下の test2a の様な単純な設定の時点で bash と振る舞いが異なるとい
# う事が分かってしまった。修正する必要がある。調べてみるとどうやら
# ble/complete/action:file/complete 迄ちゃんと呼び出されている様だ。と、これで
# 分かった。生成された候補が '~/opt' であるが、これはチルダ展開をしないとファイ
# ル名にならない。なので正しくディレクトリであるかどうかを判定する事ができない
# という事。

source out/ble.sh --norc

function _test2a {
[[ ${BLE_ATTACHED-} ]] &&
compopt -o ble/syntax-raw
compopt -o filenames
COMPREPLY=("~/opt")
#COMPREPLY=("a b") # 元の bash では全体をファイル名として認識し quote もする
#COMPREPLY=("'a b'") # 元の bash では quote removal 等する事なく ' もファイル名の一部として、quote もする。
#COMPREPLY=("~murase/opt") # 元の bash では quote removal 等する事なく ' もファイル名の一部として、quote もする。
#COMPREPLY=("~/o?t") # 元の bash では途中のパス名展開は実行しない。
}
complete -F _test2a test2a
function _test2b {
[[ ${BLE_ATTACHED-} ]] &&
compopt -o ble/syntax-raw
compopt -o filenames
COMPREPLY=("~/opt")
}
complete -F _test2b test2b
109 changes: 109 additions & 0 deletions note.txt
Expand Up @@ -6666,6 +6666,115 @@ bash_tips

2022-12-13

* fzf-completion: ファイル名に付く suffix の判定ができていない (reported by qoreQyaS) [#D1921]
https://github.com/akinomyoga/ble.sh/issues/264

結局問題は ble/syntax-raw で fzf にファイル名を渡しているので結果として生成
される物が、必ずしもそのままでファイル名になっているとは限らないのが原因だっ
た。

[原因解明]

bash-completion & fzf & ble.sh の組み合わせで再現する事を確認した。色々調べ
た所、単に以下の補完設定でも ble.sh だと問題が再現する。

function _test2a {
compopt -o filenames
COMPREPLY=("~/opt")
}
complete -F _test2a test2a

ble.sh の中の動作を調べると ble/complete/action:file/complete 迄期待通りに
呼び出されているが、そこで分かった。~/が定義されていないのである。

? ok: fzf の補完で ~ が直接渡って suffix が付かなくなるのは良いとしても、不
思議なのは普通の補完で同様の修正が働かない理由である。そもそも ~/opt は
/home/murase/o に変換してから補完が走る設計にしていた様な気がする。何故 ~
が直接補完関数に渡っているのだろうか??

と思ったがよく考えたらテストの問題である。問題再現の為に直接
COMPREPLY=('~/opt') の様にしていただけで、実際に COMP_LINE や COMP_WORDS
に '~' が含まれていた訳では無い。

[修正]

取り敢えず ble/syntax-raw の時にはその場でパス名展開を試行してファイル名か
どうかの判定を実行する事にする。


? 存在しないファイル名がある時に nullglob で消えてしまうのでは。これだと一
番最後の単語でない物を拾ってテストしてしまう可能性がある。

こういった設定を変更しないでできるパス名展開は存在しただろうか。と思った
が util の eval-pathname-expansion は元からその様な物だった。

* reject: comp_opts の値を記録する事を考える。或いは、DATA は progcomp の時
には常に comp_opts だと仮定して良いのだろうか。と思ったが、駄目。progcomp
のものに関しては問題が起こらないが、それ以外で生成された物について DATA
は別のものを含んでいるので、直接 DATA を読み取っていると誤作動の原因にな
る。

或いはそれが progcomp によって生成された物であるかどうかを判定する方法は
あるのか。確認した所、action=progcomp らしい。action=mandb もあるような気
がしたがそれは source:mandb から生成された物だけの様である。更に、
action=mandb で出てきた物はファイル名ではないのは明らかなので、やはり除外
しても良い。

progcomp から出てくる物は action=progcomp であると仮定して良い。

実装した。動いている。auto-complete の場合でもちゃんと / が挿入される。

x fixed: と思ったが menu-complete の着色の為にファイル名を判定している所で
結局同様にファイル名の判定に失敗して全てが赤くなっている。これにも対応す
る必要がある気がする。

これについても修正を行った。ファイル名取得の処理を共通化して、そしたら簡
単だった。

? 生成される物が eval した後にファイル名になるという事を仮定しているが本当
にそう思って良いのだろうか。元の bash の振る舞いでは空白が入っていたとし
ても -o filename を指定したら quote してくれるみたいな事になっていたりは
しないのか?

x bash の振る舞いについて確認する事にする。更にそもそも不用意に eval して良
いのかという問題がある。コマンド置換など含まれていたらどうするのか。
syntax/simple-word で判定してから eval するべきなのではないか。

チルダ展開だけを実行するためにはどうしたら良いか。ble/widget/tilde-expand
を確認してみた所、これは command line に含まれる物に対する作用だったので、
単に syntax 情報を参照していた。

コマンド置換が含まれていたらチルダ展開は諦めると思ったがコマンド置換が含
まれていたとしても、結局は quote されるので inactive である。取り敢えずチ
ルダ展開だけ試みるというのが正しい動作の気がする。という事を考えると、最
初がチルダであって次の / までに何か特別な文字が含まれていない時に限ってチ
ルダ展開を試みるという処置が必要である。

先ず最初に作った以下のコードは全て棄却である。

| local -a dtor=()
| if shopt -q nullglob; then
| shopt -u nullglob
| ble/array#push dtor 'shopt -s nullglob'
| fi
| if shopt -q failglob; then
| shopt -u failglob
| ble/array#push dtor 'shopt -s failglob'
| fi
|
| # Note: 一番最後の文字の直後の文脈を知りたいので、末尾に '' を追加して評価
| # してから最後の単語を抜き出す。
| if ble/util/eval-pathname-expansion "$file''" && ((${#ret[@]})); then
| file=${ret[${#ret[@]}-1]}
| else
| file=
| fi
|
| ble/util/invoke-hook dtor

実装し直した。動作確認する。動いている。auto-complete もOK。menu-complete
もOK。その他の微妙なファイル名でも bash と同様に動作する事を確認した。

* bind: M-C-@ が正しく捕まえられていない気がする [#D1920]

bind -s で確認するとマクロ置換後の C-@ が消滅している。これは単にマクロが内
Expand Down

0 comments on commit 32277da

Please sign in to comment.