Skip to content

Commit

Permalink
mandb: look for git subcommands
Browse files Browse the repository at this point in the history
  • Loading branch information
akinomyoga committed Jan 5, 2024
1 parent 2c7cca2 commit 9641c3b
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 34 deletions.
2 changes: 1 addition & 1 deletion contrib
1 change: 1 addition & 0 deletions docs/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- keymap/vi: split widget `text-object` into `text-object-{inner,outer}` (requested by Darukutsu) `#D2093` 11cf118a
- keymap/vi: implement text-object in xmap for brackets (requested by Darukutsu) `#D2095` 7d80167c
- util: support `ble-import -C callback` (motivated by Dominiquini) `#D2102` 0fdbe3b0
- mandb: look for git subcommands (motivated by bkerin) `#D2111` xxxxxxxx

## Changes

Expand Down
121 changes: 94 additions & 27 deletions lib/core-complete.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1676,8 +1676,7 @@ function ble/complete/action/requote-final-insert {
if [[ $insert == "$comps_prefix"* && $comps_prefix != *[!':/={,'] ]]; then
local ret ins=${insert:${#comps_prefix}}
if ! ble/syntax:bash/simple-word/is-literal "$ins" &&
ble/syntax:bash/simple-word/is-simple "$ins" &&
ble/syntax:bash/simple-word/eval "$ins" &&
ble/syntax:bash/simple-word/safe-eval "$ins" &&
((${#ret[@]}==1))
then
ble/string#quote-word "$ret" quote-empty
Expand Down Expand Up @@ -3475,7 +3474,7 @@ function ble/complete/progcomp/.parse-complete {
##
## @var[out] $arr, flag_mandb
## @var[in] compgen
## @var[in] COMPV compcmd comp_words
## @var[in] COMPV compcmd comp_cword comp_words
## @var[in] comp_opts use_workaround_for_git
function ble/complete/progcomp/.filter-and-split-compgen {
flag_mandb=
Expand Down Expand Up @@ -3513,15 +3512,47 @@ function ble/complete/progcomp/.filter-and-split-compgen {
require_awk=1 # for uniq
fi

# 3. awk (sort 後処理)
# Prepare mandb
local -a args_mandb=()
if [[ $compcmd == "${comp_words[0]}" && $COMPV != [!-]* ]]; then
if local ret; ble/complete/mandb/generate-cache "$compcmd"; then
if [[ $comp_cword -gt 0 && $COMPV != [!-]* ]]; then
# Expand the command name. We first try to use the external variable
# compcmd, which is supposed contain the expanded command name. However,
# when the variable "compcmd" contains a special value, we try to expand
# the first word in-place.
local cmd=$compcmd
if [[ $cmd == _DefaultCmD_ || $cmd == _InitialWorD_ || $cmd == -[DI] ]]; then
cmd=${comp_words[0]}
local ret
ble/syntax:bash/simple-word/safe-eval "$cmd" nonull && cmd=$ret
fi

# If the first word is "git" and the first non-option word "SUBCMD"
# exists before comp_cword, we try to get mandb associated with
# "git-SUBCMD".
local man_page=${cmd##*/}
if [[ $man_page == git ]]; then
for ((isubcmd=1;isubcmd<comp_cword;isubcmd++)); do
local subcmd=${comp_words[isubcmd]} ret
if ble/syntax:bash/simple-word/safe-eval "$subcmd"; then
((${#ret[@]})) || continue
subcmd=$ret
fi
if [[ $subcmd != -* ]]; then
man_page=git-$subcmd
break
fi
done
fi

if local ret; ble/complete/mandb/generate-cache "$man_page" "bin=$command"; then
require_awk=1
args_mandb=(mode=mandb "$ret")
fi
fi

# 3. awk (sort 後処理)
if [[ $require_awk ]]; then
local fs=$_ble_term_FS
local awk_script='
BEGIN { mandb_count = 0; }
mode == "mandb" {
Expand All @@ -3532,6 +3563,12 @@ function ble/complete/progcomp/.filter-and-split-compgen {
}
function register_mandb_entry(name, display, entry) {
# If the completion generated by progcomp ends with = yet the suffix
# specified by the entry is a space, we replace the suffix in the
# entry.
if (display ~ /=$/ && match(entry, /^[^'$fs']*'$fs'[^'$fs']*'$fs' '$fs'/) > 0)
entry = substr(entry, 1, RLENGTH - 2) "=" substr(entry, RLENGTH);
if (name2index[name] != "") {
# Remove duplicates after removing trailing /=$/. If the new
# "display" is longer, overwrite the existing one.
Expand Down Expand Up @@ -3978,11 +4015,17 @@ function ble/complete/progcomp/.split-alias-words {
## @fn ble/complete/progcomp/.try-load-completion cmd
## bash-completion の loader を呼び出して遅延補完設定をチェックする。
function ble/complete/progcomp/.try-load-completion {
ble/is-function __load_completion || return 1

ble/function#push command_not_found_handle
__load_completion "$1" < /dev/null &>/dev/null; local ext=$?
ble/function#pop command_not_found_handle
if ble/is-function _comp_load; then
ble/function#push command_not_found_handle
_comp_load -- "$1" < /dev/null &>/dev/null; local ext=$?
ble/function#pop command_not_found_handle
elif ble/is-function __load_completion; then
ble/function#push command_not_found_handle
__load_completion "$1" < /dev/null &>/dev/null; local ext=$?
ble/function#pop command_not_found_handle
else
return 1
fi
((ext==0)) || return "$ext"

builtin complete -p -- "$1" &>/dev/null
Expand Down Expand Up @@ -5070,7 +5113,8 @@ function ble/complete/mandb:bash-completion/inject {
if ble/is-function _comp_compgen_help; then
# bash-completion 2.12
ble/function#advice after _comp_compgen_help__get_help_lines 'ble/complete/mandb:bash-completion/_get_help_lines.advice' &&
ble/function#advice before _comp_longopt 'ble/complete/mandb:bash-completion/_parse_help.advice "${ADVICE_WORDS[1]}"' &&
{ ble/function#advice before _comp_complete_longopt 'ble/complete/mandb:bash-completion/_parse_help.advice "${ADVICE_WORDS[1]}"' ||
ble/function#advice before _comp_longopt 'ble/complete/mandb:bash-completion/_parse_help.advice "${ADVICE_WORDS[1]}"'; } &&
function ble/complete/mandb:bash-completion/inject { return 0; }
elif ble/is-function _parse_help; then
ble/function#advice before _parse_help 'ble/complete/mandb:bash-completion/_parse_help.advice "${ADVICE_WORDS[1]}" "${ADVICE_WORDS[2]}"' &&
Expand Down Expand Up @@ -5105,8 +5149,7 @@ function ble/complete/mandb:bash-completion/.alloc-subcache {

local command=$1 hash=$2 opts=$3
if [[ :$opts: == *:dequote:* ]]; then
ble/syntax:bash/simple-word/is-simple "$command" &&
ble/syntax:bash/simple-word/eval "$command" noglob &&
ble/syntax:bash/simple-word/safe-eval "$command" noglob:nonull &&
command=$ret
fi
[[ $command ]] || return 1
Expand Down Expand Up @@ -5188,11 +5231,13 @@ function ble/complete/mandb:bash-completion/_get_help_lines.advice {
printf '%s\n' "${_lines[@]}" | ble/complete/mandb:help/generate-cache "$help_opts" >| "$subcache"
}

## @fn ble/complete/mandb/generate-cache cmdname
## @fn ble/complete/mandb/generate-cache cmdname [opts]
## @param[in,opt] opts
## @opt man=MAN_PAGE
## @var[out] ret
## キャッシュファイル名を返します。
function ble/complete/mandb/generate-cache {
local command=${1##*/}
local command=${1##*/} opts=${2-}
[[ $command ]] || return 1
local lc_messages=${LC_ALL:-${LC_MESSAGES:-${LANG:-C}}}
local mandb_cache_dir=$_ble_base_cache/complete.mandb/${lc_messages//'/'/%}
Expand Down Expand Up @@ -5222,7 +5267,10 @@ function ble/complete/mandb/generate-cache {
fi

# fcache_man
if [[ :$cmdspec_opts: != *:mandb-disable-man:* ]] && ble/bin#has "$1"; then
if [[ :$cmdspec_opts: != *:mandb-disable-man:* ]] && {
ble/opts#extract-last-optarg "$opts" bin
local path=${ret:-"$1"}
ble/bin#has "$path"; }; then
local subcache=$mandb_cache_dir/man.d/$command
if ! [[ -s $subcache && $subcache -nt $_ble_base/lib/core-complete.sh ]]; then
ble/util/mkd "${subcache%/*}"
Expand Down Expand Up @@ -5338,8 +5386,7 @@ function ble/complete/source:option/.is-option-context {

local word ret
for word; do
ble/syntax:bash/simple-word/is-simple "$word" &&
ble/syntax:bash/simple-word/eval "$word" noglob &&
ble/syntax:bash/simple-word/safe-eval "$word" noglob &&
ble/progcolor/stop-option#test "$ret" &&
return 1
done
Expand Down Expand Up @@ -5393,7 +5440,11 @@ function ble/complete/source:option/generate-for-command {
prev_args=("${@:2}")

local alias_checked=' '
while local ret; ! ble/complete/mandb/load-cache "$cmd"; do
while
local ret cmdv=$cmd
ble/syntax:bash/simple-word/safe-eval "$cmd" nonull && cmdv=$ret
! ble/complete/mandb/load-cache "$cmdv"
do
alias_checked=$alias_checked$cmd' '
ble/alias#expand "$cmd" || return 1
local words; ble/string#split-words ret "$ret"; words=("${ret[@]}")
Expand All @@ -5403,14 +5454,31 @@ function ble/complete/source:option/generate-for-command {
while [[ ${words[iword]} =~ $rex ]]; do ((iword++)); done
[[ ${words[iword]} && $alias_checked != *" ${words[iword]} "* ]] || return 1
prev_args=("${words[@]:iword+1}" "${prev_args[@]}")
cmd=${words[iret]}
cmd=${words[iword]}
done
local -a entries; entries=("${ret[@]}")

local ret cmdspec_opts=
ble/syntax:bash/simple-word/is-simple "$cmd" &&
ble/syntax:bash/simple-word/eval "$cmd" noglob &&
ble/cmdspec/opts#load "$ret"
# If the main command name is git, try to load the man page corresponding to
# the subcommand.
if [[ ${cmdv##*/} == git ]]; then
local isubcmd
for ((isubcmd=0;isubcmd<${#prev_args[@]};isubcmd++)); do
local subcmd=${prev_args[isubcmd]}
if ble/syntax:bash/simple-word/safe-eval "$subcmd"; then
((${#ret[@]}==0)) || continue
subcmd=$ret
fi
if [[ $subcmd != -* ]] && ble/complete/mandb/load-cache "git-$subcmd"; then
cmdv=git-$subcmd
entries=("${ret[@]}")
prev_args=("${prev_args[@]:isubcmd+1}")
break
fi
done
fi

local cmdspec_opts=
ble/cmdspec/opts#load "$cmdv"
# "--" や非オプション引数など、オプション無効化条件をチェック
ble/complete/source:option/.is-option-context "${prev_args[@]}" || return 1

Expand Down Expand Up @@ -6431,8 +6499,7 @@ function ble/complete/candidates/determine-common-prefix {
# なのでチルダ展開・パス名展開を無効にして部分一致を試みる必要がある。
if [[ ! $is_processed ]] &&
local notilde=\'\' &&
ble/syntax:bash/simple-word/reconstruct-incomplete-word "$COMPS" &&
ble/syntax:bash/simple-word/eval "$notilde$ret" noglob &&
ble/syntax:bash/simple-word/safe-eval "$notilde$COMPS" reconstruct:noglob &&
local compv_notilde=$ret &&
ble/syntax:bash/simple-word/eval "$notilde$common_reconstructed" noglob &&
local commonv_notilde=$ret &&
Expand Down
31 changes: 30 additions & 1 deletion lib/core-syntax.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1217,7 +1217,7 @@ function ble/syntax:bash/simple-word/evaluate-last-brace-expansion {
ret=$out simple_ibrace=$iopen:$((${#out}-no_brace_length))
}

## @fn ble/syntax:bash/simple-word/reconstruct-incomplete-word
## @fn ble/syntax:bash/simple-word/reconstruct-incomplete-word word
## word について不完全なブレース展開と不完全な引用符を閉じ、
## 更にブレース展開を実行して最後の単語を取得します。
##
Expand Down Expand Up @@ -1552,6 +1552,35 @@ function ble/syntax:bash/simple-word/eval {
return "$ext"
}

## @fn ble/syntax:bash/simple-word/eval word [opts]
## @param[in,opt] opts
## A colon-separated list of options. In addition to the values supported
## by ble/syntax:bash/simple-word/eval, the following value is available:
##
## @opt reconstruct
## Try to reconstruct the full word using
## ble/syntax:bash/simple-word/reconstruct-incomplete-word when there is
## no closing quote corresponding to an opening one in the word.
##
## @opt nonull
## Fails when no word is generated. This may happen with e.g. an
## expansion an empty array "${arr[@]}" or unmatching glob pattern with
## nullglob.
##
## @arr[out] ret
##
function ble/syntax:bash/simple-word/safe-eval {
if [[ :$2: == *:reconstruct:* ]]; then
local simple_flags simple_ibrace
ble/syntax:bash/simple-word/reconstruct-incomplete-word "$1" || return 1
ble/util/unlocal simple_flags simple_ibrace
else
ble/syntax:bash/simple-word/is-simple "$1" || return 1
fi
ble/syntax:bash/simple-word/eval "$1" &&
{ [[ :$2: != *:nonull:* ]] || ((${#ret[@]})); }
}

## @fn ble/syntax:bash/simple-word/get-rex_element sep
## 指定した分割文字 (sep) で区切られた単純単語片に一致する正規表現を構築します。
## @var[out] rex_element
Expand Down
53 changes: 52 additions & 1 deletion note.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1905,6 +1905,13 @@ bash_tips
- make_command.sh の整理 (scan 分離, char_width 分離)
- note.txt -> memo.txt

2024-01-05

* mc 的な TUI を自前で実装しても良いのではないか? どうも mc を使っている人は
結構いるようである。更に、dylanaraps/fff 等の機能も参考にしても良いのかもしれない。と
思ったが、fff はデモを見る限りは大した機能はないのではないのかという気がす
る。

2023-12-10

* main: ble-update, ble-reload, bleopt, ble-sabbrev, ble-palette の adjust-bash-options
Expand All @@ -1915,7 +1922,7 @@ bash_tips
ble-reload に関しては内部で source するのだとしたら無理やり状態を復元保存し
ようとするのは問題がある気がする。特に ble-reload で adjust した後の状態を
グローバル変数に記録してしまうのではないか。そう思うと ble-reload は待避の
対称ではない気がする。そういう場合もあるという事を考えると ble で一括で待避
対象ではない気がする。そういう場合もあるという事を考えると ble で一括で待避
するというのも実は柔軟性に書けるという事になるのかもしれない。

2023-10-04
Expand Down Expand Up @@ -7055,6 +7062,50 @@ bash_tips

2024-01-05

* mandb: git のオプションの説明は man git-subcommand から取得するべき (motivated by bkerin) [#D2111]
https://github.com/akinomyoga/ble.sh/issues/386

果たしてこれが報告者の意図していた事かは分からないがその様に読めなくもない。
何れにしてもこれは対応できる様な気がするので対応する事にする。

? 先ず、mandb から説明を補填するかどうかの判定条件に $compcmd ==
${comp_words[0]} がある。これは一体何を意味しているのか。compcmd の初期化
を辿ってみると、先ず -D や -I の特別な場合を除き ${comp_words[0]}} を代入
している。そして、その後で simple-word の時には eval した値で置き換えてい
る。eval したかどうかで振る舞いを変えるというのは変な気がするので、これは
単に -D や -I ではないという事を確認する為の物だろうか。

一応コードの履歴を確認する事にする。判定は c1cd666b で最初に progcomp に
対する説明付加が導入された時から存在しているが、大した議論は残っていない。
特に意図があってこの様な判定にしたという訳でもない気がするので、気にしな
い事にする。単に -D または -I ではないという事を確認する為のコードと思う
事にする。

然し、-D だったとしても man ${comp_words[0]} で候補を探索しても良いのでは
ないか? うーん。改めて ${comp_words[0]} を展開しなおしてしまっても良いの
では?

うーん。取り敢えず progcomp で生成したオプションに説明を付加する部分と、
source:option の generate-for-command で対応した。

x ok: generate-for-command の alias 展開 & 変数代入読み飛ばし部分で
words[iret] になっていた。修正した。

* done: ble/complete/mandb:bash-completion/inject の対象である
_comp_longopt は _comp_complete_longopt に改名された。一応両方に対応でき
る様にしておく。

また __load_completion は _comp_load -D に変わった。今回の場合には -D は
欲しくないので _comp_load で呼び出す (わざわざ -D を bash-completion で導
入したのは ble.sh を使う事を念頭に置いての物)。

x done: git format-patch --output-directory に関しては元々は = が入っていた
が、man git-format-patch には = が含まれていない為に単なる空白に変わって
しまっている。git が suggest する内容に = が含まれている場合には = を保持
する様にできないか? → その様に修正した。

* done: simple-word/safe-eval を使える箇所は置き換える。

* progcomp: git の補完するオプションで --option= の後に空白が挿入される (reported by bkerin) [#D2110]
https://github.com/akinomyoga/ble.sh/issues/387

Expand Down
7 changes: 3 additions & 4 deletions src/edit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10171,8 +10171,8 @@ function ble/widget/command-help/.type/.resolve-alias {
builtin unalias "$command"
builtin eval "alias_def=${alias_def#*=}" # remove quote
literal=${alias_def%%["$_ble_term_IFS"]*} command= type=
ble/syntax:bash/simple-word/is-simple "$literal" || break # Note: type=
local ret; ble/syntax:bash/simple-word/eval "$literal"; command=$ret
local ret; ble/syntax:bash/simple-word/safe-eval "$literal" nonull || break # Note: type=
command=$ret
ble/util/type type "$command"
[[ $type ]] || break # Note: type=

Expand Down Expand Up @@ -10207,8 +10207,7 @@ function ble/widget/command-help/.type/.resolve-alias {
function ble/widget/command-help/.type {
local literal=$1
type= command=
ble/syntax:bash/simple-word/is-simple "$literal" || return 1
local ret; ble/syntax:bash/simple-word/eval "$literal"; command=$ret
local ret; ble/syntax:bash/simple-word/safe-eval "$literal" nonull || return 1; command=$ret
ble/util/type type "$command"

# alias の時はサブシェルで解決
Expand Down

0 comments on commit 9641c3b

Please sign in to comment.