diff --git a/docs/ChangeLog.md b/docs/ChangeLog.md index 6ce38166..d68067b6 100644 --- a/docs/ChangeLog.md +++ b/docs/ChangeLog.md @@ -190,6 +190,7 @@ - mandb: support man-page format of `rsync` `#D1733` 7900144 - mandb: fix a bug that the description is inserted for `--no-OPTION` `#D1761` 88614b8 - mandb: fix a bug that the man page is not correctly searched (fixup 2365e09) `#D1794` 65ffe70 + - mandb: support the man-page formats of `man ls` in coreutils/Japanese and in macOS `#D1847` XXXXXXX - edit: work around the wrong job information of Bash in trap handlers (reported by 3ximus) `#D1435` `#D1436` bc4735e - edit (command-help): work around the Bash bug that tempenv vanishes with `builtin eval` `#D1438` 8379d4a - global: suppress missing locale errors (reported by 3ximus) `#D1440` 4d3c595 diff --git a/lib/core-complete.sh b/lib/core-complete.sh index 79f700ec..b0193a32 100644 --- a/lib/core-complete.sh +++ b/lib/core-complete.sh @@ -4309,6 +4309,7 @@ function ble/complete/mandb/.generate-cache-from-man { } #-------------------------------------------------------------------------- # Format #1: [.TP \n key \n desc] + # Format #1: [.TP \n key desc \n desc...] # This is the typical format in "man". type == "man" && REQ == "TP" { if (g_keys_count && g_desc != "") flush_topic(); @@ -4317,7 +4318,18 @@ function ble/complete/mandb/.generate-cache-from-man { } mode == "key1" { if (/^\.PD[[:space:]]*([0-9]+[[:space:]]*)?$/) next; - register_key($0); + + # In Japanese version of "man ls", key and desc is separated by multiple + # spaces, where the number of spaces seem to vary from 5 to more than 10 + # spaces. + if (match($0, /[[:space:]][[:space:]][[:space:]]/) > 0) { + register_key(substr($0, 1, RSTART - 1)); + g_desc = substr($0, RSTART); + sub(/^[[:space:]]+/, "", g_desc); + } else { + register_key($0); + } + mode = "desc"; next; } @@ -4344,6 +4356,9 @@ function ble/complete/mandb/.generate-cache-from-man { } function process_key(line, _, n, specs, i, spec, option, optarg, suffix) { + gsub(/^[[:space:]]+|[[:space:]]+$/, "", line); + if (line == "") return; + gsub(/\x1b\[[ -?]*[@-~]/, "", line); # CSI seq gsub(/\x1b[ -\/]*[0-~]/, "", line); # ESC seq gsub(/.\x08/, "", line); # CHAR BS @@ -4409,35 +4424,45 @@ function ble/complete/mandb/.generate-cache-from-man { function process_desc(line) { gsub(/^[[:space:]]*|[[:space:]]*$/, "", line); - gsub(/[[:space:]][[:space:]]+/, " ", line); if (line == "") { if (g_desc != "") return 0; return 1; } + + gsub(/[[:space:]][[:space:]]+/, " ", line); if (g_desc != "") g_desc = g_desc " "; g_desc = g_desc line; return 1; } - sub(/^[[:space:]]*__ble_key__/, "", $0) { - flush_pair(); - mode = "key"; - if (match($0, /__ble_desc__/) > 0) { - s_key = substr($0, 1, RSTART - 1); - s_desc = substr($0, RSTART + RLENGTH); - process_key(s_key); - mode = "desc"; - if (!process_desc(s_desc)) mode = ""; - next; + function process_string_fragment(str) { + if (mode == "key") { + process_key(str); + } else if (mode == "desc") { + if (!process_desc(str)) mode = ""; } } - sub(/^[[:space:]]*__ble_desc__/, "", $0) { - mode = "desc"; - } - mode == "key" { process_key($0); } - mode == "desc" { if (!process_desc($0)) mode = ""; } + function process_line(line, _, head, m0) { + while (match(line, /__ble_(key|desc)__/) > 0) { + head = substr(line, 1, RSTART - 1); + m0 = substr(line, RSTART, RLENGTH); + line = substr(line, RSTART + RLENGTH); + + process_string_fragment(head); + if (m0 == "__ble_key__") { + flush_pair(); + mode = "key"; + } else { + mode = "desc"; + } + } + + process_string_fragment(line); + } + + { process_line($0); } END { flush_pair(); } ' | ble/bin/sort -t "$_ble_term_FS" -k 1 } @@ -4453,7 +4478,7 @@ function ble/complete/mandb:help/generate-cache { local space=$' \t' # for #D1709 (WA gawk 4.0.2) local rex_argsep='(\[?[:=]| ?|\[)' - local rex_option='[-+](,|[^]:='$space',[]+)('$rex_argsep'(<[^<>]+>|\([^()]+\)|[^-[:space:]])[^[:space:]]*)?' + local rex_option='[-+](,|[^]:='$space',[]+)('$rex_argsep'(<[^<>]+>|\([^()]+\)|\[[^][]+\]|[^-[:space:]、。][^[:space:]、。]*))?([,[:space:]]|$)' ble/bin/awk -F "$_ble_term_FS" ' BEGIN { cfg_help = ENVIRON["cfg_help"]; @@ -4466,8 +4491,44 @@ function ble/complete/mandb:help/generate-cache { cfg_plus_generate = ENVIRON["cfg_plus_generate"]; cfg_plus = ENVIRON["cfg_plus"] cfg_plus_generate; + + entries_init(); } + #-------------------------------------------------------------------------- + # entries + + function entries_init() { + entries_count = 0; + } + + function entries_register(entry, score, _, name, ientry) { + name = entry; + sub(/'"$_ble_term_FS"'.*$/, "", name); + if (name ~ /^\+/ && !cfg_plus) return; + + if (entries_index[name] != "") { + ientry = entries_index[name]; + if (score >= entries_score[name]) return; + } else { + ientry = entries_count++; + entries_keys[ientry] = name; + } + + entries_index[name] = ientry; + entries_entry[name] = entry; + entries_score[name] = score; + } + + function entries_dump(_, ientry, name) { + for (ientry = 0; ientry < entries_count; ientry++) { + name = entries_keys[ientry]; + print entries_entry[name]; + } + } + + #-------------------------------------------------------------------------- + function split_option_optarg_suffix(optspec, _, key, suffix, optarg) { # Note: Skip options that contain FS (due to the limitation by the cache format) if (index(optspec, FS) != 0) return ""; @@ -4488,13 +4549,6 @@ function ble/complete/mandb:help/generate-cache { return key FS optarg FS suffix; } - function print_entry(entry, _, name) { - name = entry; - sub(/'"$_ble_term_FS"'.*$/, "", name); - if (name ~ /^\+/ && !cfg_plus) return; - if (!g_hash[name]++) # uniq - print entry; - } { gsub(/\x1b\[[ -?]*[@-~]/, ""); # CSI seq @@ -4509,13 +4563,13 @@ function ble/complete/mandb:help/generate-cache { if (!cfg_plus_generate) return; n = length(cfg_plus_generate); for (i = 1; i <= n; i++) - print_entry("+" substr(cfg_plus_generate, i, 1) FS FS FS); + entries_register("+" substr(cfg_plus_generate, i, 1) FS FS FS, 999); } #-------------------------------------------------------------------------- # Extract usage [-DEI] [-f[helo] | --prefix=PATH] - function parse_usage(line, _, optspec, optspec1, option, optarg, n, i, o) { + function usage_parse(line, _, optspec, optspec1, option, optarg, n, i, o) { while (match(line, /\[[[:space:]]*([^][]|\[[^][]*\])+[[:space:]]*\]/)) { optspec = substr(line, RSTART + 1, RLENGTH - 2); line = substr(line, RSTART + RLENGTH); @@ -4544,15 +4598,15 @@ function ble/complete/mandb:help/generate-cache { } } } - function print_usage(_, i) { + function usage_generate(_, i) { for (i = 0; i < g_usage_count; i++) - print_entry(g_usage[i] FS); + entries_register(g_usage[i] FS, 999); } cfg_usage { if (NR <= 20 && (g_usage_start || $0 ~ /^[a-zA-Z_0-9]|^[^-[:space:]][^[:space:]]*(: |:)/) ) { g_usage_start = 1; - parse_usage($0); + usage_parse($0); } else if (/^[[:space:]]*$/) cfg_usage = 0; } @@ -4577,7 +4631,7 @@ function ble/complete/mandb:help/generate-cache { function flush_data(_, i) { if (g_indent < 0) return; for (i = 0; i < g_keys_count; i++) - print_entry(g_keys[i] FS g_desc); + entries_register(g_keys[i] FS g_desc, g_indent); g_indent = -1; g_keys_count = 0; g_desc = ""; @@ -4594,7 +4648,7 @@ function ble/complete/mandb:help/generate-cache { key = substr(keydef, 1, RLENGTH); keydef = substr(keydef, RLENGTH + 1); - sub(/,$/, "", key); + sub(/[,[:space:]]$/, "", key); keys[nkey++] = key; } @@ -4638,7 +4692,10 @@ function ble/complete/mandb:help/generate-cache { g_desc = g_desc " " desc; } - cfg_help && match($0, /^[[:space:]]*'"$rex_option"'(,?[[:space:]]+'"$rex_option"')*/) { + # Note (#D1847): We here restrict the number of spaces between synonymous + # options within 2 or 3. Note that "rex_option" already contains the + # trailing comma or space. + cfg_help && match($0, /^[[:space:]]*'"$rex_option"'(([[:space:]][[:space:]]?)?'"$rex_option"')*/) { key = substr($0, 1, RLENGTH); desc = substr($0, RLENGTH + 1); if (desc ~ /^,/) next; @@ -4659,8 +4716,9 @@ function ble/complete/mandb:help/generate-cache { END { flush_data(); - print_usage(); + usage_generate(); generate_plus(); + entries_dump(); } ' | ble/bin/sort -t "$_ble_term_FS" -k 1 } diff --git a/note.txt b/note.txt index 6be8bf93..e30ad479 100644 --- a/note.txt +++ b/note.txt @@ -6461,6 +6461,109 @@ bash_tips Done (実装ログ) ------------------------------------------------------------------------------- +2022-07-13 + + * mandb: ls のオプションの抽出がおかしい [#D1847] + https://github.com/akinomyoga/ble.sh/issues/204#issuecomment-1181790000 + + * fixed: 手許でも具体的な振る舞いは異なってはいるが ls の man 情報の抽出が + ちゃんとできていない。日本語の説明が混入してしまっている。 + + 実際生成されているキャッシュの man.d/ls を確認すると誤った位置で引数が抽 + 出されているのを確認できた。確か、空白が2個以上などの条件で分離していたが + それがいけないという事なのではないか。当該箇所を確認してみる事にする。 + + うーん。途中で出力してみるとどうやら man を変換した時点で変な位置に + __ble_desc__ が挿入されている様である。元の groff ソースを見ると以下の様 + になっていた。 + + | .TP + | \fB\-\-time\fR=\fIWORD\fR \fB\-l\fR と併せて使用し、デフォルトのファイル更新時刻の代わりに + | WORD で指定した時間を表示する: atime/access/use (\fB\-u\fR), + | ctime/status (\fB\-c\fR)。 + | \fB\-\-sort\fR=\fItime\fR を指定した場合はソートのキーとして + | 指定した時間が使用される + + つまり変な形式で man が書かれているのが原因である。取り敢えずこれには対応 + した。動いている。 + + x fixed: と思ったがやはり動いていない。うーん。"-" を入力してから補完する + 時には問題は発生しないが、空文字列から生成すると問題が発生する。キャッ + シュは man.d/ls は問題ないが ls に問題がある。これは合成して新しく ls + を作る時に問題になっているという事だろうか。と思ったら + _parse_help.d/ls.00000000000000 が問題であった。つまり _parse_help への + 介入の解析が問題。問題になっている ls --help の出力の行は以下の形をして + いる: + + | --author -l と合わせて使用した時、各ファイルの作成者を表示する + + うーん。これも空白が3個以上間にある時は説明とオプションの境界と解釈する + などの対処が必要になるだろうか。 + + x fixed: 更にこれでも変な物が抽出される。以下の物が抽出されている様だ。 + + | -l と使用した場合、名前でソートし、アクセス時間を表示する。 + + 空白が単一であったとしても後に続く文字列に [、。] が含まれている場合に + はオプション引数として解釈しない様にした。 + + x fixed: 然しこの様にしても、今度は -l の説明がこの偽物の説明で上書きされ + てしまっている。本当は以下の説明が抽出されて欲しい。 + + | -l 詳細リスト形式を表示する + + 複数の同じオプションがある場合にはインデントの最も小さい物を選択する様 + にしたい → L4510 で uniq している所を何とかしたい → 取り敢えず一旦 + indent の情報と一緒に全部記録して最後に出力する様に変更した。同じ名前の + オプションの説明があった場合は indent の小さい物を優先させる。 + + * 補完設定の違いによる cache の違い + + というかそもそも日本語で表示されたり英語で表示されなかったり一定していな + いのも変である。man/help のどちらかが優先されるのだとしたらちゃんと両方と + も表示されるべきである。うーん。bash-completion 経由で初期化すると --help + の説明を抽出する形になって、built-in completion だと man page が優先され + るのが違いの原因の様である。問題はキャッシュが後々に残ってしまうという事 + にある。キャッシュを生成する時にちゃんと両方を個別に記録して後に合成する + 必要があるのではないか。 + + % と思ったが今確認してみるとちゃんと bash-completion の有無で補完の説明が + % 異なるし、オプションの説明の切り出しも変な事にはなっていない。問題がど + % のような条件で発生するのか確認する必要があるのである。と思ったが + % LANG=C.UTF-8 にしていたのだった。LANG=C.UTF-8 にしている時には日本語の + % 説明がオプション引数の部分にくっつく等の事は起こらず、ちゃんと抽出でき + % ている。 + + うーん。他にも変な現象が起こったりしていた様な気がするが、これは古い + ble.sh で動作している session も書き換えているからなのではないかという気 + もする。これについては以前考察した筈なのでまた改めて考察はしない事にする。 + + * ok: 何故か最初の menu の列だけ sep の " : " が挿入されていない。謎。と思っ + たが、これは単にとても長いオプション名がその列に含まれているからというだ + けの様だ。気にしなくて良い。 + + * fixed: __ble_decode__ の切り分けの失敗がどの様に起こるのかは気になる。改 + めて実装を確認してみるとどうも __ble_desc__ が行の途中に埋め込まれる様な + 状況は想定していない? + + うーん。mode == "key" の途中で __ble_desc__ が現れる事も原理的にあるし、 + また mode == "desc" の途中で __ble_key__ が現れる事もある。→実装してみた + が検証のしようがない。というか面倒である。取り敢えず既存の物がちゃんと動 + いているかどうかだけ確認する。 + + 取り敢えず安全側に倒した実装に変更したので動く様になっていると考えたい。他 + の可能性として \b を使って上書きする事により太字を再現している場合に、太字 + になっている __ble_desc__ や __ble_key__ を検出できないという可能性もあるが、 + 下手に対策して逆に動かなくなるケースがあっても嫌なので、それは実際に起って + から考える事にする。 + + * というか、単に修飾を外してからマッチさせる方法だと、実際に欲しい着色や太 + 字の修飾が外れてしまうので、修飾を外す前の文字列を正規表現で一致させなけ + ればならない。だとすると ble に対して b(\bb)?l(\bl)?e(\be)? 等の様にしな + ければならない。なのだとすれば、逆に動かなくなるケースもない様な気がする。 + とは言いつつ実際にあるかも分からない事例に対して実装するのも変な気がする + ので現状のままにする。 + 2022-07-12 * ble.sh built-in completion で既定でオプションを補完するが他の候補よりも前に来るので邪魔 (reported by geekscrapy) [#D1846]